domain: primaryImageTag -> imageId end-to-end (phase 4a/4b)
Rust: PlayerMediaItem and MergedMediaItem gain image_id (dual-carry), populated from primary_image_tag at every construction/conversion site. Regenerated bindings. Frontend: all catalog + player + merged readers now use imageId. The NowPlayingItem->MediaItem bridge (player.ts) properly maps the remote session's Jellyfin fields (Type, runTimeTicks, primaryImageTag) onto the neutral kind/durationMs/imageId. Types that are genuinely out of scope (Person, NowPlayingItem, PlayItemRequest) keep primaryImageTag. Rust 456, frontend 644, check clean.
This commit is contained in:
@@ -45,7 +45,7 @@ function createMoviesStore() {
|
||||
|
||||
/** Artwork check for hero candidates: needs a backdrop or a primary image. */
|
||||
const hasArt = (i: MediaItem) =>
|
||||
!!(i.backdropImageTags && i.backdropImageTags.length > 0) || !!i.primaryImageTag;
|
||||
!!(i.backdropImageTags && i.backdropImageTags.length > 0) || !!i.imageId;
|
||||
|
||||
async function loadSections(libraryId: string) {
|
||||
update(s => ({
|
||||
|
||||
@@ -55,7 +55,7 @@ function createMusicStore() {
|
||||
|
||||
/** Artwork check for hero candidates: needs a primary image or backdrop. */
|
||||
const hasArt = (i: MediaItem) =>
|
||||
!!i.primaryImageTag || !!(i.backdropImageTags && i.backdropImageTags.length > 0);
|
||||
!!i.imageId || !!(i.backdropImageTags && i.backdropImageTags.length > 0);
|
||||
|
||||
async function loadSections(libraryId: string) {
|
||||
update(s => ({
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
*/
|
||||
|
||||
import { writable, derived } from "svelte/store";
|
||||
import type { MediaItem, ItemType } from "$lib/api/types";
|
||||
import type { MediaItem, MediaKind } from "$lib/api/types";
|
||||
import type { NowPlayingItem } from "$lib/api/bindings";
|
||||
import { isRemoteMode } from "./playbackMode";
|
||||
import { selectedSession } from "./sessions";
|
||||
@@ -24,7 +24,7 @@ export interface MergedMediaItem {
|
||||
album: string | null;
|
||||
albumId: string | null;
|
||||
duration: number | null;
|
||||
primaryImageTag: string | null;
|
||||
imageId: string | null;
|
||||
mediaType: "audio" | "video";
|
||||
}
|
||||
|
||||
@@ -170,16 +170,24 @@ export const isMuted = derived(player, ($p) => $p.muted);
|
||||
* falls back to the `artists` string list when `artistItems` is absent.)
|
||||
*/
|
||||
function nowPlayingToMediaItem(npi: NowPlayingItem): MediaItem {
|
||||
// NowPlayingItem is remote-session data still carrying Jellyfin field names
|
||||
// (Type, runTimeTicks, primaryImageTag). Map it onto the neutral MediaItem the
|
||||
// UI consumes. Only the coarse audio/video split matters here for display.
|
||||
const kind: MediaKind =
|
||||
npi.Type === "Movie" ? "movie" :
|
||||
npi.Type === "Episode" ? "episode" :
|
||||
npi.Type === "MusicAlbum" ? "album" :
|
||||
"track";
|
||||
return {
|
||||
id: npi.id ?? "",
|
||||
name: npi.name ?? "",
|
||||
type: (npi.Type ?? "Audio") as ItemType,
|
||||
kind,
|
||||
serverId: "",
|
||||
albumName: npi.album,
|
||||
albumId: npi.albumId,
|
||||
artists: npi.artists,
|
||||
primaryImageTag: npi.primaryImageTag ?? npi.albumPrimaryImageTag,
|
||||
runTimeTicks: npi.runTimeTicks,
|
||||
imageId: npi.primaryImageTag ?? npi.albumPrimaryImageTag,
|
||||
durationMs: npi.runTimeTicks != null ? Math.floor(npi.runTimeTicks / 10000) : null,
|
||||
} as MediaItem;
|
||||
}
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ function createTvStore() {
|
||||
const hasArt = (i: MediaItem) =>
|
||||
!!(i.backdropImageTags && i.backdropImageTags.length > 0) ||
|
||||
!!(i.parentBackdropImageTags && i.parentBackdropImageTags.length > 0) ||
|
||||
!!i.primaryImageTag;
|
||||
!!i.imageId;
|
||||
|
||||
async function loadSections(libraryId: string) {
|
||||
update(s => ({
|
||||
|
||||
Reference in New Issue
Block a user