build fixes - type errors, missing icons, tauri externals, unused imports

This commit is contained in:
2026-04-03 08:48:28 +03:00
parent b43aef0f73
commit a8349c3f18
11 changed files with 51 additions and 39 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
import { useMemo } from 'react'
import { useLibraryGenreDistribution, useLibraryByTmdbId } from '../../hooks/use-jellyfin'
import { useTmdbDiscoverMovies, useTmdbTopRatedMovies } from '../../hooks/use-tmdb'
import { useTmdbDiscoverMovies } from '../../hooks/use-tmdb'
import { usePreferencesStore } from '../../stores/preferences-store'
import { mapTmdbToJf } from '../../lib/tmdb-mapping'
import { tmdbMovieGenreId } from '../../lib/tmdb-genres'
+5 -5
View File
@@ -58,14 +58,14 @@ 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') {
return { supported: null, hwAccelerated: null }
}
const codec = (stream.codec || stream.Codec || '').toLowerCase()
const w = stream.width ?? stream.Width ?? 1920
const h = stream.height ?? stream.Height ?? 1080
const br = stream.bitrate ?? stream.BitRate ?? 8000000
const codec = (stream.Codec || '').toLowerCase()
const w = stream.Width ?? 1920
const h = stream.Height ?? 1080
const br = stream.BitRate ?? 8000000
// Map common Jellyfin codec names to MIME codec strings
const mimeCodec =
codec === 'h264' ? 'avc1.640033'
+6 -3
View File
@@ -11,18 +11,21 @@ import { toast } from '../stores/toast-store'
*/
export function useNewReleaseNotifications(enabled: boolean) {
const qc = useQueryClient()
const lastNotifiedRef = useRef<string | null>(() => {
const lastNotifiedRef = useRef<string | null>(
(() => {
try { return localStorage.getItem('jf_last_notify_date') } catch { return null }
}())
})()
)
useEffect(() => {
if (!enabled) return
const api = jellyfinClient.getApi()
if (!api) return
const apiRef = api
async function check() {
try {
const res = await getItemsApi(api).getItems({
const res = await getItemsApi(apiRef).getItems({
userId: jellyfinClient.getAuthState()!.userId,
sortBy: ['DateCreated'],
sortOrder: ['Descending'],
+9 -6
View File
@@ -31,15 +31,18 @@ export async function startDownload(args: {
// Tauri path: fetch via the Rust-backed HTTP client so we avoid
// CORS + we can stream large files without the browser's memory
// pressure.
const { fetch } = await import('@tauri-apps/api/http')
const { appLocalDataDir } = await import('@tauri-apps/api/path')
const { writeBinaryFile, BaseDirectory } = await import('@tauri-apps/api/fs')
// @ts-ignore
const { fetch } = await import('@tauri-apps/api/http') as any
// @ts-ignore
const { appLocalDataDir } = await import('@tauri-apps/api/path') as any
// @ts-ignore
const { writeBinaryFile, BaseDirectory } = await import('@tauri-apps/api/fs') as any
const res = await fetch<Uint8Array>(streamUrl, {
const res = await (fetch as any)(streamUrl, {
method: 'GET',
responseType: 3, // ResponseType.Binary
})
const bytes = res.data
const bytes: Uint8Array = res.data
const dir = await appLocalDataDir()
const fileName = `download_${itemId}_${Date.now()}.mp4`
await writeBinaryFile(fileName, bytes, { dir: BaseDirectory.AppLocalData })
@@ -77,7 +80,7 @@ export async function startDownload(args: {
}
// Assemble the full blob
const blob = new Blob(chunks)
const blob = new Blob(chunks as any)
const objectUrl = URL.createObjectURL(blob)
store.update(dl.id, {
status: 'done',
+2
View File
@@ -79,6 +79,7 @@ export {
IconBuilding as Building2,
IconTicket as Ticket,
IconAlertCircle as AlertCircle,
IconBell as Bell,
IconLoader2 as Loader2,
IconWifiOff as WifiOff,
IconInfoCircle as Info,
@@ -140,6 +141,7 @@ export {
IconStethoscope as Stethoscope,
IconLeaf as Leaf,
IconMoonStars as MoonStars,
IconMoon as Moon,
IconPlane as Plane,
// People / places
-2
View File
@@ -3,12 +3,10 @@ import { useNavigate } from 'react-router-dom'
import { motion } from 'framer-motion'
import { Film, Tv, AlertCircle } from '../lib/icons'
import { useLibraryItems } from '../hooks/use-jellyfin'
import { getBestImage, getStoredServerUrl } from '../api/jellyfin'
import PosterCard from '../components/ui/PosterCard'
export default function DuplicatesPage() {
const navigate = useNavigate()
const serverUrl = getStoredServerUrl()
const { data, isLoading } = useLibraryItems(undefined, {
includeItemTypes: ['Movie', 'Series'],
sortBy: ['SortName'],
+2 -1
View File
@@ -191,6 +191,7 @@ export default function PlayerPage() {
const stillWatchingTargetRef = useRef<string | null>(null)
/* Preferences */
const sleepTimerMinutes = usePreferencesStore(s => s.sleepTimerMinutes)
const autoplayNext = usePreferencesStore(s => s.autoplayNext)
const subtitleMode = usePreferencesStore(s => s.subtitleMode)
const subtitleLanguage = usePreferencesStore(s => s.subtitleLanguage)
@@ -1520,7 +1521,7 @@ export default function PlayerPage() {
streamUrl,
})
}}
isDownloaded={!!item && useDownloads.getState().items.some(d => d.itemId === item.Id)},
isDownloaded={!!item && useDownloads.getState().items.some(d => d.itemId === item.Id)}
/>
{/* Center play/pause indicator (only shown briefly when paused) */}
@@ -1,9 +1,9 @@
import { useMemo } from 'react'
import { useQuery } from '@tanstack/react-query'
import { motion } from 'framer-motion'
import { Activity, Monitor, Users, Server as ServerIcon, Clock, Film } from '../../../lib/icons'
import { Activity, MonitorPlay, Users, Server as ServerIcon, Clock, Film } from '../../../lib/icons'
import { jellyfinClient, getSystemApi, getSessionApi, getActivityLogApi } from '../../../api/jellyfin'
import { Section, Row, SubHeading } from '../_ui'
import { Section, SubHeading } from '../_ui'
function useApi() {
return jellyfinClient.getApi()
@@ -49,12 +49,13 @@ export function ServerDashboardSection() {
const transcodes = activeSessions.filter(s => s.PlayState?.PlayMethod === 'Transcode')
const uptime = useMemo(() => {
if (!info?.ServerStartTime) return null
const ms = Date.now() - new Date(info.ServerStartTime).getTime()
const start = (info as any)?.ServerStartTime
if (!start) return null
const ms = Date.now() - new Date(start).getTime()
const days = Math.floor(ms / 86_400_000)
const hrs = Math.floor((ms % 86_400_000) / 3_600_000)
return days > 0 ? `${days}d ${hrs}h` : `${hrs}h`
}, [info?.ServerStartTime])
}, [info])
return (
<Section id="server-dashboard" title="Server dashboard" description="Live stats and activity">
@@ -62,7 +63,7 @@ export function ServerDashboardSection() {
<div className="grid grid-cols-2 md:grid-cols-4 gap-3 mb-6">
<StatCard label="Version" value={info?.Version || '-'} icon={<ServerIcon size={12} className="text-accent" />} />
<StatCard label="Uptime" value={uptime || '-'} icon={<Clock size={12} className="text-accent" />} />
<StatCard label="Active streams" value={String(activeSessions.length)} icon={<Monitor size={12} className="text-accent" />} />
<StatCard label="Active streams" value={String(activeSessions.length)} icon={<MonitorPlay size={12} className="text-accent" />} />
<StatCard label="Transcoding" value={String(transcodes.length)} icon={<Activity size={12} className="text-accent" />} />
</div>
+1 -1
View File
@@ -3,7 +3,7 @@ import { ExternalLink, Loader2, Check, Trash2 } from '../../../lib/icons'
import { Section, Row, Input, Toggle } from '../_ui'
import { useTrakt } from '../../../stores/trakt-store'
import { useWatchlist } from '../../../hooks/use-watchlist'
import { requestDeviceCode, pollDeviceToken, fetchTraktWatchlist, addToTraktWatchlist } from '../../../lib/trakt'
import { requestDeviceCode, pollDeviceToken, fetchTraktWatchlist } from '../../../lib/trakt'
import { toast } from '../../../stores/toast-store'
import { useLibraryByTmdbId } from '../../../hooks/use-jellyfin'
+7 -6
View File
@@ -20,7 +20,7 @@ export interface DownloadItem {
interface State {
items: DownloadItem[]
add: (item: Omit<DownloadItem, 'id' | 'status' | 'progress' | 'createdAt'>) => void
add: (item: Omit<DownloadItem, 'id' | 'status' | 'progress' | 'createdAt'>) => DownloadItem
update: (id: string, patch: Partial<DownloadItem>) => void
remove: (id: string) => void
clearCompleted: () => void
@@ -35,9 +35,9 @@ export const useDownloads = create<State>()(
persist(
(set, get) => ({
items: [],
add: item =>
set(s => {
if (s.items.some(i => i.itemId === item.itemId && i.status !== 'error')) return s
add: item => {
const existing = get().items.find(i => i.itemId === item.itemId && i.status !== 'error')
if (existing) return existing
const next: DownloadItem = {
...item,
id: uid(),
@@ -45,8 +45,9 @@ export const useDownloads = create<State>()(
progress: 0,
createdAt: new Date().toISOString(),
}
return { items: [...s.items, next] }
}),
set(s => ({ items: [...s.items, next] }))
return next
},
update: (id, patch) =>
set(s => ({
items: s.items.map(i => (i.id === id ? { ...i, ...patch } : i)),
+3
View File
@@ -6,5 +6,8 @@ export default defineConfig({
plugins: [react(), tailwindcss()],
build: {
chunkSizeWarningLimit: 900,
rollupOptions: {
external: [/^@tauri-apps\/.*/],
},
},
})