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