1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
|
/*
This file is part of jellything (https://codeberg.org/metamuffin/jellything)
which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
Copyright (C) 2023 metamuffin <metamuffin.org>
*/
use super::{account::session::Session, layout::LayoutPage};
use crate::{
library::{Item, Library},
routes::{
stream::stream_uri,
ui::{error::MyResult, layout::DynLayoutPage},
},
};
use jellycommon::SourceTrackKind;
use rocket::{get, FromForm, State};
use std::{path::PathBuf, sync::Arc};
pub fn player_uri(path: &PathBuf) -> String {
format!("/player/{}", path.to_str().unwrap())
}
#[derive(FromForm, Default, Clone, Debug)]
pub struct PlayerConfig {
pub a: Option<u64>,
pub v: Option<u64>,
pub s: Option<u64>,
pub webm: bool,
}
#[get("/player/<path..>?<conf..>", rank = 4)]
pub fn r_player(
_sess: Session,
library: &State<Library>,
path: PathBuf,
conf: PlayerConfig,
) -> MyResult<DynLayoutPage<'_>> {
let item = library.nested_path(&path)?.get_item()?;
if conf.a.is_none() && conf.v.is_none() && conf.s.is_none() {
return player_conf(item.clone());
}
let tracks = conf
.a
.into_iter()
.chain(conf.v.into_iter())
.chain(conf.s.into_iter())
.collect::<Vec<_>>();
Ok(LayoutPage {
title: item.info.title.to_owned(),
content: markup::new! {
video[src=stream_uri(&item.lib_path, &tracks, true), controls];
},
})
}
pub fn player_conf<'a>(item: Arc<Item>) -> MyResult<DynLayoutPage<'a>> {
let mut audio_tracks = vec![];
let mut video_tracks = vec![];
let mut sub_tracks = vec![];
for (tid, track) in item.info.tracks.clone() {
match &track.kind {
SourceTrackKind::Audio { .. } => audio_tracks.push((tid, track)),
SourceTrackKind::Video { .. } => video_tracks.push((tid, track)),
SourceTrackKind::Subtitles { .. } => sub_tracks.push((tid, track)),
}
}
Ok(LayoutPage {
title: "Configure Player".to_string(),
content: markup::new! {
// img.backdrop[src=uri!(r_item_assets(&item.lib_path)).to_string()];
form.playerconf[method = "GET", action = ""] {
h2 { "Select tracks for " @item.info.title }
fieldset.video {
legend { "Video" }
@for (i, (tid, track)) in video_tracks.iter().enumerate() {
input[type="radio", id=tid, name="v", value=tid, checked=i==0];
label[for=tid] { @format!("{track}") } br;
}
input[type="radio", id="v-none", name="v", value=""];
label[for="v-none"] { "No video" }
}
fieldset.audio {
legend { "Audio" }
@for (i, (tid, track)) in audio_tracks.iter().enumerate() {
input[type="radio", id=tid, name="a", value=tid, checked=i==0];
label[for=tid] { @format!("{track}") } br;
}
input[type="radio", id="a-none", name="a", value=""];
label[for="a-none"] { "No audio" }
}
fieldset.subtitles {
legend { "Subtitles" }
@for (i, (tid, track)) in sub_tracks.iter().enumerate() {
input[type="radio", id=tid, name="s", value=tid, checked=i==0];
label[for=tid] { @format!("{track}") } br;
}
input[type="radio", id="s-none", name="s", value=""];
label[for="s-none"] { "No subtitles" }
}
input[type="submit", value="Start playback"];
}
},
})
}
|