aboutsummaryrefslogtreecommitdiff
path: root/server/src/routes/compat/jellyfin/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'server/src/routes/compat/jellyfin/mod.rs')
-rw-r--r--server/src/routes/compat/jellyfin/mod.rs117
1 files changed, 79 insertions, 38 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 {