/* 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 */ use super::{account::session::Session, layout::LayoutPage}; use crate::{ database::Database, routes::{ stream::stream_uri, ui::{ assets::{rocket_uri_macro_r_item_assets, AssetRole}, error::MyResult, layout::DynLayoutPage, }, }, uri, }; use anyhow::anyhow; use jellycommon::{Node, SourceTrackKind}; use markup::DynRender; use rocket::{get, FromForm, State}; #[derive(FromForm, Default, Clone, Debug)] pub struct PlayerConfig { pub a: Option, pub v: Option, pub s: Option, pub webm: bool, } pub fn player_uri(id: &str) -> String { format!("/n/{}/player", id) } #[get("/n//player?", rank = 4)] pub fn r_player( _sess: Session, db: &State, id: String, conf: PlayerConfig, ) -> MyResult> { let item = db.node.get(&id)?.ok_or(anyhow!("node does not exist"))?; let tracks = None .into_iter() .chain(conf.v.into_iter()) .chain(conf.a.into_iter()) .chain(conf.s.into_iter()) .collect::>(); let conf = player_conf(item.clone(), !tracks.is_empty())?; Ok(LayoutPage { title: item.public.title.to_owned(), class: Some("player"), content: markup::new! { @if tracks.is_empty() { img.backdrop[src=uri!(r_item_assets(&id, AssetRole::Backdrop)).to_string()]; } else { video[src=stream_uri(&id, &tracks, true), controls]{} } @conf }, show_back: true, ..Default::default() }) } pub fn player_conf<'a>(item: Node, playing: bool) -> anyhow::Result> { let mut audio_tracks = vec![]; let mut video_tracks = vec![]; let mut sub_tracks = vec![]; let tracks = item .public .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.public.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" }]; } }) }