type player and layout

This commit is contained in:
2026-04-27 02:34:08 +03:00
parent 9641dfc1a9
commit 192cb92c1e
6 changed files with 15 additions and 15 deletions
+4 -4
View File
@@ -88,7 +88,7 @@ export default function AppHeader({ pinned, onTogglePin }: Props) {
recursive: true, recursive: true,
includeItemTypes: ['Movie'], includeItemTypes: ['Movie'],
fields: ['DateCreated', 'PrimaryImageAspectRatio', 'ImageTags'], fields: ['DateCreated', 'PrimaryImageAspectRatio', 'ImageTags'],
} as any), }),
getItemsApi(api!).getItems({ getItemsApi(api!).getItems({
userId: auth.userId, userId: auth.userId,
sortBy: ['DateCreated'], sortBy: ['DateCreated'],
@@ -97,10 +97,10 @@ export default function AppHeader({ pinned, onTogglePin }: Props) {
recursive: true, recursive: true,
includeItemTypes: ['Episode'], includeItemTypes: ['Episode'],
fields: ['DateCreated', 'PrimaryImageAspectRatio', 'ImageTags', 'SeriesName', 'SeriesId', 'SeriesPrimaryImageTag', 'ParentIndexNumber', 'IndexNumber'], fields: ['DateCreated', 'PrimaryImageAspectRatio', 'ImageTags', 'SeriesName', 'SeriesId', 'SeriesPrimaryImageTag', 'ParentIndexNumber', 'IndexNumber'],
} as any), }),
]) ])
const movies = (movieRes.data.Items || []) as any[] const movies = movieRes.data.Items || []
const episodes = (episodeRes.data.Items || []) as any[] const episodes = episodeRes.data.Items || []
// Deduplicate episodes by series -- keep only the newest per show // Deduplicate episodes by series -- keep only the newest per show
const seenSeries = new Set<string>() const seenSeries = new Set<string>()
const dedupedEpisodes: any[] = [] const dedupedEpisodes: any[] = []
+1 -1
View File
@@ -41,7 +41,7 @@ export default function Titlebar() {
<div <div
data-tauri-drag-region data-tauri-drag-region
className="app-titlebar shrink-0 h-9 flex items-center justify-between bg-void/95 border-b border-border select-none" className="app-titlebar shrink-0 h-9 flex items-center justify-between bg-void/95 border-b border-border select-none"
style={{ ['WebkitUserSelect' as any]: 'none' }} style={{ WebkitUserSelect: 'none' }}
> >
<div data-tauri-drag-region className="flex items-center gap-2 pl-3"> <div data-tauri-drag-region className="flex items-center gap-2 pl-3">
<span <span
+2 -2
View File
@@ -279,8 +279,8 @@ function RowStrip({ title, items }: { title: string; items: BaseItemDto[] }) {
</p> </p>
<div className="flex gap-2 overflow-x-auto hide-scrollbar -mx-1 px-1 pb-1.5"> <div className="flex gap-2 overflow-x-auto hide-scrollbar -mx-1 px-1 pb-1.5">
{items.map(it => { {items.map(it => {
const tmdbPoster = (it as any)._tmdbPoster as string | undefined const tmdbPoster = it._tmdbPoster
const inLibrary = (it as any)._inLibrary === true const inLibrary = it._inLibrary === true
const poster = const poster =
tmdbPoster || tmdbPoster ||
(it.ImageTags?.Primary && it.Id (it.ImageTags?.Primary && it.Id
+1 -1
View File
@@ -141,7 +141,7 @@ export default function EpisodesPanel({
{/* Panel */} {/* Panel */}
<motion.aside <motion.aside
ref={panelRef as any} ref={panelRef as React.RefObject<HTMLDivElement>}
initial={{ x: '100%' }} initial={{ x: '100%' }}
animate={{ x: 0 }} animate={{ x: 0 }}
exit={{ x: '100%' }} exit={{ x: '100%' }}
+3 -3
View File
@@ -38,7 +38,7 @@ export default function LibAssRenderer({ playerRef, subtitleUrl }: Props) {
function getVideo(): HTMLVideoElement | null { function getVideo(): HTMLVideoElement | null {
const player = playerRef.current const player = playerRef.current
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 return (el?.querySelector('video') as HTMLVideoElement | null) || null
} }
@@ -50,8 +50,8 @@ export default function LibAssRenderer({ playerRef, subtitleUrl }: Props) {
// SubtitlesOctopus is exposed as a global by the dist bundle. We // SubtitlesOctopus is exposed as a global by the dist bundle. We
// dynamic-import the npm package so the wasm worker isn't pulled // dynamic-import the npm package so the wasm worker isn't pulled
// into the main bundle for users who never see ASS subs. // into the main bundle for users who never see ASS subs.
const mod: any = await import('libass-wasm') const mod = await import('libass-wasm') as { default?: unknown; SubtitlesOctopus?: unknown }
const SubtitlesOctopus = mod.default || mod.SubtitlesOctopus || (window as any).SubtitlesOctopus const SubtitlesOctopus = (mod.default || mod.SubtitlesOctopus || window.SubtitlesOctopus) as new (opts: Record<string, unknown>) => { dispose(): void }
if (!SubtitlesOctopus || cancelled) return if (!SubtitlesOctopus || cancelled) return
if (octopusRef.current) { if (octopusRef.current) {
try { octopusRef.current.dispose() } catch { /* noop */ } try { octopusRef.current.dispose() } catch { /* noop */ }
+4 -4
View File
@@ -49,7 +49,7 @@ function readLiveStats(): LiveStats {
} }
} }
} catch { /* timeranges throws sometimes */ } } catch { /* timeranges throws sometimes */ }
const q = (video as any).getVideoPlaybackQuality?.() const q = video.getVideoPlaybackQuality?.()
return { return {
bufferAheadSec: bufferAhead, bufferAheadSec: bufferAhead,
droppedFrames: q?.droppedVideoFrames ?? null, droppedFrames: q?.droppedVideoFrames ?? null,
@@ -59,7 +59,7 @@ function readLiveStats(): LiveStats {
} }
async function checkHwDecode(stream: { Codec?: string | null; Width?: number | null; Height?: number | null; BitRate?: number | null } | null): Promise<HwDecodeState> { async function checkHwDecode(stream: { Codec?: string | null; Width?: number | null; Height?: number | null; BitRate?: number | null } | null): Promise<HwDecodeState> {
if (!stream || typeof (navigator as any).mediaCapabilities?.decodingInfo !== 'function') { if (!stream || typeof navigator.mediaCapabilities?.decodingInfo !== 'function') {
return { supported: null, hwAccelerated: null } return { supported: null, hwAccelerated: null }
} }
const codec = (stream.Codec || '').toLowerCase() const codec = (stream.Codec || '').toLowerCase()
@@ -75,7 +75,7 @@ async function checkHwDecode(stream: { Codec?: string | null; Width?: number | n
: null : null
if (!mimeCodec) return { supported: null, hwAccelerated: null } if (!mimeCodec) return { supported: null, hwAccelerated: null }
try { try {
const info = await (navigator as any).mediaCapabilities.decodingInfo({ const info = await navigator.mediaCapabilities!.decodingInfo({
type: 'media-source', type: 'media-source',
video: { video: {
contentType: `video/mp4; codecs="${mimeCodec}"`, contentType: `video/mp4; codecs="${mimeCodec}"`,
@@ -163,7 +163,7 @@ export default function StreamInfo({ item, visible, playMethod }: Props) {
useEffect(() => { useEffect(() => {
if (!visible) return if (!visible) return
const v = getVideoStream(item || {}) const v = getVideoStream(item || {})
checkHwDecode(v as any).then(setHw) checkHwDecode(v).then(setHw)
}, [visible, item?.Id]) }, [visible, item?.Id])
if (!visible || !item) return null if (!visible || !item) return null