skip resume prompt for ?resume=true and playlist queue

This commit is contained in:
2026-06-06 23:35:20 +03:00
parent 000e4feb01
commit ec06cf69a1
+33 -21
View File
@@ -32,6 +32,7 @@ import PlayerOverlays from '../components/player/PlayerOverlays'
import { computeRecapTrigger } from '../lib/recap-trigger'
import { usePersonalData } from '../stores/personal-data-store'
import { usePlayerRuntimeStore } from '../stores/player-runtime-store'
import { useQueueStore } from '../stores/queue-store'
import { usePlayerShortcuts } from '../hooks/use-player-shortcuts'
import { detachAudioGraph } from '../lib/audio-graph'
import type { ShortcutContext } from '../lib/player-shortcuts'
@@ -363,15 +364,16 @@ export default function PlayerPage() {
})
}
/* 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. */
/* Resume behaviour: when the saved position is past the threshold,
* queue the seek so onCanPlay can apply it (the underlying
* HTMLMediaElement.currentTime is the only path that works for both
* direct-play MP4 and HLS without restarting from 0). Decide whether
* to also show the prompt:
* - ?resume=true : the caller already chose Resume, don't ask again
* - playlist queue: auto-advance through a playlist shouldn't ask
* before every episode
* - otherwise : show the prompt so the user can pick Resume /
* Start over (if the show-resume-prompt pref is on) */
const resumePromptShownRef = useRef<string | null>(null)
const resumeItemId = item?.Id
const resumePositionTicks = item?.UserData?.PlaybackPositionTicks
@@ -388,25 +390,35 @@ export default function PlayerPage() {
usePlayerRuntimeStore.getState().resetForNewItem()
}, [id, setPanel])
/* Resume behaviour: when the saved position is past the threshold,
* queue the seek so onCanPlay can apply it (the underlying
* HTMLMediaElement.currentTime is the only path that works for both
* direct-play MP4 and HLS without restarting from 0). Decide whether
* to also show the prompt:
* - ?resume=true : the caller already chose Resume, don't ask again
* - playlist queue: auto-advance through a playlist shouldn't ask
* before every episode
* - otherwise : show the prompt so the user can pick Resume /
* Start over (if the show-resume-prompt pref is on) */
const queueSource = useQueueStore(s => s.source)
useEffect(() => {
if (typeof window !== 'undefined') {
console.log('[player] resume prompt effect', {
resumeItemId,
alreadyShown: resumePromptShownRef.current === resumeItemId,
pos: Number(resumePositionTicks ?? 0),
showResumePromptPref,
})
}
if (!resumeItemId || resumePromptShownRef.current === resumeItemId) return
if (!resumeItemId) return
const pos = Number(resumePositionTicks ?? 0)
const thresholdSec = usePreferencesStore.getState().resumeThresholdSec ?? 5
const threshold = thresholdSec * 10_000_000
if (showResumePromptPref && pos > threshold) {
if (typeof window !== 'undefined') console.log('[player] resume prompt opening')
if (pos <= threshold) return
const target = pos / 10_000_000
if (pendingSeekRef.current == null) {
pendingSeekRef.current = target
}
if (resumePromptShownRef.current === resumeItemId) return
const inPlaylist = queueActive && queueSource?.type === 'playlist'
const skipPrompt = resume || inPlaylist
if (!skipPrompt && showResumePromptPref) {
setResumePromptOpen(true)
resumePromptShownRef.current = resumeItemId
}
}, [resumeItemId, resumePositionTicks, showResumePromptPref])
}, [resumeItemId, resumePositionTicks, showResumePromptPref, resume, queueActive, queueSource])
/* Auto-rewatch counter: when an already-played item starts playing
* again, record the rewatch. We trip it at most once per item-mount