diff options
author | metamuffin <metamuffin@disroot.org> | 2025-01-29 16:07:58 +0100 |
---|---|---|
committer | metamuffin <metamuffin@disroot.org> | 2025-01-29 16:07:58 +0100 |
commit | e7ba3274e27fad755f15465581f5b403c82ab4d2 (patch) | |
tree | f2d693c61786ee6ed027636393fd75f086bd77e8 /server/src | |
parent | 5ac3f397b4a28b7bf8b399e73ad0d29e3da45ab0 (diff) | |
download | jellything-e7ba3274e27fad755f15465581f5b403c82ab4d2.tar jellything-e7ba3274e27fad755f15465581f5b403c82ab4d2.tar.bz2 jellything-e7ba3274e27fad755f15465581f5b403c82ab4d2.tar.zst |
prepare database refactor
Diffstat (limited to 'server/src')
-rw-r--r-- | server/src/routes/mod.rs | 13 | ||||
-rw-r--r-- | server/src/routes/stream.rs | 11 | ||||
-rw-r--r-- | server/src/routes/ui/admin/log.rs | 4 | ||||
-rw-r--r-- | server/src/routes/ui/admin/mod.rs | 75 | ||||
-rw-r--r-- | server/src/routes/ui/assets.rs | 70 | ||||
-rw-r--r-- | server/src/routes/ui/browser.rs | 1 | ||||
-rw-r--r-- | server/src/routes/ui/home.rs | 34 | ||||
-rw-r--r-- | server/src/routes/ui/node.rs | 112 | ||||
-rw-r--r-- | server/src/routes/ui/player.rs | 13 | ||||
-rw-r--r-- | server/src/routes/ui/search.rs | 3 | ||||
-rw-r--r-- | server/src/routes/ui/sort.rs | 4 |
11 files changed, 163 insertions, 177 deletions
diff --git a/server/src/routes/mod.rs b/server/src/routes/mod.rs index 33f1c69..45dd89a 100644 --- a/server/src/routes/mod.rs +++ b/server/src/routes/mod.rs @@ -30,15 +30,15 @@ use ui::{ }, admin::{ log::r_admin_log, - r_admin_dashboard, r_admin_delete_cache, r_admin_import, r_admin_invite, - r_admin_remove_invite, r_admin_transcode_posters, + r_admin_dashboard, r_admin_delete_cache, r_admin_invite, r_admin_remove_invite, + r_admin_transcode_posters, user::{r_admin_remove_user, r_admin_user, r_admin_user_permission, r_admin_users}, }, - assets::{r_asset, r_item_assets, r_node_thumbnail, r_person_asset}, + assets::{r_asset, r_item_backdrop, r_item_poster, r_node_thumbnail, r_person_asset}, browser::r_all_items_filter, error::{r_api_catch, r_catch}, home::{r_home, r_home_unpriv}, - node::{r_library_node_ext, r_library_node_filter}, + node::r_library_node_filter, player::r_player, search::r_search, style::{r_assets_font, r_assets_js, r_assets_js_map, r_assets_style}, @@ -100,12 +100,12 @@ pub fn build_rocket(database: DataAcid, federation: Federation) -> Rocket<Build> r_streamsync, r_favicon, r_asset, - r_item_assets, + r_item_backdrop, + r_item_poster, r_person_asset, r_search, r_all_items_filter, r_library_node_filter, - r_library_node_ext, r_assets_style, r_assets_font, r_assets_js, @@ -130,7 +130,6 @@ pub fn build_rocket(database: DataAcid, federation: Federation) -> Rocket<Build> r_admin_users, r_admin_remove_invite, r_admin_user_permission, - r_admin_import, r_admin_delete_cache, r_admin_transcode_posters, r_admin_log, diff --git a/server/src/routes/stream.rs b/server/src/routes/stream.rs index 756c502..3500ee4 100644 --- a/server/src/routes/stream.rs +++ b/server/src/routes/stream.rs @@ -57,22 +57,21 @@ pub async fn r_stream( .get(db, id)? .only_if_permitted(&session.user.permissions) .ok_or(anyhow!("node does not exist"))?; - let source = node - .private - .source + let media = node + .media .as_ref() .ok_or(anyhow!("item does not contain media"))?; // TODO its unclear how requests with multiple tracks should be handled. if spec.track.len() == 1 { let ti = spec.track[0]; - if let TrackSource::Remote(remote_index) = source[ti] { + if let TrackSource::Remote(remote_index) = media.tracks[ti].source { session .user .permissions .assert(&UserPermission::FederatedContent)?; - let track = &node.public.media.ok_or(anyhow!("no media"))?.tracks[ti]; + let track = &node.media.ok_or(anyhow!("no media"))?.tracks[ti]; let host = track .federated .last() @@ -100,7 +99,7 @@ pub async fn r_stream( .await?; let uri = session.stream_url( - node.public.id.as_ref().unwrap(), + &node.slug, &StreamSpec { track: vec![remote_index], ..spec diff --git a/server/src/routes/ui/admin/log.rs b/server/src/routes/ui/admin/log.rs index 884ad7a..b123ada 100644 --- a/server/src/routes/ui/admin/log.rs +++ b/server/src/routes/ui/admin/log.rs @@ -136,9 +136,7 @@ impl log::Log for Log { fn vt100_to_html(s: &str) -> String { let mut out = HtmlOut::default(); let mut st = vte::Parser::new(); - for b in s.bytes() { - st.advance(&mut out, b); - } + st.advance(&mut out, s.as_bytes()); out.s } diff --git a/server/src/routes/ui/admin/mod.rs b/server/src/routes/ui/admin/mod.rs index 25f1f42..6e19373 100644 --- a/server/src/routes/ui/admin/mod.rs +++ b/server/src/routes/ui/admin/mod.rs @@ -26,12 +26,10 @@ use jellybase::{ database::{ redb::{ReadableTable, ReadableTableMetadata}, tantivy::query::Bm25StatisticsProvider, - TableExt, T_INVITE, T_NODE, T_NODE_EXTENDED, T_USER_NODE, + TableExt, T_INVITE, T_NODE, T_USER_NODE, }, - federation::Federation, CONF, }; -use jellyimport::{import, is_importing, IMPORT_ERRORS}; use markup::DynRender; use rand::Rng; use rocket::{form::Form, get, post, FromForm, State}; @@ -66,7 +64,7 @@ pub async fn admin_dashboard<'a>( }; let flash = flash.map(|f| f.map_err(|e| format!("{e:?}"))); - let last_import_err = IMPORT_ERRORS.read().await.to_owned(); + // let last_import_err = IMPORT_ERRORS.read().await.to_owned(); let database = database.to_owned(); Ok(LayoutPage { @@ -74,28 +72,28 @@ pub async fn admin_dashboard<'a>( content: markup::new! { h1 { "Admin Panel" } @FlashDisplay { flash: flash.clone() } - @if !last_import_err.is_empty() { - section.message.error { - p.error {"The last import resulted in at least one error:"} - ol { @for e in &last_import_err { - li.error { pre.error { @e } } - }} - } - } + // @if !last_import_err.is_empty() { + // section.message.error { + // p.error {"The last import resulted in at least one error:"} + // ol { @for e in &last_import_err { + // li.error { pre.error { @e } } + // }} + // } + // } ul { li{a[href=uri!(r_admin_log(true))] { "Server Log (Warnings only)" }} li{a[href=uri!(r_admin_log(false))] { "Server Log (Full) " }} } h2 { "Library" } - @if is_importing() { - section.message { p.warn { "An import is currently running." } } - } + // @if is_importing() { + // section.message { p.warn { "An import is currently running." } } + // } @if is_transcoding() { section.message { p.warn { "Currently transcoding posters." } } } - form[method="POST", action=uri!(r_admin_import())] { - input[type="submit", disabled=is_importing(), value="(Re-)Import Library"]; - } + // form[method="POST", action=uri!(r_admin_import())] { + // input[type="submit", disabled=is_importing(), value="(Re-)Import Library"]; + // } form[method="POST", action=uri!(r_admin_transcode_posters())] { input[type="submit", disabled=is_transcoding(), value="Transcode all posters with low resolution"]; } @@ -133,7 +131,7 @@ pub async fn r_admin_invite( _session: AdminSession, database: &State<DataAcid>, ) -> MyResult<DynLayoutPage<'static>> { - let i = format!("{}", rand::thread_rng().gen::<u128>()); + let i = format!("{}", rand::rng().random::<u128>()); T_INVITE.insert(database, &*i, ())?; admin_dashboard(database, Some(Ok(format!("Invite: {}", i)))).await @@ -158,24 +156,24 @@ pub async fn r_admin_remove_invite( admin_dashboard(database, Some(Ok("Invite invalidated".into()))).await } -#[post("/admin/import")] -pub async fn r_admin_import( - session: AdminSession, - database: &State<DataAcid>, - federation: &State<Federation>, -) -> MyResult<DynLayoutPage<'static>> { - drop(session); - let t = Instant::now(); - let r = import(database, federation).await; - admin_dashboard( - database, - Some( - r.map_err(|e| e.into()) - .map(|_| format!("Import successful; took {:?}", t.elapsed())), - ), - ) - .await -} +// #[post("/admin/import")] +// pub async fn r_admin_import( +// session: AdminSession, +// database: &State<DataAcid>, +// federation: &State<Federation>, +// ) -> MyResult<DynLayoutPage<'static>> { +// drop(session); +// let t = Instant::now(); +// let r = import(database, federation).await; +// admin_dashboard( +// database, +// Some( +// r.map_err(|e| e.into()) +// .map(|_| format!("Import successful; took {:?}", t.elapsed())), +// ), +// ) +// .await +// } #[post("/admin/delete_cache")] pub async fn r_admin_delete_cache( @@ -218,7 +216,7 @@ pub async fn r_admin_transcode_posters( let nodes = txn.open_table(T_NODE)?; for node in nodes.iter()? { let (_, node) = node?; - if let Some(poster) = &node.value().0.public.poster { + if let Some(poster) = &node.value().0.poster { let asset = AssetInner::deser(&poster.0)?; if asset.is_federated() { continue; @@ -246,7 +244,6 @@ fn db_stats(db: &DataAcid) -> anyhow::Result<DynRender> { let txn = db.inner.begin_read()?; let stats = [ ("node", txn.open_table(T_NODE)?.stats()?), - ("node-ext", txn.open_table(T_NODE_EXTENDED)?.stats()?), ("user", txn.open_table(T_USER_NODE)?.stats()?), ("user-node", txn.open_table(T_USER_NODE)?.stats()?), ("invite", txn.open_table(T_INVITE)?.stats()?), diff --git a/server/src/routes/ui/assets.rs b/server/src/routes/ui/assets.rs index ad31240..aeb4eff 100644 --- a/server/src/routes/ui/assets.rs +++ b/server/src/routes/ui/assets.rs @@ -9,16 +9,15 @@ use base64::Engine; use jellybase::{ assetfed::AssetInner, cache::async_cache_file, - database::{DataAcid, TableExt, T_NODE, T_NODE_EXTENDED}, + database::{DataAcid, TableExt, T_NODE}, federation::Federation, permission::NodePermissionExt, CONF, }; -pub use jellycommon::AssetRole; use jellycommon::{LocalTrack, PeopleGroup, SourceTrackKind, TrackSource}; use log::info; use rocket::{get, http::ContentType, response::Redirect, State}; -use std::path::PathBuf; +use std::{path::PathBuf, str::FromStr}; pub const AVIF_QUALITY: f32 = 50.; pub const AVIF_SPEED: u8 = 5; @@ -66,12 +65,11 @@ pub async fn resolve_asset(asset: AssetInner) -> anyhow::Result<PathBuf> { } } -#[get("/n/<id>/asset?<role>&<width>")] -pub async fn r_item_assets( +#[get("/n/<id>/poster?<width>")] +pub async fn r_item_poster( session: Session, db: &State<DataAcid>, id: &str, - role: AssetRole, width: Option<usize>, ) -> MyResult<Redirect> { let node = T_NODE @@ -79,26 +77,45 @@ pub async fn r_item_assets( .only_if_permitted(&session.user.permissions) .ok_or(anyhow!("node does not exist"))?; - let mut asset = match role { - AssetRole::Backdrop => node.public.backdrop, - AssetRole::Poster => node.public.poster, + let mut asset = node.poster; + if asset.is_none() { + if let Some(parent) = &node.parents.last() { + let parent = T_NODE + .get(db, parent.as_str())? + .ok_or(anyhow!("node does not exist"))?; + asset = parent.poster; + } }; + let asset = asset.unwrap_or_else(|| { + AssetInner::Assets(format!("fallback-{:?}.avif", node.kind.unwrap_or_default()).into()) + .ser() + }); + Ok(Redirect::temporary(rocket::uri!(r_asset(asset.0, width)))) +} +#[get("/n/<id>/backdrop?<width>")] +pub async fn r_item_backdrop( + session: Session, + db: &State<DataAcid>, + id: &str, + width: Option<usize>, +) -> MyResult<Redirect> { + let node = T_NODE + .get(db, id)? + .only_if_permitted(&session.user.permissions) + .ok_or(anyhow!("node does not exist"))?; + + let mut asset = node.poster; if asset.is_none() { - if let Some(parent) = &node.public.path.last() { + if let Some(parent) = &node.parents.last() { let parent = T_NODE .get(db, parent.as_str())? .ok_or(anyhow!("node does not exist"))?; - asset = match role { - AssetRole::Backdrop => parent.public.backdrop, - AssetRole::Poster => parent.public.poster, - }; + asset = parent.poster; } }; let asset = asset.unwrap_or_else(|| { - AssetInner::Assets( - format!("fallback-{:?}.avif", node.public.kind.unwrap_or_default()).into(), - ) - .ser() + AssetInner::Assets(format!("fallback-{:?}.avif", node.kind.unwrap_or_default()).into()) + .ser() }); Ok(Redirect::temporary(rocket::uri!(r_asset(asset.0, width)))) } @@ -109,7 +126,7 @@ pub async fn r_person_asset( db: &State<DataAcid>, id: &str, index: usize, - group: PeopleGroup, + group: String, width: Option<usize>, ) -> MyResult<Redirect> { T_NODE @@ -117,10 +134,10 @@ pub async fn r_person_asset( .only_if_permitted(&session.user.permissions) .ok_or(anyhow!("node does not exist"))?; - let ext = T_NODE_EXTENDED.get(db, id)?.unwrap_or_default(); - let app = ext + let node = T_NODE.get(db, id)?.unwrap_or_default(); + let app = node .people - .get(&group) + .get(&PeopleGroup::from_str(&group).map_err(|()| anyhow!("unknown people group"))?) .ok_or(anyhow!("group has no members"))? .get(index) .ok_or(anyhow!("person does not exist"))?; @@ -150,15 +167,18 @@ pub async fn r_node_thumbnail( .only_if_permitted(&session.user.permissions) .ok_or(anyhow!("node does not exist"))?; - let media = node.public.media.ok_or(anyhow!("no media"))?; + let media = node.media.ok_or(anyhow!("no media"))?; let (thumb_track_index, thumb_track) = media .tracks .iter() .enumerate() .find(|(_i, t)| matches!(t.kind, SourceTrackKind::Video { .. })) .ok_or(anyhow!("no video track to create a thumbnail of"))?; - let source = node.private.source.ok_or(anyhow!("no source"))?; - let thumb_track_source = &source[thumb_track_index]; + let source = media + .tracks + .get(thumb_track_index) + .ok_or(anyhow!("no source"))?; + let thumb_track_source = source.source.clone(); if t < 0. || t > media.duration { Err(anyhow!("thumbnail instant not within media duration"))? diff --git a/server/src/routes/ui/browser.rs b/server/src/routes/ui/browser.rs index da17271..4faf40b 100644 --- a/server/src/routes/ui/browser.rs +++ b/server/src/routes/ui/browser.rs @@ -39,7 +39,6 @@ pub fn r_all_items_filter( .unwrap() .map(|z| z.value().0) .unwrap_or_default(); - let y = y.public; (x, y, z) }) .collect::<Vec<_>>(); diff --git a/server/src/routes/ui/home.rs b/server/src/routes/ui/home.rs index 0a1089a..6f70644 100644 --- a/server/src/routes/ui/home.rs +++ b/server/src/routes/ui/home.rs @@ -3,19 +3,14 @@ which is licensed under the GNU Affero General Public License (version 3); see /COPYING. Copyright (C) 2024 metamuffin <metamuffin.org> */ -use super::{ - account::session::Session, - layout::LayoutPage, - node::{DatabaseNodeUserDataExt, NodeCard}, -}; +use super::{account::session::Session, layout::LayoutPage, node::NodeCard}; use crate::{ database::DataAcid, routes::ui::{error::MyResult, layout::DynLayoutPage}, }; -use anyhow::Context; use chrono::{Datelike, Utc}; use jellybase::{ - database::{redb::ReadableTable, TableExt, T_NODE, T_USER_NODE}, + database::{redb::ReadableTable, T_NODE, T_USER_NODE}, CONF, }; use jellycommon::{user::WatchedState, Rating}; @@ -38,7 +33,6 @@ pub fn r_home(sess: Session, db: &State<DataAcid>) -> MyResult<DynLayoutPage> { .unwrap() .map(|z| z.value().0) .unwrap_or_default(); - let y = y.public; (x, y, z) }) .collect::<Vec<_>>(); @@ -49,16 +43,14 @@ pub fn r_home(sess: Session, db: &State<DataAcid>) -> MyResult<DynLayoutPage> { .flat_map(|i| Some(items[cheap_daily_random(i).checked_rem(items.len())?].clone())) .collect::<Vec<_>>(); - let toplevel = T_NODE - .get(db, "library")? - .context("root node missing")? - .public - .children - .into_iter() - .map(|n| db.get_node_with_userdata(&n, &sess)) - .collect::<anyhow::Result<Vec<_>>>()? - .into_iter() - .collect::<Vec<_>>(); + // let toplevel = T_NODE + // .get(db, "library")? + // .context("root node missing")? + // .into_iter() + // .map(|n| db.get_node_with_userdata(&n, &sess)) + // .collect::<anyhow::Result<Vec<_>>>()? + // .into_iter() + // .collect::<Vec<_>>(); items.sort_by_key(|(_, n, _)| { n.ratings @@ -98,9 +90,9 @@ pub fn r_home(sess: Session, db: &State<DataAcid>) -> MyResult<DynLayoutPage> { title: "Home".to_string(), content: markup::new! { h2 { "Explore " @CONF.brand } - ul.children.hlist {@for (id, node, udata) in &toplevel { - li { @NodeCard { id, node, udata } } - }} + // ul.children.hlist {@for (id, node, udata) in &toplevel { + // li { @NodeCard { id, node, udata } } + // }} @if !continue_watching.is_empty() { h2 { "Continue Watching" } ul.children.hlist {@for (id, node, udata) in &continue_watching { diff --git a/server/src/routes/ui/node.rs b/server/src/routes/ui/node.rs index 40faf5a..88f71b7 100644 --- a/server/src/routes/ui/node.rs +++ b/server/src/routes/ui/node.rs @@ -4,7 +4,10 @@ Copyright (C) 2024 metamuffin <metamuffin.org> */ use super::{ - assets::{rocket_uri_macro_r_item_assets, rocket_uri_macro_r_node_thumbnail}, + assets::{ + rocket_uri_macro_r_item_backdrop, rocket_uri_macro_r_item_poster, + rocket_uri_macro_r_node_thumbnail, + }, error::MyResult, sort::{filter_and_sort_nodes, NodeFilterSort, NodeFilterSortForm, SortOrder, SortProperty}, }; @@ -14,7 +17,7 @@ use crate::{ api::AcceptJson, ui::{ account::session::Session, - assets::{rocket_uri_macro_r_person_asset, AssetRole}, + assets::rocket_uri_macro_r_person_asset, layout::{DynLayoutPage, LayoutPage}, player::{rocket_uri_macro_r_player, PlayerConfig}, }, @@ -28,12 +31,12 @@ use crate::{ use anyhow::{anyhow, Result}; use chrono::DateTime; use jellybase::{ - database::{TableExt, T_NODE, T_NODE_EXTENDED, T_USER_NODE}, + database::{TableExt, T_NODE, T_USER_NODE}, permission::NodePermissionExt, }; use jellycommon::{ user::{NodeUserData, WatchedState}, - Chapter, ExtendedNode, MediaInfo, NodeKind, NodePublic, PeopleGroup, Rating, SourceTrackKind, + Chapter, MediaInfo, Node, NodeKind, PeopleGroup, Rating, SourceTrackKind, }; use rocket::{get, serde::json::Json, Either, State}; @@ -43,20 +46,6 @@ pub fn r_library_node(id: String) { drop(id) } -#[get("/n/<id>/extended")] -pub async fn r_library_node_ext<'a>( - session: Session, - id: &'a str, - db: &'a State<DataAcid>, -) -> MyResult<Json<ExtendedNode>> { - T_NODE - .get(db, id)? - .only_if_permitted(&session.user.permissions) - .ok_or(anyhow!("node does not exist"))?; - - Ok(Json(T_NODE_EXTENDED.get(db, id)?.unwrap_or_default())) -} - #[get("/n/<id>?<filter..>")] pub async fn r_library_node_filter<'a>( session: Session, @@ -64,13 +53,11 @@ pub async fn r_library_node_filter<'a>( db: &'a State<DataAcid>, aj: AcceptJson, filter: NodeFilterSort, -) -> MyResult<Either<DynLayoutPage<'a>, Json<NodePublic>>> { +) -> MyResult<Either<DynLayoutPage<'a>, Json<Node>>> { let node = T_NODE .get(db, id)? .only_if_permitted(&session.user.permissions) - .ok_or(anyhow!("node does not exist"))? - .public; - let node_ext = T_NODE_EXTENDED.get(db, id)?.unwrap_or_default(); + .ok_or(anyhow!("node does not exist"))?; let udata = T_USER_NODE .get(db, &(session.user.name.as_str(), id))? @@ -80,29 +67,29 @@ pub async fn r_library_node_filter<'a>( return Ok(Either::Right(Json(node))); } - let mut children = node - .children - .iter() - .map(|c| db.get_node_with_userdata(c, &session)) - .collect::<anyhow::Result<Vec<_>>>()? - .into_iter() - .collect(); + // let mut children = node + // .children + // .iter() + // .map(|c| db.get_node_with_userdata(c, &session)) + // .collect::<anyhow::Result<Vec<_>>>()? + // .into_iter() + // .collect(); - let path = node - .path - .iter() - .map(|c| { - Ok(( - c.to_owned(), - T_NODE - .get(db, c.as_str())? - .ok_or(anyhow!("parent node missing"))? - .public, - )) - }) - .collect::<anyhow::Result<Vec<_>>>()? - .into_iter() - .collect::<Vec<_>>(); + // let path = node + // .path + // .iter() + // .map(|c| { + // Ok(( + // c.to_owned(), + // T_NODE + // .get(db, c.as_str())? + // .ok_or(anyhow!("parent node missing"))? + // .public, + // )) + // }) + // .collect::<anyhow::Result<Vec<_>>>()? + // .into_iter() + // .collect::<Vec<_>>(); filter_and_sort_nodes( &filter, @@ -110,25 +97,26 @@ pub async fn r_library_node_filter<'a>( NodeKind::Channel => (SortProperty::ReleaseDate, SortOrder::Descending), _ => (SortProperty::Title, SortOrder::Ascending), }, - &mut children, + // TODO + &mut Vec::new(), ); Ok(Either::Left(LayoutPage { title: node.title.clone().unwrap_or_default(), content: markup::new! { - @NodePage { node: &node, id, udata: &udata, children: &children, path: &path, filter: &filter, node_ext: &node_ext } + @NodePage { node: &node, id, udata: &udata, children: &[], path: &[], filter: &filter } }, ..Default::default() })) } markup::define! { - NodeCard<'a>(id: &'a str, node: &'a NodePublic, udata: &'a NodeUserData) { + NodeCard<'a>(id: &'a str, node: &'a Node, udata: &'a NodeUserData) { @let cls = format!("node card poster {}", aspect_class(node.kind.unwrap_or_default())); div[class=cls] { .poster { a[href=uri!(r_library_node(id))] { - img[src=uri!(r_item_assets(id, AssetRole::Poster, Some(1024))), loading="lazy"]; + img[src=uri!(r_item_poster(id, Some(1024))), loading="lazy"]; } .cardhover.item { @if node.media.is_some() { @@ -149,14 +137,14 @@ markup::define! { } } } - NodePage<'a>(id: &'a str, node: &'a NodePublic, node_ext: &'a ExtendedNode, udata: &'a NodeUserData, children: &'a [(String, NodePublic, NodeUserData)], path: &'a [(String, NodePublic)], filter: &'a NodeFilterSort) { + NodePage<'a>(id: &'a str, node: &'a Node, udata: &'a NodeUserData, children: &'a [(String, Node, NodeUserData)], path: &'a [(String, Node)], filter: &'a NodeFilterSort) { @if !matches!(node.kind.unwrap_or_default(), NodeKind::Collection) { - img.backdrop[src=uri!(r_item_assets(id, AssetRole::Backdrop, Some(2048))), loading="lazy"]; + img.backdrop[src=uri!(r_item_backdrop(id, Some(2048))), loading="lazy"]; } .page.node { @if !matches!(node.kind.unwrap_or_default(), NodeKind::Collection) { @let cls = format!("bigposter {}", aspect_class(node.kind.unwrap_or_default())); - div[class=cls] { img[src=uri!(r_item_assets(id, AssetRole::Poster, Some(2048))), loading="lazy"]; } + div[class=cls] { img[src=uri!(r_item_poster(id, Some(2048))), loading="lazy"]; } } .title { h1 { @node.title } @@ -213,16 +201,16 @@ markup::define! { }} }} } - @if !node_ext.people.is_empty() { + @if !node.people.is_empty() { h2 { "Cast & Crew" } - @for (group, people) in &node_ext.people { + @for (group, people) in &node.people { details[open=group==&PeopleGroup::Cast] { summary { h3 { @format!("{}", group) } } ul.children.hlist { @for (i, pe) in people.iter().enumerate() { li { .card."aspect-port" { .poster { a[href="#"] { - img[src=&uri!(r_person_asset(id, i, group, Some(1024))), loading="lazy"]; + img[src=&uri!(r_person_asset(id, i, group.to_string(), Some(1024))), loading="lazy"]; } } .title { @@ -265,7 +253,7 @@ markup::define! { } } - Props<'a>(node: &'a NodePublic, udata: &'a NodeUserData, full: bool) { + Props<'a>(node: &'a Node, udata: &'a NodeUserData, full: bool) { .props { @if let Some(m) = &node.media { p { @format_duration(m.duration) } @@ -278,9 +266,10 @@ markup::define! { @DateTime::from_timestamp_millis(*d).unwrap().date_naive().to_string() }} } - @if !node.children.is_empty() { - p { @format!("{} items", node.children.len()) } - } + // TODO + // @if !node.children.is_empty() { + // p { @format!("{} items", node.children.len()) } + // } @for (kind, value) in &node.ratings { @match kind { Rating::YoutubeLikes => {p{ @format_count(*value as usize) " Likes" }} @@ -337,21 +326,20 @@ pub trait DatabaseNodeUserDataExt { &self, id: &str, session: &Session, - ) -> Result<(String, NodePublic, NodeUserData)>; + ) -> Result<(String, Node, NodeUserData)>; } impl DatabaseNodeUserDataExt for DataAcid { fn get_node_with_userdata( &self, id: &str, session: &Session, - ) -> Result<(String, NodePublic, NodeUserData)> { + ) -> Result<(String, Node, NodeUserData)> { Ok(( id.to_owned(), T_NODE .get(self, id)? .only_if_permitted(&session.user.permissions) - .ok_or(anyhow!("node does not exist: {id}"))? - .public, + .ok_or(anyhow!("node does not exist: {id}"))?, T_USER_NODE .get(self, &(session.user.name.as_str(), id))? .unwrap_or_default(), diff --git a/server/src/routes/ui/player.rs b/server/src/routes/ui/player.rs index 55e1303..c5232e1 100644 --- a/server/src/routes/ui/player.rs +++ b/server/src/routes/ui/player.rs @@ -11,11 +11,7 @@ use crate::{ database::DataAcid, routes::{ stream::rocket_uri_macro_r_stream, - ui::{ - assets::{rocket_uri_macro_r_item_assets, AssetRole}, - error::MyResult, - layout::DynLayoutPage, - }, + ui::{assets::rocket_uri_macro_r_item_backdrop, error::MyResult, layout::DynLayoutPage}, }, uri, }; @@ -121,13 +117,13 @@ pub fn r_player<'a>( let conf = player_conf(item.clone(), playing)?; Ok(Either::Left(LayoutPage { - title: item.public.title.to_owned().unwrap_or_default(), + title: item.title.to_owned().unwrap_or_default(), class: Some("player"), content: markup::new! { @if playing { video[src=uri!(r_stream(&id, &spec)), controls, preload="auto"]{} } else { - img.backdrop[src=uri!(r_item_assets(&id, AssetRole::Backdrop, Some(2048))).to_string()]; + img.backdrop[src=uri!(r_item_backdrop(&id, Some(2048))).to_string()]; } @conf }, @@ -139,7 +135,6 @@ pub fn player_conf<'a>(item: Node, playing: bool) -> anyhow::Result<DynRender<'a let mut video_tracks = vec![]; let mut sub_tracks = vec![]; let tracks = item - .public .media .clone() .ok_or(anyhow!("node does not have media"))? @@ -155,7 +150,7 @@ pub fn player_conf<'a>(item: Node, playing: bool) -> anyhow::Result<DynRender<'a Ok(markup::new! { form.playerconf[method = "GET", action = ""] { - h2 { "Select tracks for " @item.public.title } + h2 { "Select tracks for " @item.title } fieldset.video { legend { "Video" } diff --git a/server/src/routes/ui/search.rs b/server/src/routes/ui/search.rs index 5ca4b51..c1f9865 100644 --- a/server/src/routes/ui/search.rs +++ b/server/src/routes/ui/search.rs @@ -51,8 +51,7 @@ pub async fn r_search<'a>( let node = T_NODE .get(db, id)? .only_if_permitted(&session.user.permissions) - .ok_or(anyhow!("node does not exist"))? - .public; + .ok_or(anyhow!("node does not exist"))?; let udata = T_USER_NODE .get(db, &(session.user.name.as_str(), id))? .unwrap_or_default(); diff --git a/server/src/routes/ui/sort.rs b/server/src/routes/ui/sort.rs index bcd9fe3..bb71184 100644 --- a/server/src/routes/ui/sort.rs +++ b/server/src/routes/ui/sort.rs @@ -1,7 +1,7 @@ use jellycommon::{ helpers::SortAnyway, user::{NodeUserData, WatchedState}, - NodeKind, NodePublic, Rating, + Node, NodeKind, Rating, }; use markup::RenderAttributeValue; use rocket::{ @@ -134,7 +134,7 @@ pub enum SortOrder { pub fn filter_and_sort_nodes( f: &NodeFilterSort, default_sort: (SortProperty, SortOrder), - nodes: &mut Vec<(String, NodePublic, NodeUserData)>, + nodes: &mut Vec<(String, Node, NodeUserData)>, ) { let sort_prop = f.sort_by.unwrap_or(default_sort.0); nodes.retain(|(_id, node, udata)| { |