skip resume prompt for ?resume=true and playlist queue
This commit is contained in:
+33
-21
@@ -32,6 +32,7 @@ import PlayerOverlays from '../components/player/PlayerOverlays'
|
|||||||
import { computeRecapTrigger } from '../lib/recap-trigger'
|
import { computeRecapTrigger } from '../lib/recap-trigger'
|
||||||
import { usePersonalData } from '../stores/personal-data-store'
|
import { usePersonalData } from '../stores/personal-data-store'
|
||||||
import { usePlayerRuntimeStore } from '../stores/player-runtime-store'
|
import { usePlayerRuntimeStore } from '../stores/player-runtime-store'
|
||||||
|
import { useQueueStore } from '../stores/queue-store'
|
||||||
import { usePlayerShortcuts } from '../hooks/use-player-shortcuts'
|
import { usePlayerShortcuts } from '../hooks/use-player-shortcuts'
|
||||||
import { detachAudioGraph } from '../lib/audio-graph'
|
import { detachAudioGraph } from '../lib/audio-graph'
|
||||||
import type { ShortcutContext } from '../lib/player-shortcuts'
|
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
|
/* Resume behaviour: when the saved position is past the threshold,
|
||||||
* past the threshold AND the user wants the prompt. The prompt auto-
|
* queue the seek so onCanPlay can apply it (the underlying
|
||||||
* confirms after a few seconds, which queues the deferred seek via
|
* HTMLMediaElement.currentTime is the only path that works for both
|
||||||
* pendingSeekRef and seeks the underlying HTMLMediaElement directly
|
* direct-play MP4 and HLS without restarting from 0). Decide whether
|
||||||
* (vidstack's MediaPlayerInstance.currentTime has a known bug on
|
* to also show the prompt:
|
||||||
* direct-play MP4 sources that restarts the video from 0).
|
* - ?resume=true : the caller already chose Resume, don't ask again
|
||||||
* Intentionally scoped to item?.Id only - we only want to evaluate
|
* - playlist queue: auto-advance through a playlist shouldn't ask
|
||||||
* the resume condition once per item, not re-trigger when item data
|
* before every episode
|
||||||
* refreshes or prefs change mid-playback. */
|
* - 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 resumePromptShownRef = useRef<string | null>(null)
|
||||||
const resumeItemId = item?.Id
|
const resumeItemId = item?.Id
|
||||||
const resumePositionTicks = item?.UserData?.PlaybackPositionTicks
|
const resumePositionTicks = item?.UserData?.PlaybackPositionTicks
|
||||||
@@ -388,25 +390,35 @@ export default function PlayerPage() {
|
|||||||
usePlayerRuntimeStore.getState().resetForNewItem()
|
usePlayerRuntimeStore.getState().resetForNewItem()
|
||||||
}, [id, setPanel])
|
}, [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(() => {
|
useEffect(() => {
|
||||||
if (typeof window !== 'undefined') {
|
if (!resumeItemId) return
|
||||||
console.log('[player] resume prompt effect', {
|
|
||||||
resumeItemId,
|
|
||||||
alreadyShown: resumePromptShownRef.current === resumeItemId,
|
|
||||||
pos: Number(resumePositionTicks ?? 0),
|
|
||||||
showResumePromptPref,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if (!resumeItemId || resumePromptShownRef.current === resumeItemId) return
|
|
||||||
const pos = Number(resumePositionTicks ?? 0)
|
const pos = Number(resumePositionTicks ?? 0)
|
||||||
const thresholdSec = usePreferencesStore.getState().resumeThresholdSec ?? 5
|
const thresholdSec = usePreferencesStore.getState().resumeThresholdSec ?? 5
|
||||||
const threshold = thresholdSec * 10_000_000
|
const threshold = thresholdSec * 10_000_000
|
||||||
if (showResumePromptPref && pos > threshold) {
|
if (pos <= threshold) return
|
||||||
if (typeof window !== 'undefined') console.log('[player] resume prompt opening')
|
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)
|
setResumePromptOpen(true)
|
||||||
resumePromptShownRef.current = resumeItemId
|
resumePromptShownRef.current = resumeItemId
|
||||||
}
|
}
|
||||||
}, [resumeItemId, resumePositionTicks, showResumePromptPref])
|
}, [resumeItemId, resumePositionTicks, showResumePromptPref, resume, queueActive, queueSource])
|
||||||
|
|
||||||
/* Auto-rewatch counter: when an already-played item starts playing
|
/* Auto-rewatch counter: when an already-played item starts playing
|
||||||
* again, record the rewatch. We trip it at most once per item-mount
|
* again, record the rewatch. We trip it at most once per item-mount
|
||||||
|
|||||||
Reference in New Issue
Block a user