From 2589b695f1b14d980a64edad819892a4aeed13ff Mon Sep 17 00:00:00 2001 From: lashman Date: Tue, 28 Apr 2026 03:08:59 +0300 Subject: [PATCH] type pages and utilities --- src/lib/audio-graph.ts | 2 +- src/lib/cast.ts | 2 +- src/lib/downloads.ts | 2 +- src/lib/episode-meta.ts | 4 +- src/lib/item-types.ts | 2 +- src/lib/stats.ts | 2 +- src/lib/trakt.ts | 4 +- src/pages/DetailPage.tsx | 2 +- src/pages/HomePage.tsx | 2 +- src/pages/LibraryPage.tsx | 4 +- src/pages/LiveTvPage.tsx | 2 +- src/pages/PersonPage.tsx | 4 +- src/pages/PlayerPage.tsx | 38 +++++++++---------- src/pages/SearchPage.tsx | 6 +-- src/pages/TmdbDetailPage.tsx | 18 ++++----- src/pages/home/rows/library.tsx | 2 +- .../settings/sections/ServerDashboard.tsx | 2 +- 17 files changed, 49 insertions(+), 49 deletions(-) diff --git a/src/lib/audio-graph.ts b/src/lib/audio-graph.ts index 1e6671c..4ec9c98 100644 --- a/src/lib/audio-graph.ts +++ b/src/lib/audio-graph.ts @@ -52,7 +52,7 @@ export function ensureAudioGraph(video: HTMLVideoElement): AudioGraph | null { if (graph) detachAudioGraph() try { - const Ctor = window.AudioContext || (window as any).webkitAudioContext + const Ctor = window.AudioContext || window.webkitAudioContext if (!Ctor) return null const ctx: AudioContext = new Ctor() const source = ctx.createMediaElementSource(video) diff --git a/src/lib/cast.ts b/src/lib/cast.ts index a61b82c..30e1b5a 100644 --- a/src/lib/cast.ts +++ b/src/lib/cast.ts @@ -54,7 +54,7 @@ export async function sendToSession(sessionId: string, itemId: string): Promise< if (!api) throw new Error('Not authenticated') await getSessionApi(api).play({ sessionId, - playCommand: 'PlayNow' as any, + playCommand: 'PlayNow' as const, itemIds: [itemId], }) } diff --git a/src/lib/downloads.ts b/src/lib/downloads.ts index f161bd9..570da87 100644 --- a/src/lib/downloads.ts +++ b/src/lib/downloads.ts @@ -49,7 +49,7 @@ export async function startDownload(args: { } } - const blob = new Blob(chunks as any) + const blob = new Blob(chunks) const objectUrl = URL.createObjectURL(blob) store.update(dl.id, { status: 'done', diff --git a/src/lib/episode-meta.ts b/src/lib/episode-meta.ts index bafc5c0..a6fdc56 100644 --- a/src/lib/episode-meta.ts +++ b/src/lib/episode-meta.ts @@ -43,9 +43,9 @@ export function deriveEpisodeMeta( // against the main ensemble happens at the consuming component. const guests = (credits?.cast || []).slice(0, 8) const crew = credits?.crew || [] - const director = crew.find(c => (c as any).job === 'Director') || null + const director = crew.find(c => c.job === 'Director') || null const writer = crew.find( - c => (c as any).job === 'Writer' || (c as any).job === 'Screenplay', + c => c.job === 'Writer' || c.job === 'Screenplay', ) || null return { diff --git a/src/lib/item-types.ts b/src/lib/item-types.ts index ae755f3..fcaaea0 100644 --- a/src/lib/item-types.ts +++ b/src/lib/item-types.ts @@ -1,7 +1,7 @@ /** * Typed accessors for fields the Jellyfin SDK doesn't fully model and for * synthetic fields the app stamps on `BaseItemDto` to bridge TMDB results - * into the `PosterCard` pipeline. Keeps the `as any` casts in one place + * into the `PosterCard` pipeline. Centralizes type-normalization for items entering PosterCard * so call sites can read fields directly with confidence. */ import type { BaseItemDto } from '../api/types' diff --git a/src/lib/stats.ts b/src/lib/stats.ts index 5552544..9aca618 100644 --- a/src/lib/stats.ts +++ b/src/lib/stats.ts @@ -102,7 +102,7 @@ export function topByPersonRole( ): PersonShare[] { const buckets = new Map() for (const it of items) { - const people = ((it as any).People || []) as Array<{ Name?: string | null; Type?: string | null; Role?: string | null }> + const people = (it.People || []) as Array<{ Name?: string | null; Type?: string | null; Role?: string | null }> const seen = new Set() for (const p of people) { if (!p.Name) continue diff --git a/src/lib/trakt.ts b/src/lib/trakt.ts index 8017315..44bb1ae 100644 --- a/src/lib/trakt.ts +++ b/src/lib/trakt.ts @@ -250,7 +250,7 @@ export async function addToTraktWatchlist(item: BaseItemDto): Promise { if (!token) return false const body = await buildScrobbleBody(item, 0) if (!body) return false - const payload = item.Type === 'Movie' ? { movies: [{ ids: (body as any).movie.ids }] } : { shows: [{ ids: (body as any).show.ids }] } + const payload = item.Type === 'Movie' ? { movies: [{ ids: body.movie.ids }] } : { shows: [{ ids: body.show.ids }] } try { const res = await fetch(`${BASE}/sync/watchlist`, { method: 'POST', @@ -269,7 +269,7 @@ export async function removeFromTraktWatchlist(item: BaseItemDto): Promise(null) const activeSourceId = selectedSourceId || sources[0]?.Id || null diff --git a/src/pages/HomePage.tsx b/src/pages/HomePage.tsx index b953833..447c23c 100644 --- a/src/pages/HomePage.tsx +++ b/src/pages/HomePage.tsx @@ -144,7 +144,7 @@ export default function HomePage() { ImageTags: {}, ProviderIds: { Tmdb: String(r.id) }, _tmdbPoster: r.poster_path ? getTmdbImageUrl(r.poster_path, 'w342') : undefined, - } as any as BaseItemDto))} + } as BaseItemDto))} /> ) diff --git a/src/pages/LibraryPage.tsx b/src/pages/LibraryPage.tsx index 11cad7b..869d1a3 100644 --- a/src/pages/LibraryPage.tsx +++ b/src/pages/LibraryPage.tsx @@ -148,8 +148,8 @@ export default function LibraryPage({ type }: Props) { const items = useMemo(() => { return allItems.filter(it => { if (genreFilter && !(it.Genres || []).includes(genreFilter)) return false - if (only4K && resolutionLabel(it as any) !== '4K') return false - if (onlyHdr && !videoRangeLabel(it as any)) return false + if (only4K && resolutionLabel(it) !== '4K') return false + if (onlyHdr && !videoRangeLabel(it)) return false return true }) }, [allItems, genreFilter, only4K, onlyHdr]) diff --git a/src/pages/LiveTvPage.tsx b/src/pages/LiveTvPage.tsx index a726ff9..074f84e 100644 --- a/src/pages/LiveTvPage.tsx +++ b/src/pages/LiveTvPage.tsx @@ -120,7 +120,7 @@ function ChannelsList() { return (
    {channels.map(ch => { - const program = (ch as any).CurrentProgram as { Name?: string; StartDate?: string; EndDate?: string } | undefined + const program = ch.CurrentProgram as { Name?: string; StartDate?: string; EndDate?: string } | undefined const imageTag = ch.ImageTags?.Primary const img = ch.Id && imageTag ? getImageUrl(serverUrl, ch.Id, 'Primary', 128, imageTag) : '' return ( diff --git a/src/pages/PersonPage.tsx b/src/pages/PersonPage.tsx index 59287ac..ec5c68e 100644 --- a/src/pages/PersonPage.tsx +++ b/src/pages/PersonPage.tsx @@ -37,7 +37,7 @@ export default function PersonPage() { if (filter === 'Acting') { merged = merged.filter(c => c._kind === 'cast') } else { - merged = merged.filter(c => c._kind === 'crew' && (c as any).department === filter) + merged = merged.filter(c => c._kind === 'crew' && c.department === filter) } } @@ -260,7 +260,7 @@ export default function PersonPage() { {title}

    - {(c as any).character ? (c as any).character : (c as any).job} + {c.character ? c.character : c.job} {year && ( <> · diff --git a/src/pages/PlayerPage.tsx b/src/pages/PlayerPage.tsx index d80edda..2bad6bb 100644 --- a/src/pages/PlayerPage.tsx +++ b/src/pages/PlayerPage.tsx @@ -247,7 +247,7 @@ export default function PlayerPage() { } = usePlayerChrome(isPaused) const subtitleStreams = item ? getSubtitleStreams(item) : [] - const mediaSourceId = ((item as any)?.MediaSources?.[0]?.Id as string | undefined) || undefined + const mediaSourceId = item?.MediaSources?.[0]?.Id || undefined const { seriesId, @@ -485,7 +485,7 @@ export default function PlayerPage() { // on every meaningful state tick until the native volume actually // matches the pref - that's the only reliable signal. function getNativeVideo(): HTMLVideoElement | null { - const el = (player as any)?.el as HTMLElement | undefined + const el = (player as { el?: HTMLElement } | null)?.el return (el?.querySelector('video') as HTMLVideoElement | null) || null } function applyVolume() { @@ -594,7 +594,7 @@ export default function PlayerPage() { // Fallback: chapters with intro/credits names if (out.length === 0) { - const chapters = ((item as any)?.Chapters || []) as { Name?: string; StartPositionTicks?: number }[] + const chapters = (item?.Chapters || []) as { Name?: string; StartPositionTicks?: number }[] if (chapters.length && duration) { for (let i = 0; i < chapters.length; i++) { const c = chapters[i] @@ -670,7 +670,7 @@ export default function PlayerPage() { } // 2. Browser's native list on the underlying

    @@ -262,12 +262,12 @@ export default function TmdbDetailPage({ tmdbId, kind }: Props) { )} - {kind === 'tv' && (data as any).number_of_seasons > 0 && ( + {kind === 'tv' && data.number_of_seasons > 0 && ( <> - {(data as any).number_of_seasons} season{(data as any).number_of_seasons === 1 ? '' : 's'} + {data.number_of_seasons} season{data.number_of_seasons === 1 ? '' : 's'} )} @@ -287,7 +287,7 @@ export default function TmdbDetailPage({ tmdbId, kind }: Props) { )}
    - + {matchedLocal && (