new
This commit is contained in:
@@ -50,6 +50,16 @@ pub struct MediaItem {
|
||||
|
||||
impl MediaItem {
|
||||
pub fn primary_image_id(&self) -> &str {
|
||||
if let Some(ref p_id) = self.parent_primary_image_item_id {
|
||||
if p_id.starts_with("http://") || p_id.starts_with("https://") {
|
||||
return p_id;
|
||||
}
|
||||
}
|
||||
if let Some(ref b_id) = self.parent_backdrop_item_id {
|
||||
if b_id.starts_with("http://") || b_id.starts_with("https://") {
|
||||
return b_id;
|
||||
}
|
||||
}
|
||||
if self.has_primary_image {
|
||||
&self.id
|
||||
} else if let Some(ref p_id) = self.parent_primary_image_item_id {
|
||||
@@ -268,7 +278,25 @@ impl JellyfinClient {
|
||||
);
|
||||
let mut items = fetch_endpoint(&self.client, &url, &headers).await;
|
||||
|
||||
// 2. If empty, maybe this is an artist: try fetching albums via albumArtistIds
|
||||
// 2. If empty, maybe this is a TV Show (Series): fetch seasons
|
||||
if items.is_empty() {
|
||||
let url_seasons = format!(
|
||||
"{}/Shows/{}/Seasons?userId={}&fields=Overview,ProductionYear,CommunityRating,ParentBackdropItemId,ParentPrimaryImageItemId,UserData,IndexNumber,SortName,Genres",
|
||||
base_url, folder_id, user_id
|
||||
);
|
||||
items = fetch_endpoint(&self.client, &url_seasons, &headers).await;
|
||||
}
|
||||
|
||||
// 3. If empty, maybe this is a Season: fetch episodes
|
||||
if items.is_empty() {
|
||||
let url_episodes = format!(
|
||||
"{}/Shows/{}/Episodes?userId={}&fields=Overview,ProductionYear,CommunityRating,ParentBackdropItemId,ParentPrimaryImageItemId,UserData,IndexNumber,SortName,Genres",
|
||||
base_url, folder_id, user_id
|
||||
);
|
||||
items = fetch_endpoint(&self.client, &url_episodes, &headers).await;
|
||||
}
|
||||
|
||||
// 4. If empty, maybe this is an artist: try fetching albums via albumArtistIds
|
||||
if items.is_empty() {
|
||||
let url_albums = format!(
|
||||
"{}/Users/{}/Items?albumArtistIds={}&includeItemTypes=MusicAlbum&recursive=true&sortBy=SortName&limit=500&fields=Overview,ProductionYear,CommunityRating,ParentBackdropItemId,ParentPrimaryImageItemId,UserData,IndexNumber,SortName,Genres",
|
||||
@@ -277,7 +305,7 @@ impl JellyfinClient {
|
||||
items = fetch_endpoint(&self.client, &url_albums, &headers).await;
|
||||
}
|
||||
|
||||
// 3. If still empty, try artistIds for albums
|
||||
// 5. If still empty, try artistIds for albums
|
||||
if items.is_empty() {
|
||||
let url_albums2 = format!(
|
||||
"{}/Users/{}/Items?artistIds={}&includeItemTypes=MusicAlbum&recursive=true&sortBy=SortName&limit=500&fields=Overview,ProductionYear,CommunityRating,ParentBackdropItemId,ParentPrimaryImageItemId,UserData,IndexNumber,SortName,Genres",
|
||||
@@ -286,7 +314,7 @@ impl JellyfinClient {
|
||||
items = fetch_endpoint(&self.client, &url_albums2, &headers).await;
|
||||
}
|
||||
|
||||
// 4. If still empty (e.g. ABBA, *NSYNC who have no albums, only compilation tracks), fetch individual audio songs directly
|
||||
// 6. If still empty (e.g. ABBA, *NSYNC who have no albums, only compilation tracks), fetch individual audio songs directly
|
||||
if items.is_empty() {
|
||||
let url_songs = format!(
|
||||
"{}/Users/{}/Items?artistIds={}&includeItemTypes=Audio&recursive=true&sortBy=SortName&limit=500&fields=Overview,ProductionYear,CommunityRating,ParentBackdropItemId,ParentPrimaryImageItemId,UserData,IndexNumber,SortName,Genres",
|
||||
@@ -295,8 +323,8 @@ impl JellyfinClient {
|
||||
items = fetch_endpoint(&self.client, &url_songs, &headers).await;
|
||||
}
|
||||
|
||||
// If the folder items are Audio tracks, sort them by index_number
|
||||
if items.iter().any(|i| i.item_type == "Audio") {
|
||||
// If the folder items are Audio tracks, Seasons, or Episodes, sort them by index_number
|
||||
if items.iter().any(|i| i.item_type == "Audio" || i.item_type == "Season" || i.item_type == "Episode") {
|
||||
items.sort_by_key(|i| i.index_number.unwrap_or(u32::MAX));
|
||||
} else {
|
||||
sort_media_items_alphabetically(&mut items);
|
||||
@@ -312,10 +340,6 @@ impl JellyfinClient {
|
||||
let guard = self.token.read().await;
|
||||
guard.clone().unwrap_or_default()
|
||||
};
|
||||
let user_id = {
|
||||
let guard = self.user_id.read().await;
|
||||
guard.clone().unwrap_or_default()
|
||||
};
|
||||
|
||||
// 0. YouTube Video or direct stream URL
|
||||
if item.item_type == "YouTubeVideo"
|
||||
@@ -339,43 +363,13 @@ impl JellyfinClient {
|
||||
});
|
||||
}
|
||||
|
||||
// 2. Series -> resolve next unplayed episode
|
||||
if item.item_type == "Series" {
|
||||
if let Ok(headers) = self.get_authed_headers().await {
|
||||
let next_url = format!("{}/Shows/NextUp?seriesId={}&userId={}&fields=Genres", base_url, item.id, user_id);
|
||||
let episodes = fetch_endpoint(&self.client, &next_url, &headers).await;
|
||||
if let Some(ep) = episodes.first() {
|
||||
return Ok(PlayableTarget::Stream {
|
||||
url: ep.stream_url(base_url, &token),
|
||||
title: format!("{}: {}", item.name, ep.name),
|
||||
media_type: "video".to_string(),
|
||||
artist: None,
|
||||
genre: ep.genre.clone().or_else(|| item.genre.clone()),
|
||||
});
|
||||
}
|
||||
// Fallback: episode 1
|
||||
let ep1_url = format!(
|
||||
"{}/Users/{}/Items?parentId={}&includeItemTypes=Episode&recursive=true&sortBy=SortName&limit=1&fields=Genres",
|
||||
base_url, user_id, item.id
|
||||
);
|
||||
let ep1 = fetch_endpoint(&self.client, &ep1_url, &headers).await;
|
||||
if let Some(ep) = ep1.first() {
|
||||
return Ok(PlayableTarget::Stream {
|
||||
url: ep.stream_url(base_url, &token),
|
||||
title: format!("{}: {}", item.name, ep.name),
|
||||
media_type: "video".to_string(),
|
||||
artist: None,
|
||||
genre: ep.genre.clone().or_else(|| item.genre.clone()),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. PhotoAlbum, Folder, MusicArtist, or MusicAlbum -> Open folder in UI
|
||||
if item.item_type == "PhotoAlbum"
|
||||
// 2. Series, Season, PhotoAlbum, Folder, MusicArtist, or MusicAlbum -> Open folder in UI
|
||||
if item.item_type == "Series"
|
||||
|| item.item_type == "Season"
|
||||
|| item.item_type == "PhotoAlbum"
|
||||
|| item.item_type == "MusicArtist"
|
||||
|| item.item_type == "MusicAlbum"
|
||||
|| (item.is_folder && item.item_type != "Series")
|
||||
|| item.is_folder
|
||||
{
|
||||
return Ok(PlayableTarget::OpenFolder {
|
||||
folder_id: item.id.clone(),
|
||||
|
||||
Reference in New Issue
Block a user