mirror of
https://github.com/Andre-Bzk/twitch4steamdeck.git
synced 2026-11-15 15:43:08 +01:00
Fix für Resume und R2-Seeking bei fMP4-VODs auf dem Steam Deck
- ffmpeg-full im Flatpak eingebunden für vollständiges H.264/VAAPI-Decoding - Trigger-Repeat für L2/R2 deaktiviert, um gestapelte 300s-Seeks zu vermeiden - fMP4-HLS-Playlists über EXT-X-MAP erkannt - große fMP4-Seeks nicht mehr per In-Stream-Seek, sondern per Reload einer getrimmten Playlist - getrimmte Playlists über localhost statt file:// ausgeliefert - absoluten Playback-Offset eingeführt, damit mehrfaches R2 korrekt weiter vorspult - B Button ermöglicht, mit der selektierung zurück zum sidemenu zurückzukehren - Logging Schalter dem Einstellungs Screen hinzugefügt
This commit is contained in:
@@ -6,6 +6,7 @@ export interface AppSettings {
|
||||
streamBadgeMode: StreamBadgeMode
|
||||
sidebarWidth: number
|
||||
badgeGap: number
|
||||
mpvLoggingEnabled: boolean
|
||||
}
|
||||
|
||||
const STORAGE_KEY = 't4sd:settings'
|
||||
@@ -18,7 +19,8 @@ const BADGE_GAP_DEFAULT = 6
|
||||
const DEFAULTS: AppSettings = {
|
||||
streamBadgeMode: 'language',
|
||||
sidebarWidth: SIDEBAR_DEFAULT,
|
||||
badgeGap: BADGE_GAP_DEFAULT
|
||||
badgeGap: BADGE_GAP_DEFAULT,
|
||||
mpvLoggingEnabled: true
|
||||
}
|
||||
|
||||
export { SIDEBAR_MIN, SIDEBAR_MAX, SIDEBAR_DEFAULT, BADGE_GAP_MIN, BADGE_GAP_MAX, BADGE_GAP_DEFAULT }
|
||||
@@ -36,7 +38,10 @@ function loadSettings(): AppSettings {
|
||||
? (parsed.streamBadgeMode as StreamBadgeMode)
|
||||
: DEFAULTS.streamBadgeMode,
|
||||
sidebarWidth: sw >= SIDEBAR_MIN && sw <= SIDEBAR_MAX ? sw : SIDEBAR_DEFAULT,
|
||||
badgeGap: bg >= BADGE_GAP_MIN && bg <= BADGE_GAP_MAX ? bg : BADGE_GAP_DEFAULT
|
||||
badgeGap: bg >= BADGE_GAP_MIN && bg <= BADGE_GAP_MAX ? bg : BADGE_GAP_DEFAULT,
|
||||
mpvLoggingEnabled: typeof parsed.mpvLoggingEnabled === 'boolean'
|
||||
? parsed.mpvLoggingEnabled
|
||||
: DEFAULTS.mpvLoggingEnabled
|
||||
}
|
||||
} catch {
|
||||
return DEFAULTS
|
||||
@@ -56,6 +61,7 @@ interface SettingsCtx {
|
||||
setStreamBadgeMode: (mode: StreamBadgeMode) => void
|
||||
setSidebarWidth: (width: number) => void
|
||||
setBadgeGap: (gap: number) => void
|
||||
setMpvLoggingEnabled: (enabled: boolean) => void
|
||||
}
|
||||
|
||||
const SettingsContext = createContext<SettingsCtx | null>(null)
|
||||
@@ -68,6 +74,10 @@ export function SettingsProvider({ children }: { children: React.ReactNode }): J
|
||||
document.documentElement.style.setProperty('--badge-gap', `${settings.badgeGap}px`)
|
||||
}, []) // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
useEffect(() => {
|
||||
void window.t4sd.playback.setLoggingEnabled(settings.mpvLoggingEnabled)
|
||||
}, [settings.mpvLoggingEnabled])
|
||||
|
||||
const setStreamBadgeMode = useCallback((mode: StreamBadgeMode) => {
|
||||
setSettings((prev) => {
|
||||
const next = { ...prev, streamBadgeMode: mode }
|
||||
@@ -96,8 +106,16 @@ export function SettingsProvider({ children }: { children: React.ReactNode }): J
|
||||
document.documentElement.style.setProperty('--badge-gap', `${clamped}px`)
|
||||
}, [])
|
||||
|
||||
const setMpvLoggingEnabled = useCallback((enabled: boolean) => {
|
||||
setSettings((prev) => {
|
||||
const next = { ...prev, mpvLoggingEnabled: enabled }
|
||||
saveSettings(next)
|
||||
return next
|
||||
})
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<SettingsContext.Provider value={{ settings, setStreamBadgeMode, setSidebarWidth, setBadgeGap }}>
|
||||
<SettingsContext.Provider value={{ settings, setStreamBadgeMode, setSidebarWidth, setBadgeGap, setMpvLoggingEnabled }}>
|
||||
{children}
|
||||
</SettingsContext.Provider>
|
||||
)
|
||||
|
||||
@@ -32,21 +32,31 @@ const OPTIONS: Option[] = [
|
||||
const SIDEBAR_STEP = 10
|
||||
const BADGE_GAP_STEP = 2
|
||||
|
||||
/** Total focusable rows: badge options + sidebar slider + badge gap slider */
|
||||
/** Total focusable rows: badge options + sidebar slider + badge gap slider + logging toggle */
|
||||
const SIDEBAR_SLIDER_ROW = OPTIONS.length
|
||||
const BADGE_GAP_SLIDER_ROW = OPTIONS.length + 1
|
||||
const TOTAL_ROWS = OPTIONS.length + 2
|
||||
const LOGGING_TOGGLE_ROW = OPTIONS.length + 2
|
||||
const TOTAL_ROWS = OPTIONS.length + 3
|
||||
|
||||
export default function SettingsScreen({ hasFocus, onRequestSidebar }: Props): JSX.Element {
|
||||
const { settings, setStreamBadgeMode, setSidebarWidth, setBadgeGap } = useSettings()
|
||||
const { settings, setStreamBadgeMode, setSidebarWidth, setBadgeGap, setMpvLoggingEnabled } = useSettings()
|
||||
const [logPath, setLogPath] = useState('/home/deck/.var/app/tv.twitch4steamdeck.App/config/Electron/mpv.log')
|
||||
const [focusedIndex, setFocusedIndex] = useState(() =>
|
||||
Math.max(0, OPTIONS.findIndex((o) => o.mode === settings.streamBadgeMode))
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
void window.t4sd.playback.getLogPath().then(setLogPath).catch(() => {})
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (!hasFocus) return
|
||||
const onKey = (e: KeyboardEvent): void => {
|
||||
switch (e.key) {
|
||||
case 'Escape':
|
||||
e.preventDefault()
|
||||
onRequestSidebar()
|
||||
break
|
||||
case 'ArrowUp':
|
||||
e.preventDefault()
|
||||
setFocusedIndex((i) => Math.max(0, i - 1))
|
||||
@@ -83,6 +93,8 @@ export default function SettingsScreen({ hasFocus, onRequestSidebar }: Props): J
|
||||
setSidebarWidth(SIDEBAR_DEFAULT)
|
||||
} else if (focusedIndex === BADGE_GAP_SLIDER_ROW) {
|
||||
setBadgeGap(BADGE_GAP_DEFAULT)
|
||||
} else if (focusedIndex === LOGGING_TOGGLE_ROW) {
|
||||
setMpvLoggingEnabled(!settings.mpvLoggingEnabled)
|
||||
}
|
||||
break
|
||||
}
|
||||
@@ -90,7 +102,7 @@ export default function SettingsScreen({ hasFocus, onRequestSidebar }: Props): J
|
||||
}
|
||||
window.addEventListener('keydown', onKey)
|
||||
return () => window.removeEventListener('keydown', onKey)
|
||||
}, [hasFocus, focusedIndex, settings.sidebarWidth, settings.badgeGap, onRequestSidebar, setStreamBadgeMode, setSidebarWidth, setBadgeGap])
|
||||
}, [hasFocus, focusedIndex, settings.sidebarWidth, settings.badgeGap, settings.mpvLoggingEnabled, onRequestSidebar, setStreamBadgeMode, setSidebarWidth, setBadgeGap, setMpvLoggingEnabled])
|
||||
|
||||
const rowRefs = useRef<Array<HTMLElement | null>>([])
|
||||
|
||||
@@ -102,6 +114,7 @@ export default function SettingsScreen({ hasFocus, onRequestSidebar }: Props): J
|
||||
|
||||
const sidebarSliderFocused = hasFocus && focusedIndex === SIDEBAR_SLIDER_ROW
|
||||
const badgeGapSliderFocused = hasFocus && focusedIndex === BADGE_GAP_SLIDER_ROW
|
||||
const loggingToggleFocused = hasFocus && focusedIndex === LOGGING_TOGGLE_ROW
|
||||
|
||||
return (
|
||||
<div className="screen settings-screen">
|
||||
@@ -205,6 +218,38 @@ export default function SettingsScreen({ hasFocus, onRequestSidebar }: Props): J
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="settings-section">
|
||||
<h3 className="settings-section__title">mpv-Logging</h3>
|
||||
<p className="settings-section__hint">
|
||||
Aktiviert oder deaktiviert die mpv-Logdatei für Diagnosezwecke.
|
||||
Logpfad auf dem Steam Deck: <code>{logPath}</code>
|
||||
</p>
|
||||
|
||||
<button
|
||||
ref={(el) => { rowRefs.current[LOGGING_TOGGLE_ROW] = el }}
|
||||
className={[
|
||||
'settings-option',
|
||||
settings.mpvLoggingEnabled ? 'settings-option--active' : '',
|
||||
loggingToggleFocused ? 'settings-option--focused' : ''
|
||||
].filter(Boolean).join(' ')}
|
||||
onClick={() => {
|
||||
setFocusedIndex(LOGGING_TOGGLE_ROW)
|
||||
setMpvLoggingEnabled(!settings.mpvLoggingEnabled)
|
||||
}}
|
||||
tabIndex={loggingToggleFocused ? 0 : -1}
|
||||
>
|
||||
<span className="settings-option__radio" aria-hidden="true">
|
||||
{settings.mpvLoggingEnabled ? '●' : '○'}
|
||||
</span>
|
||||
<span className="settings-option__label">
|
||||
{settings.mpvLoggingEnabled ? 'Logging aktiviert' : 'Logging deaktiviert'}
|
||||
</span>
|
||||
<span className="settings-option__preview">
|
||||
{settings.mpvLoggingEnabled ? 'mpv schreibt in mpv.log' : 'keine neue mpv.log wird geschrieben'}
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{!hasFocus && (
|
||||
<div className="screen__state" style={{ flex: 0 }}>
|
||||
<SettingsIcon style={{ width: 48, height: 48, opacity: 0.2 }} />
|
||||
|
||||
Vendored
+2
@@ -100,6 +100,8 @@ export interface T4sdApi {
|
||||
resume: () => Promise<void>
|
||||
seekTo: (seconds: number) => Promise<void>
|
||||
getCurrentPosition: () => Promise<number | null>
|
||||
setLoggingEnabled: (enabled: boolean) => Promise<void>
|
||||
getLogPath: () => Promise<string>
|
||||
onEvent: (cb: (event: PlaybackEvent) => void) => () => void
|
||||
}
|
||||
gamepad: {
|
||||
|
||||
Reference in New Issue
Block a user