diff options
Diffstat (limited to 'server/src/routes/ui/player.rs')
-rw-r--r-- | server/src/routes/ui/player.rs | 200 |
1 files changed, 0 insertions, 200 deletions
diff --git a/server/src/routes/ui/player.rs b/server/src/routes/ui/player.rs deleted file mode 100644 index 2bb439b..0000000 --- a/server/src/routes/ui/player.rs +++ /dev/null @@ -1,200 +0,0 @@ -/* - 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) 2025 metamuffin <metamuffin.org> -*/ -use super::{ - account::session::{token, Session}, - layout::LayoutPage, - node::{get_similar_media, DatabaseNodeUserDataExt, NodePage}, - sort::NodeFilterSort, -}; -use crate::{ - database::Database, - routes::{ - locale::AcceptLanguage, - ui::{error::MyResult, layout::DynLayoutPage}, - }, -}; -use anyhow::anyhow; -use jellybase::CONF; -use jellycommon::{ - stream::{StreamContainer, StreamSpec}, - user::{PermissionSet, PlayerKind}, - Node, NodeID, SourceTrackKind, TrackID, Visibility, -}; -use markup::DynRender; -use rocket::{get, response::Redirect, Either, FromForm, State, UriDisplayQuery}; -use std::sync::Arc; - -#[derive(FromForm, Default, Clone, Debug, UriDisplayQuery)] -pub struct PlayerConfig { - pub a: Option<TrackID>, - pub v: Option<TrackID>, - pub s: Option<TrackID>, - pub t: Option<f64>, - pub kind: Option<PlayerKind>, -} - -impl PlayerConfig { - pub fn seek(t: f64) -> Self { - Self { - t: Some(t), - ..Default::default() - } - } -} - -fn jellynative_url(action: &str, seek: f64, secret: &str, node: &str, session: &str) -> String { - let protocol = if CONF.tls { "https" } else { "http" }; - let host = &CONF.hostname; - let stream_url = format!( - "/n/{node}/stream{}", - StreamSpec::HlsMultiVariant { - segment: 0, - container: StreamContainer::Matroska - } - .to_query() - ); - format!("jellynative://{action}/{secret}/{session}/{seek}/{protocol}://{host}{stream_url}",) -} - -#[get("/n/<id>/player?<conf..>", rank = 4)] -pub fn r_player( - session: Session, - lang: AcceptLanguage, - db: &State<Database>, - id: NodeID, - conf: PlayerConfig, -) -> MyResult<Either<DynLayoutPage<'_>, Redirect>> { - let AcceptLanguage(lang) = lang; - let (node, udata) = db.get_node_with_userdata(id, &session)?; - - let mut parents = node - .parents - .iter() - .map(|pid| db.get_node_with_userdata(*pid, &session)) - .collect::<anyhow::Result<Vec<_>>>()?; - - let mut similar = get_similar_media(&node, db, &session)?; - - similar.retain(|(n, _)| n.visibility >= Visibility::Reduced); - parents.retain(|(n, _)| n.visibility >= Visibility::Reduced); - - let native_session = |action: &str| { - Ok(Either::Right(Redirect::temporary(jellynative_url( - action, - conf.t.unwrap_or(0.), - &session.user.native_secret, - &id.to_string(), - &token::create( - session.user.name, - PermissionSet::default(), // TODO - chrono::Duration::hours(24), - ), - )))) - }; - - match conf.kind.unwrap_or(session.user.player_preference) { - PlayerKind::Browser => (), - PlayerKind::Native => { - return native_session("player-v2"); - } - PlayerKind::NativeFullscreen => { - return native_session("player-fullscreen-v2"); - } - } - - // TODO - // let spec = StreamSpec { - // track: None - // .into_iter() - // .chain(conf.v) - // .chain(conf.a) - // .chain(conf.s) - // .collect::<Vec<_>>(), - // format: StreamFormat::Matroska, - // webm: Some(true), - // ..Default::default() - // }; - // let playing = false; // !spec.track.is_empty(); - // let conf = player_conf(node.clone(), playing)?; - - Ok(Either::Left(LayoutPage { - title: node.title.to_owned().unwrap_or_default(), - class: Some("player"), - content: markup::new! { - // @if playing { - // // video[src=uri!(r_stream(&node.slug, &spec)), controls, preload="auto"]{} - // } - // @conf - @NodePage { - children: &[], - parents: &parents, - filter: &NodeFilterSort::default(), - node: &node, - udata: &udata, - player: true, - similar: &similar, - lang: &lang - } - }, - })) -} - -pub fn player_conf<'a>(item: Arc<Node>, playing: bool) -> anyhow::Result<DynRender<'a>> { - let mut audio_tracks = vec![]; - let mut video_tracks = vec![]; - let mut sub_tracks = vec![]; - let tracks = item - .media - .clone() - .ok_or(anyhow!("node does not have media"))? - .tracks - .clone(); - for (tid, track) in tracks.into_iter().enumerate() { - 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(markup::new! { - form.playerconf[method = "GET", action = ""] { - h2 { "Select tracks for " @item.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]; - label[for=tid] { @format!("{track}") } br; - } - input[type="radio", id="s-none", name="s", value="", checked=true]; - label[for="s-none"] { "No subtitles" } - } - - input[type="submit", value=if playing { "Change tracks" } else { "Start playback" }]; - } - }) -} |