seek via underlying media element for resume
This commit is contained in:
@@ -348,6 +348,19 @@ export default function PlayerPage() {
|
||||
}
|
||||
return ''
|
||||
})()
|
||||
if (typeof window !== 'undefined' && playbackInfo) {
|
||||
const transcodingUrl = resolvedSource?.TranscodingUrl
|
||||
const supportsDirectPlay = resolvedSource?.SupportsDirectPlay
|
||||
const hasRuntimeTicks = transcodingUrl ? transcodingUrl.includes('runtimeTicks=') : null
|
||||
console.log('[player] stream resolved', {
|
||||
id,
|
||||
startTimeTicks,
|
||||
supportsDirectPlay,
|
||||
transcodingUrlPresent: !!transcodingUrl,
|
||||
transcodingUrlHasRuntimeTicks: hasRuntimeTicks,
|
||||
streamUrl: streamUrl.replace(/api_key=[^&]+/, 'api_key=***'),
|
||||
})
|
||||
}
|
||||
|
||||
/* Reset transient flags on item change */
|
||||
useEffect(() => {
|
||||
@@ -1164,8 +1177,13 @@ export default function PlayerPage() {
|
||||
if (p && pendingSeekRef.current != null) {
|
||||
const target = pendingSeekRef.current
|
||||
pendingSeekRef.current = null
|
||||
if (p.currentTime < target - 0.5 || p.currentTime > target + 0.5) {
|
||||
try { p.currentTime = target } catch { /* ignore */ }
|
||||
const mediaEl = (p as any).media as HTMLMediaElement | undefined
|
||||
const before = mediaEl ? mediaEl.currentTime : p.currentTime
|
||||
if (before < target - 0.5 || before > target + 0.5) {
|
||||
try {
|
||||
if (mediaEl) mediaEl.currentTime = target
|
||||
else p.currentTime = target
|
||||
} catch { /* ignore */ }
|
||||
}
|
||||
p.play().catch(() => {})
|
||||
}
|
||||
@@ -1403,13 +1421,29 @@ export default function PlayerPage() {
|
||||
setResumePromptOpen(false)
|
||||
const p = playerRef.current
|
||||
const pos = Number(item?.UserData?.PlaybackPositionTicks ?? 0)
|
||||
const target = pos > 0 ? pos / 10_000_000 : 0
|
||||
if (typeof window !== 'undefined') {
|
||||
console.log('[player] resume prompt clicked', {
|
||||
id,
|
||||
pos,
|
||||
target,
|
||||
mediaElementCurrentTime: (p as any)?.media?.currentTime,
|
||||
streamUrlStart: streamUrl.includes('StartTimeTicks=') || streamUrl.includes('runtimeTicks='),
|
||||
})
|
||||
}
|
||||
if (p) {
|
||||
// Queue the seek: if the video isn't ready yet, onCanPlay
|
||||
// picks it up. The setter works on a paused player in
|
||||
// vidstack, but buffering the seek target can race the
|
||||
// canPlay event for the initial source.
|
||||
pendingSeekRef.current = pos > 0 ? pos / 10_000_000 : 0
|
||||
try { p.currentTime = pendingSeekRef.current } catch { /* ignore */ }
|
||||
// Vidstack has a known issue (GH #941) where setting
|
||||
// currentTime on the MediaPlayerInstance for a direct-play
|
||||
// MP4 source restarts the video from the beginning. The
|
||||
// workaround is to set currentTime on the underlying
|
||||
// HTMLMediaElement. For HLS it works either way; we use
|
||||
// the underlying element for consistency.
|
||||
pendingSeekRef.current = target
|
||||
const mediaEl = (p as any).media as HTMLMediaElement | undefined
|
||||
try {
|
||||
if (mediaEl) mediaEl.currentTime = target
|
||||
else p.currentTime = target
|
||||
} catch { /* ignore */ }
|
||||
p.play().catch(() => {})
|
||||
}
|
||||
},
|
||||
@@ -1418,7 +1452,11 @@ export default function PlayerPage() {
|
||||
const p = playerRef.current
|
||||
if (p) {
|
||||
pendingSeekRef.current = 0
|
||||
try { p.currentTime = 0 } catch { /* ignore */ }
|
||||
const mediaEl = (p as any).media as HTMLMediaElement | undefined
|
||||
try {
|
||||
if (mediaEl) mediaEl.currentTime = 0
|
||||
else p.currentTime = 0
|
||||
} catch { /* ignore */ }
|
||||
p.play().catch(() => {})
|
||||
}
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user