diff --git a/src/main/index.ts b/src/main/index.ts index a2afcfa..aa3f8f9 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -12,6 +12,9 @@ const isDev = !app.isPackaged // Erlaubt video.play() ohne vorangehende User-Geste (nötig, weil play() in hls.js-Callbacks // aufgerufen wird, die asynchron weit nach dem ursprünglichen Click-Event stattfinden). app.commandLine.appendSwitch('autoplay-policy', 'no-user-gesture-required') +// Explizite Cache-Größe verhindert Chromiums dynamische Größenberechnung, die bei +// wechselndem freiem Speicherplatz zu "Invalid cache (current) size"-Fehlern führt. +app.commandLine.appendSwitch('disk-cache-size', String(500 * 1024 * 1024)) function createWindow(): BrowserWindow { const isLinux = process.platform === 'linux' diff --git a/src/renderer/src/screens/AppShell.tsx b/src/renderer/src/screens/AppShell.tsx index 5fa01fe..c667b4c 100644 --- a/src/renderer/src/screens/AppShell.tsx +++ b/src/renderer/src/screens/AppShell.tsx @@ -14,7 +14,7 @@ import type { FollowedChannelInfo, GameInfo, HlsUrlPayload } from '../types/t4sd type Region = 'sidebar' | 'main' type QuitChoice = 'yes' | 'no' -type GlobalPlayState = 'idle' | 'starting' | 'playing' | 'paused' +type GlobalPlayState = 'idle' | 'starting' | 'playing' | 'paused' | 'error' interface Props { onLogout: () => void @@ -42,6 +42,7 @@ export default function AppShell({ onLogout }: Props): JSX.Element { const [liveCurrentQuality, setLiveCurrentQuality] = useState('best') const [liveQualityPanelOpen, setLiveQualityPanelOpen] = useState(false) const [liveQualityFocusedIndex, setLiveQualityFocusedIndex] = useState(0) + const [liveErrorMsg, setLiveErrorMsg] = useState('') const isGlobalPlaying = livePlayState !== 'idle' @@ -56,7 +57,7 @@ export default function AppShell({ onLogout }: Props): JSX.Element { if (!isGlobalPlaybackInitiated.current) return if (ev.kind === 'started') { setLivePlayState('playing') - } else if (ev.kind === 'stopped' || ev.kind === 'error') { + } else if (ev.kind === 'stopped') { isGlobalPlaybackInitiated.current = false setLiveHlsPayload(null) setLivePlayState('idle') @@ -65,6 +66,14 @@ export default function AppShell({ onLogout }: Props): JSX.Element { setLiveAvailableQualities(undefined) setLiveCurrentQuality('best') setLiveQualityPanelOpen(false) + setLiveErrorMsg('') + } else if (ev.kind === 'error') { + isGlobalPlaybackInitiated.current = false + setLiveHlsPayload(null) + setLivePlayState('error') + setLiveErrorMsg(ev.message ?? 'Stream konnte nicht gestartet werden.') + setLiveAvailableQualities(undefined) + setLiveQualityPanelOpen(false) } }) return () => { unsubHls(); unsubEvent() } @@ -106,6 +115,7 @@ export default function AppShell({ onLogout }: Props): JSX.Element { setLiveAvailableQualities(undefined) setLiveCurrentQuality('best') setLiveQualityPanelOpen(false) + setLiveErrorMsg('') void window.t4sd.playback.startLive(ch.broadcasterLogin).then(() => { window.t4sd.playback.getQualities(`twitch.tv/${ch.broadcasterLogin}`) .then((qs) => setLiveAvailableQualities(qs.length > 0 ? qs : [])) @@ -114,10 +124,15 @@ export default function AppShell({ onLogout }: Props): JSX.Element { }, []) const handleStopLive = useCallback(() => { + isGlobalPlaybackInitiated.current = false liveVideoRef.current?.stop() + setLiveHlsPayload(null) + setLivePlayState('idle') + setLiveChannel(null) setLiveAvailableQualities(undefined) setLiveCurrentQuality('best') setLiveQualityPanelOpen(false) + setLiveErrorMsg('') void window.t4sd.playback.stop() }, []) @@ -352,6 +367,21 @@ export default function AppShell({ onLogout }: Props): JSX.Element { Starte Wiedergabe… )} + {/* Fehler-Overlay */} + {livePlayState === 'error' && ( +
+ {liveErrorMsg} +
++ B / Esc — Schließen +
+