aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2025-02-04 15:18:45 +0100
committermetamuffin <metamuffin@disroot.org>2025-02-04 15:18:45 +0100
commita117b0710fca0ba1ef1329a8921092d1bf46abcd (patch)
treec0524a44863bfce370f4a7d8a5efa7e9d381b134
parent8118667fc80bdf0246b16dff08f5a522efea27cf (diff)
downloadjellything-a117b0710fca0ba1ef1329a8921092d1bf46abcd.tar
jellything-a117b0710fca0ba1ef1329a8921092d1bf46abcd.tar.bz2
jellything-a117b0710fca0ba1ef1329a8921092d1bf46abcd.tar.zst
jellyfin backdrop
-rw-r--r--server/src/routes/compat/jellyfin/mod.rs117
-rw-r--r--server/src/routes/compat/jellyfin/models.rs2
-rw-r--r--server/src/routes/mod.rs16
-rw-r--r--server/src/routes/ui/node.rs1
-rw-r--r--server/src/routes/ui/sort.rs6
5 files changed, 92 insertions, 50 deletions
diff --git a/server/src/routes/compat/jellyfin/mod.rs b/server/src/routes/compat/jellyfin/mod.rs
index 0fed578..85d6768 100644
--- a/server/src/routes/compat/jellyfin/mod.rs
+++ b/server/src/routes/compat/jellyfin/mod.rs
@@ -9,9 +9,13 @@ use crate::routes::{
stream::rocket_uri_macro_r_stream,
ui::{
account::{login_logic, session::Session},
- assets::{rocket_uri_macro_r_asset, rocket_uri_macro_r_item_poster},
+ assets::{
+ rocket_uri_macro_r_asset, rocket_uri_macro_r_item_backdrop,
+ rocket_uri_macro_r_item_poster,
+ },
error::MyResult,
node::{aspect_class, DatabaseNodeUserDataExt},
+ sort::{filter_and_sort_nodes, FilterProperty, NodeFilterSort, SortOrder, SortProperty},
},
};
use anyhow::{anyhow, Context};
@@ -151,15 +155,25 @@ pub fn r_jellyfin_items_image_primary(
_session: Session,
id: &str,
fillWidth: Option<usize>,
- tag: Option<String>,
+ tag: String,
) -> Redirect {
- if let Some(tag) = tag {
- Redirect::permanent(rocket::uri!(r_asset(tag, fillWidth)))
- } else {
+ if tag == "poster" {
Redirect::permanent(rocket::uri!(r_item_poster(id, fillWidth)))
+ } else {
+ Redirect::permanent(rocket::uri!(r_asset(tag, fillWidth)))
}
}
+#[get("/Items/<id>/Images/Backdrop/0?<maxWidth>")]
+#[allow(non_snake_case)]
+pub fn r_jellyfin_items_images_backdrop(
+ _session: Session,
+ id: &str,
+ maxWidth: Option<usize>,
+) -> Redirect {
+ Redirect::permanent(rocket::uri!(r_item_backdrop(id, maxWidth)))
+}
+
#[get("/Items/<id>")]
#[allow(private_interfaces)]
pub fn r_jellyfin_items_item(
@@ -250,52 +264,70 @@ pub fn r_jellyfin_items(
database: &State<Database>,
query: JellyfinItemQuery,
) -> MyResult<Json<Value>> {
- let mut items = Vec::new();
-
- let nodes = if let Some(q) = query.search_term {
- database
- .search(&q, query.limit, query.start_index.unwrap_or_default())?
- .1
+ let (nodes, parent_kind) = if let Some(q) = query.search_term {
+ (
+ database
+ .search(&q, query.limit, query.start_index.unwrap_or_default())?
+ .1,
+ None,
+ )
} else if let Some(parent) = query.parent_id {
- database
- .get_node_children(NodeID::from_slug(&parent))?
- .into_iter()
- .skip(query.start_index.unwrap_or_default())
- .take(query.limit)
- .collect()
+ let parent = NodeID::from_slug(&parent);
+ (
+ database
+ .get_node_children(parent)?
+ .into_iter()
+ .skip(query.start_index.unwrap_or_default())
+ .take(query.limit)
+ .collect(),
+ database.get_node(parent)?.map(|n| n.kind),
+ )
} else {
- vec![]
+ (vec![], None)
};
let filter_kind = query
.include_item_types
- .map(|n| match n.as_str() {
- "Movie" => NodeKind::Movie,
- "Audio" => NodeKind::Music,
- "Video" => NodeKind::Video,
- _ => NodeKind::Unknown,
+ .and_then(|n| match n.as_str() {
+ "Movie" => Some(FilterProperty::KindMovie),
+ "Audio" => Some(FilterProperty::KindMusic),
+ "Video" => Some(FilterProperty::KindVideo),
+ _ => None,
})
.or(if query.internal_artists {
- Some(NodeKind::Channel)
+ Some(FilterProperty::KindChannel)
} else {
None
})
.or(if query.internal_persons {
- Some(NodeKind::Channel)
+ Some(FilterProperty::KindChannel)
} else {
None
});
- for nid in nodes {
- let (n, ud) = database.get_node_with_userdata(nid, &session)?;
- if let Some(fk) = filter_kind {
- if n.kind != fk {
- continue;
- }
- }
- if n.visibility >= Visibility::Reduced {
- items.push(item_object(&n, &ud))
- }
- }
+
+ let mut nodes = nodes
+ .into_iter()
+ .map(|nid| database.get_node_with_userdata(nid, &session))
+ .collect::<Result<Vec<_>, anyhow::Error>>()?;
+
+ filter_and_sort_nodes(
+ &NodeFilterSort {
+ sort_by: None,
+ filter_kind: filter_kind.map(|a| vec![a]),
+ sort_order: None,
+ },
+ match parent_kind {
+ Some(NodeKind::Channel) => (SortProperty::ReleaseDate, SortOrder::Descending),
+ _ => (SortProperty::Title, SortOrder::Ascending),
+ },
+ &mut nodes,
+ );
+
+ let items = nodes
+ .into_iter()
+ .filter(|(n, _)| n.visibility >= Visibility::Reduced)
+ .map(|(n, ud)| item_object(&n, &ud))
+ .collect::<Vec<_>>();
Ok(Json(json!({
"Items": items,
@@ -361,6 +393,15 @@ pub fn r_jellyfin_items_intros(_session: Session, uid: &str, id: &str) -> Json<V
}))
}
+#[get("/Shows/NextUp")]
+pub fn r_jellyfin_shows_nextup(_session: Session) -> Json<Value> {
+ Json(json!({
+ "Items": [],
+ "TotalRecordCount": 0,
+ "StartIndex": 0
+ }))
+}
+
#[post("/Items/<id>/PlaybackInfo")]
pub fn r_jellyfin_items_playbackinfo(
_session: Session,
@@ -704,8 +745,8 @@ fn item_object(node: &Node, userdata: &NodeUserData) -> JellyfinItem {
"aspect-square" | _ => 1.,
},
collection_type: "unknown".to_owned(),
- image_tags: BTreeMap::from_iter([("Primary".to_string(), "the-image".to_string())]),
- backdrop_image_tags: vec![],
+ image_tags: BTreeMap::from_iter([("Primary".to_string(), "poster".to_string())]),
+ backdrop_image_tags: vec!["backdrop".to_string()],
media_type: if node.media.is_some() {
"Video".to_owned()
} else {
diff --git a/server/src/routes/compat/jellyfin/models.rs b/server/src/routes/compat/jellyfin/models.rs
index eeffa34..be41835 100644
--- a/server/src/routes/compat/jellyfin/models.rs
+++ b/server/src/routes/compat/jellyfin/models.rs
@@ -163,7 +163,7 @@ pub(super) struct JellyfinItem {
pub primary_image_aspect_ratio: f64,
pub collection_type: String,
pub image_tags: BTreeMap<String, String>,
- pub backdrop_image_tags: Vec<()>,
+ pub backdrop_image_tags: Vec<String>,
pub location_type: Option<String>,
pub media_type: String,
pub video_type: Option<String>,
diff --git a/server/src/routes/mod.rs b/server/src/routes/mod.rs
index 98ea4b0..a0c2de4 100644
--- a/server/src/routes/mod.rs
+++ b/server/src/routes/mod.rs
@@ -12,16 +12,16 @@ use compat::{
r_jellyfin_artists, r_jellyfin_branding_configuration, r_jellyfin_branding_css,
r_jellyfin_displaypreferences_usersettings,
r_jellyfin_displaypreferences_usersettings_post, r_jellyfin_items,
- r_jellyfin_items_image_primary, r_jellyfin_items_intros, r_jellyfin_items_item,
- r_jellyfin_items_playbackinfo, r_jellyfin_items_similar,
+ r_jellyfin_items_image_primary, r_jellyfin_items_images_backdrop, r_jellyfin_items_intros,
+ r_jellyfin_items_item, r_jellyfin_items_playbackinfo, r_jellyfin_items_similar,
r_jellyfin_livetv_programs_recommended, r_jellyfin_persons,
r_jellyfin_playback_bitratetest, r_jellyfin_quickconnect_enabled,
r_jellyfin_sessions_capabilities_full, r_jellyfin_sessions_playing,
- r_jellyfin_sessions_playing_progress, r_jellyfin_socket, r_jellyfin_system_endpoint,
- r_jellyfin_system_info, r_jellyfin_system_info_public, r_jellyfin_system_info_public_case,
- r_jellyfin_users_authenticatebyname, r_jellyfin_users_id, r_jellyfin_users_items,
- r_jellyfin_users_items_item, r_jellyfin_users_public, r_jellyfin_users_views,
- r_jellyfin_video_stream,
+ r_jellyfin_sessions_playing_progress, r_jellyfin_shows_nextup, r_jellyfin_socket,
+ r_jellyfin_system_endpoint, r_jellyfin_system_info, r_jellyfin_system_info_public,
+ r_jellyfin_system_info_public_case, r_jellyfin_users_authenticatebyname,
+ r_jellyfin_users_id, r_jellyfin_users_items, r_jellyfin_users_items_item,
+ r_jellyfin_users_public, r_jellyfin_users_views, r_jellyfin_video_stream,
},
youtube::{r_youtube_channel, r_youtube_watch},
};
@@ -170,6 +170,7 @@ pub fn build_rocket(database: Database, federation: Federation) -> Rocket<Build>
r_jellyfin_displaypreferences_usersettings_post,
r_jellyfin_displaypreferences_usersettings,
r_jellyfin_items_image_primary,
+ r_jellyfin_items_images_backdrop,
r_jellyfin_items_intros,
r_jellyfin_items_item,
r_jellyfin_items_playbackinfo,
@@ -182,6 +183,7 @@ pub fn build_rocket(database: Database, federation: Federation) -> Rocket<Build>
r_jellyfin_sessions_capabilities_full,
r_jellyfin_sessions_playing_progress,
r_jellyfin_sessions_playing,
+ r_jellyfin_shows_nextup,
r_jellyfin_socket,
r_jellyfin_system_endpoint,
r_jellyfin_system_info_public_case,
diff --git a/server/src/routes/ui/node.rs b/server/src/routes/ui/node.rs
index 7c89462..337d249 100644
--- a/server/src/routes/ui/node.rs
+++ b/server/src/routes/ui/node.rs
@@ -76,7 +76,6 @@ pub async fn r_library_node_filter<'a>(
NodeKind::Channel => (SortProperty::ReleaseDate, SortOrder::Descending),
_ => (SortProperty::Title, SortOrder::Ascending),
},
- // TODO
&mut children,
);
diff --git a/server/src/routes/ui/sort.rs b/server/src/routes/ui/sort.rs
index 3831431..06e0209 100644
--- a/server/src/routes/ui/sort.rs
+++ b/server/src/routes/ui/sort.rs
@@ -12,9 +12,9 @@ use std::sync::Arc;
#[derive(FromForm, UriDisplayQuery, Default, Clone)]
pub struct NodeFilterSort {
- sort_by: Option<SortProperty>,
- filter_kind: Option<Vec<FilterProperty>>,
- sort_order: Option<SortOrder>,
+ pub sort_by: Option<SortProperty>,
+ pub filter_kind: Option<Vec<FilterProperty>>,
+ pub sort_order: Option<SortOrder>,
}
macro_rules! form_enum {