fix four audit bugs - offline playback, audio passthrough, notification dedup, dashboard fixes

This commit is contained in:
2026-04-06 04:33:21 +03:00
parent 0af7ba64cb
commit 1a84b348ad
5 changed files with 19 additions and 40 deletions
+7
View File
@@ -291,6 +291,12 @@ export default function PlayerPage() {
// native audioTracks switch isn't possible (transcoded streams, or
// single-audio sources where the alternate track isn't in the file).
// maxBitrate threads the user-picked quality cap into the same call.
// Offline fallback: if this item was downloaded, use the Blob URL
// instead of hitting the server. PlaybackInfo and reporting gracefully
// no-op when there's no connection.
const downloaded = useDownloads(s => s.getByItemId(id || ''))
const offlineUrl = downloaded?.status === 'done' ? downloaded.localPath : undefined
const { data: playbackInfo } = usePlaybackInfo(
id,
startTimeTicks,
@@ -299,6 +305,7 @@ export default function PlayerPage() {
)
const resolvedSource = playbackInfo?.MediaSources?.[0]
const streamUrl = (() => {
if (offlineUrl) return offlineUrl
if (!resolvedSource || !serverUrl) return ''
// Direct play: server-confirmed the browser can decode the source as-is
if (resolvedSource.SupportsDirectPlay) {
@@ -1,8 +1,8 @@
import { useMemo } from 'react'
import { useQuery } from '@tanstack/react-query'
import { motion } from 'framer-motion'
import { Activity, MonitorPlay, Users, Server as ServerIcon, Clock, Film } from '../../../lib/icons'
import { jellyfinClient, getSystemApi, getSessionApi, getActivityLogApi } from '../../../api/jellyfin'
import { Activity, MonitorPlay, Users, Server as ServerIcon, Clock } from '../../../lib/icons'
import { jellyfinClient, getSystemApi, getSessionApi } from '../../../api/jellyfin'
import { Section, SubHeading } from '../_ui'
function useApi() {
@@ -33,17 +33,6 @@ export function ServerDashboardSection() {
refetchInterval: 10_000,
})
const activity = useQuery({
queryKey: ['jellyfin', 'activity-log'],
queryFn: async () => {
if (!api) return []
const res = await getActivityLogApi(api).getLogEntries({ limit: 20 })
return res.data.Items || []
},
enabled: !!api,
refetchInterval: 60_000,
})
const info = serverInfo.data
const activeSessions = sessions.data?.filter(s => s.NowPlayingItem) || []
const transcodes = activeSessions.filter(s => s.PlayState?.PlayMethod === 'Transcode')
@@ -107,28 +96,7 @@ export function ServerDashboardSection() {
</>
)}
{activity.data && activity.data.length > 0 && (
<>
<SubHeading label="Recent activity" />
<div className="space-y-1">
{activity.data.slice(0, 10).map((entry: any, i: number) => (
<motion.div
key={entry.Id || i}
initial={{ opacity: 0, x: -6 }}
animate={{ opacity: 1, x: 0 }}
transition={{ delay: Math.min(i * 0.03, 0.3) }}
className="flex items-center gap-3 px-2 py-1.5 text-[11.5px]"
>
<Film size={11} className="text-text-4 shrink-0" />
<span className="text-text-3 truncate flex-1">{entry.Name}</span>
<span className="text-text-4 tabular-nums shrink-0">
{entry.DateCreated ? new Date(entry.DateCreated).toLocaleTimeString(undefined, { hour: 'numeric', minute: '2-digit' }) : ''}
</span>
</motion.div>
))}
</div>
</>
)}
</Section>
)
}