E frontend reconciliation (1/2): types.ts sources from bindings; backend field fixes

- types.ts now re-exports wire types from generated bindings (single source of
  truth); keeps frontend-only unions (ItemType/LibraryType/PersonType/
  SessionCommand) and aliases Session = SessionInfo.
- Backend: MediaItem.runtime_ticks serializes as runTimeTicks (matches frontend,
  fixes a latent undefined-read bug); ArtistItem serializes camelCase id/name
  (PascalCase aliases retained for Jellyfin deserialize).
- player.ts: normalize remote NowPlayingItem -> MediaItem in mergedMedia so
  display components treat local/remote items uniformly.
- Reduces svelte-check errors 141 -> 70 (remaining: nullable guards + played->isPlayed).
This commit is contained in:
2026-06-20 20:30:08 +02:00
parent 6146d70bc5
commit 76c78e2edc
4 changed files with 81 additions and 244 deletions
+28 -4
View File
@@ -9,7 +9,8 @@
*/
import { writable, derived } from "svelte/store";
import type { MediaItem } from "$lib/api/types";
import type { MediaItem, ItemType } from "$lib/api/types";
import type { NowPlayingItem } from "$lib/api/bindings";
import { isRemoteMode } from "./playbackMode";
import { selectedSession } from "./sessions";
import { ticksToSeconds } from "$lib/utils/playbackUnits";
@@ -161,13 +162,36 @@ export const isMuted = derived(player, ($p) => $p.muted);
/**
* Merged media item - prefers remote session when in remote mode
*/
export const mergedMedia = derived(
/**
* Normalize a remote session's NowPlayingItem into the MediaItem shape the UI
* renders, so display components can treat local and remote items uniformly.
* (NowPlayingItem has `album`/`artists` but no `albumName`/`artistItems`; the UI
* falls back to the `artists` string list when `artistItems` is absent.)
*/
function nowPlayingToMediaItem(npi: NowPlayingItem): MediaItem {
return {
id: npi.id ?? "",
name: npi.name ?? "",
type: (npi.Type ?? "Audio") as ItemType,
serverId: "",
albumName: npi.album,
albumId: npi.albumId,
artists: npi.artists,
primaryImageTag: npi.primaryImageTag ?? npi.albumPrimaryImageTag,
runTimeTicks: npi.runTimeTicks,
} as MediaItem;
}
export const mergedMedia = derived<
[typeof isRemoteMode, typeof selectedSession, typeof currentMedia],
MediaItem | null
>(
[isRemoteMode, selectedSession, currentMedia],
([$isRemote, $session, $local]) => {
if ($isRemote && $session?.nowPlayingItem) {
return $session.nowPlayingItem;
return nowPlayingToMediaItem($session.nowPlayingItem);
}
return $local;
return $local ?? null;
}
);