fix(kiosk): auto-hide OSD, prioritize hardware-decoded formats, clean YouTube share URLs
This commit is contained in:
@@ -26,7 +26,7 @@ pub enum PlayableTarget {
|
||||
OpenFolder { folder_id: String, name: String },
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||
pub struct MediaItem {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
@@ -48,6 +48,11 @@ pub struct MediaItem {
|
||||
pub has_backdrop_image: bool,
|
||||
pub parent_primary_image_item_id: Option<String>,
|
||||
pub parent_backdrop_item_id: Option<String>,
|
||||
pub recursive_item_count: Option<u32>,
|
||||
pub child_count: Option<u32>,
|
||||
pub series_id: Option<String>,
|
||||
pub album_id: Option<String>,
|
||||
pub album: Option<String>,
|
||||
}
|
||||
|
||||
impl MediaItem {
|
||||
@@ -604,22 +609,95 @@ impl JellyfinClient {
|
||||
if let Ok(headers) = self.get_authed_headers().await {
|
||||
let user_id = self.user_id.read().await.clone().unwrap_or_default();
|
||||
let url = format!(
|
||||
"{}/Shows/{}/Episodes?userId={}&fields=Overview,ProductionYear,CommunityRating,ParentBackdropItemId,ParentPrimaryImageItemId,UserData,IndexNumber,ParentIndexNumber,SortName,Genres",
|
||||
"{}/Shows/{}/Episodes?userId={}&fields=Overview,ProductionYear,CommunityRating,ParentBackdropItemId,ParentPrimaryImageItemId,UserData,IndexNumber,ParentIndexNumber,SortName,Genres,SeriesId",
|
||||
base_url, show_id, user_id
|
||||
);
|
||||
return fetch_endpoint(&self.client, &url, &headers).await;
|
||||
}
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
pub async fn fetch_episodes_paged(
|
||||
&self,
|
||||
show_id: Option<&str>,
|
||||
season: Option<u32>,
|
||||
start: usize,
|
||||
limit: usize,
|
||||
) -> (usize, Vec<MediaItem>) {
|
||||
let base_url = self.config.server_url.trim_end_matches('/');
|
||||
if let Ok(headers) = self.get_authed_headers().await {
|
||||
let user_id = self.user_id.read().await.clone().unwrap_or_default();
|
||||
let url = if let Some(sid) = show_id {
|
||||
if let Some(s_num) = season {
|
||||
format!(
|
||||
"{}/Shows/{}/Episodes?userId={}&season={}&startIndex={}&limit={}&fields=Overview,ProductionYear,CommunityRating,ParentBackdropItemId,ParentPrimaryImageItemId,UserData,IndexNumber,ParentIndexNumber,SortName,Genres,SeriesId",
|
||||
base_url, sid, user_id, s_num, start, limit
|
||||
)
|
||||
} else {
|
||||
format!(
|
||||
"{}/Shows/{}/Episodes?userId={}&startIndex={}&limit={}&fields=Overview,ProductionYear,CommunityRating,ParentBackdropItemId,ParentPrimaryImageItemId,UserData,IndexNumber,ParentIndexNumber,SortName,Genres,SeriesId",
|
||||
base_url, sid, user_id, start, limit
|
||||
)
|
||||
}
|
||||
} else {
|
||||
format!(
|
||||
"{}/Users/{}/Items?includeItemTypes=Episode&recursive=true&startIndex={}&limit={}&fields=Overview,ProductionYear,CommunityRating,ParentBackdropItemId,ParentPrimaryImageItemId,UserData,IndexNumber,ParentIndexNumber,SortName,Genres,SeriesId",
|
||||
base_url, user_id, start, limit
|
||||
)
|
||||
};
|
||||
return fetch_endpoint_paged(&self.client, &url, &headers).await;
|
||||
}
|
||||
(0, Vec::new())
|
||||
}
|
||||
|
||||
pub async fn fetch_songs_paged(
|
||||
&self,
|
||||
album_id: Option<&str>,
|
||||
artist_id: Option<&str>,
|
||||
start: usize,
|
||||
limit: usize,
|
||||
) -> (usize, Vec<MediaItem>) {
|
||||
let base_url = self.config.server_url.trim_end_matches('/');
|
||||
if let Ok(headers) = self.get_authed_headers().await {
|
||||
let user_id = self.user_id.read().await.clone().unwrap_or_default();
|
||||
let url = if let Some(aid) = album_id {
|
||||
format!(
|
||||
"{}/Users/{}/Items?parentId={}&includeItemTypes=Audio&startIndex={}&limit={}&fields=Overview,ProductionYear,ParentBackdropItemId,ParentPrimaryImageItemId,UserData,IndexNumber,ParentIndexNumber,SortName,Genres,Album,AlbumId,ArtistItems,Artists,RunTimeTicks",
|
||||
base_url, user_id, aid, start, limit
|
||||
)
|
||||
} else if let Some(arid) = artist_id {
|
||||
format!(
|
||||
"{}/Users/{}/Items?artistIds={}&includeItemTypes=Audio&recursive=true&startIndex={}&limit={}&fields=Overview,ProductionYear,ParentBackdropItemId,ParentPrimaryImageItemId,UserData,IndexNumber,ParentIndexNumber,SortName,Genres,Album,AlbumId,ArtistItems,Artists,RunTimeTicks",
|
||||
base_url, user_id, arid, start, limit
|
||||
)
|
||||
} else {
|
||||
format!(
|
||||
"{}/Users/{}/Items?includeItemTypes=Audio&recursive=true&startIndex={}&limit={}&fields=Overview,ProductionYear,ParentBackdropItemId,ParentPrimaryImageItemId,UserData,IndexNumber,ParentIndexNumber,SortName,Genres,Album,AlbumId,ArtistItems,Artists,RunTimeTicks",
|
||||
base_url, user_id, start, limit
|
||||
)
|
||||
};
|
||||
return fetch_endpoint_paged(&self.client, &url, &headers).await;
|
||||
}
|
||||
(0, Vec::new())
|
||||
}
|
||||
}
|
||||
|
||||
async fn fetch_endpoint(client: &reqwest::Client, url: &str, headers: &HeaderMap) -> Vec<MediaItem> {
|
||||
fetch_endpoint_paged(client, url, headers).await.1
|
||||
}
|
||||
|
||||
async fn fetch_endpoint_paged(client: &reqwest::Client, url: &str, headers: &HeaderMap) -> (usize, Vec<MediaItem>) {
|
||||
if let Ok(resp) = client.get(url).headers(headers.clone()).send().await {
|
||||
if let Ok(json) = resp.json::<serde_json::Value>().await {
|
||||
return parse_items(&json);
|
||||
let items = parse_items(&json);
|
||||
let total = json["TotalRecordCount"]
|
||||
.as_u64()
|
||||
.map(|n| n as usize)
|
||||
.unwrap_or(items.len());
|
||||
return (total, items);
|
||||
}
|
||||
}
|
||||
Vec::new()
|
||||
(0, Vec::new())
|
||||
}
|
||||
|
||||
fn parse_items(json: &serde_json::Value) -> Vec<MediaItem> {
|
||||
@@ -630,7 +708,16 @@ fn parse_items(json: &serde_json::Value) -> Vec<MediaItem> {
|
||||
let name = it["Name"].as_str().unwrap_or("Onbekend").to_string();
|
||||
let item_type = it["Type"].as_str().unwrap_or("Video").to_string();
|
||||
let series_name = it["SeriesName"].as_str().map(|s| s.to_string());
|
||||
let artist_name = it["AlbumArtist"].as_str().or_else(|| it["Artist"].as_str()).map(|s| s.to_string());
|
||||
let artist_name = it["AlbumArtist"]
|
||||
.as_str()
|
||||
.or_else(|| it["Artist"].as_str())
|
||||
.map(|s| s.to_string())
|
||||
.or_else(|| {
|
||||
it["Artists"].as_array().and_then(|arr| arr.first().and_then(|a| a.as_str())).map(|s| s.to_string())
|
||||
})
|
||||
.or_else(|| {
|
||||
it["ArtistItems"].as_array().and_then(|arr| arr.first().and_then(|a| a["Name"].as_str())).map(|s| s.to_string())
|
||||
});
|
||||
let genre = it["Genres"].as_array().and_then(|arr| {
|
||||
let list: Vec<&str> = arr.iter().filter_map(|g| g.as_str()).collect();
|
||||
if list.is_empty() {
|
||||
@@ -661,6 +748,11 @@ fn parse_items(json: &serde_json::Value) -> Vec<MediaItem> {
|
||||
let index_number = it["IndexNumber"].as_u64().map(|n| n as u32);
|
||||
let parent_index_number = it["ParentIndexNumber"].as_u64().map(|n| n as u32);
|
||||
let season_name = it["SeasonName"].as_str().map(|s| s.to_string());
|
||||
let recursive_item_count = it["RecursiveItemCount"].as_u64().map(|n| n as u32);
|
||||
let child_count = it["ChildCount"].as_u64().map(|n| n as u32);
|
||||
let series_id = it["SeriesId"].as_str().map(|s| s.to_string());
|
||||
let album_id = it["AlbumId"].as_str().map(|s| s.to_string());
|
||||
let album = it["Album"].as_str().map(|s| s.to_string());
|
||||
|
||||
if !id.is_empty() {
|
||||
out.push(MediaItem {
|
||||
@@ -684,6 +776,11 @@ fn parse_items(json: &serde_json::Value) -> Vec<MediaItem> {
|
||||
has_backdrop_image,
|
||||
parent_primary_image_item_id,
|
||||
parent_backdrop_item_id,
|
||||
recursive_item_count,
|
||||
child_count,
|
||||
series_id,
|
||||
album_id,
|
||||
album,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user