show resume prompt for ?resume=true and reset on item change

This commit is contained in:
2026-06-06 22:46:56 +03:00
parent 644f888995
commit 649a3da510
+16 -39
View File
@@ -361,35 +361,21 @@ export default function PlayerPage() {
transcodingUrlHasRuntimeTicks: hasRuntimeTicks,
streamUrl: streamUrl.replace(/api_key=[^&]+/, 'api_key=***'),
})
if (transcodingUrl && !hasRuntimeTicks) {
const fullUrl = `${serverUrl}${transcodingUrl}`
fetch(fullUrl, { headers: { Authorization: `MediaBrowser Token=${token}` } })
.then(r => r.text())
.then(text => {
const lines = text.split(/\r?\n/)
const variantLine = lines.find(l => l.endsWith('.m3u8') && !l.startsWith('#'))
console.log('[player] hls master playlist', text)
if (variantLine) {
const variantUrl = variantLine.startsWith('http')
? variantLine
: new URL(variantLine, fullUrl).toString()
return fetch(variantUrl, { headers: { Authorization: `MediaBrowser Token=${token}` } }).then(r => r.text())
}
return null
})
.then(variantText => {
if (!variantText) return
const lines = variantText.split(/\r?\n/)
const segmentLines = lines.filter(l => /\.(ts|m4s|mp4)(\?|$)/.test(l))
console.log('[player] hls variant playlist (first 20 lines)', lines.slice(0, 20))
console.log('[player] hls variant first 6 segment lines', segmentLines.slice(0, 6))
console.log('[player] hls variant segments have runtimeTicks', segmentLines.some(l => l.includes('runtimeTicks=')))
console.log('[player] hls variant segments have StartTimeTicks', segmentLines.some(l => l.includes('StartTimeTicks=')))
})
.catch(e => console.warn('[player] hls playlist fetch failed', e))
}
}
/* Resume prompt: show on first mount when there's a saved position
* past the threshold AND the user wants the prompt. The prompt auto-
* confirms after a few seconds, which queues the deferred seek via
* pendingSeekRef and seeks the underlying HTMLMediaElement directly
* (vidstack's MediaPlayerInstance.currentTime has a known bug on
* direct-play MP4 sources that restarts the video from 0).
* Intentionally scoped to item?.Id only - we only want to evaluate
* the resume condition once per item, not re-trigger when item data
* refreshes or prefs change mid-playback. */
const resumePromptShownRef = useRef<string | null>(null)
const resumeItemId = item?.Id
const resumePositionTicks = item?.UserData?.PlaybackPositionTicks
/* Reset transient flags on item change */
useEffect(() => {
setUpNextDismissed(false)
@@ -398,29 +384,20 @@ export default function PlayerPage() {
setStreamAudioIndex(null)
setEndCardOpen(false)
pendingSeekRef.current = null
resumePromptShownRef.current = null
usePlayerRuntimeStore.getState().resetForNewItem()
}, [id, setPanel])
/* Resume prompt: show on first mount when there's a saved position
* past the threshold AND the user wants the prompt AND the URL didn't
* already specify ?resume=true (queue navigation path).
* Intentionally scoped to item?.Id only - we only want to evaluate
* the resume condition once per item, not re-trigger when item data
* refreshes or prefs change mid-playback. */
const resumePromptShownRef = useRef<string | null>(null)
const resumeItemId = item?.Id
const resumePositionTicks = item?.UserData?.PlaybackPositionTicks
useEffect(() => {
if (!resumeItemId || resumePromptShownRef.current === resumeItemId) return
const pos = Number(resumePositionTicks ?? 0)
const thresholdSec = usePreferencesStore.getState().resumeThresholdSec ?? 5
const threshold = thresholdSec * 10_000_000
const fromQueue = searchParams.get('resume') === 'true'
if (showResumePromptPref && !fromQueue && pos > threshold) {
if (showResumePromptPref && pos > threshold) {
setResumePromptOpen(true)
resumePromptShownRef.current = resumeItemId
}
}, [resumeItemId, resumePositionTicks, searchParams, showResumePromptPref])
}, [resumeItemId, resumePositionTicks, showResumePromptPref])
/* Auto-rewatch counter: when an already-played item starts playing
* again, record the rewatch. We trip it at most once per item-mount