fix(ui): hold must-watch seek lock on progressive (non-HLS) video
The lock clamped currentTime only during the seeking event. HLS defers the forward seek until the fragment loads, so that clamp caught it; but for progressive MP4 the forward seek takes effect immediately and the mid-seek write is ignored, so playback leaked past the watched point (snackbar showed, no snap-back). Keep the immediate seeking-time clamp (HLS relies on it to avoid buffering ahead) and add an authoritative re-clamp in seeked: if the playhead still landed past the limit, snap back via a backward seek into buffered content, which holds. Snackbar now fires once per blocked gesture and only when a clamp actually happens.
This commit is contained in:
@@ -84,7 +84,8 @@
|
||||
let playedSeconds = 0;
|
||||
let lastValidTime = element.currentTime;
|
||||
let isSeeking = false;
|
||||
let hasBlockedThisSeek = false;
|
||||
let isReclamping = false;
|
||||
let seekBlockNotified = false;
|
||||
let lastHeartbeatAt = 0;
|
||||
const seekTolerance = 0.5;
|
||||
const heartbeatIntervalMs = 15_000;
|
||||
@@ -105,18 +106,50 @@
|
||||
playedSeconds = 0;
|
||||
};
|
||||
|
||||
const isAheadOfLimit = () => player.currentTime > furthestSeconds + seekTolerance;
|
||||
|
||||
const notifySeekBlocked = () => {
|
||||
if (seekBlockNotified) return;
|
||||
|
||||
seekBlockNotified = true;
|
||||
policy.onSeekBlocked?.();
|
||||
};
|
||||
|
||||
// Immediate clamp. For HLS this short-circuits the forward fragment fetch
|
||||
// so the player never buffers ahead. For progressive MP4 the write is
|
||||
// often ignored mid-seek, so `onSeeked` re-asserts it once settled.
|
||||
const onSeeking = () => {
|
||||
isSeeking = true;
|
||||
if (!hasBlockedThisSeek && player.currentTime > furthestSeconds + seekTolerance) {
|
||||
hasBlockedThisSeek = true;
|
||||
if (isReclamping) return;
|
||||
|
||||
if (isAheadOfLimit()) {
|
||||
notifySeekBlocked();
|
||||
player.currentTime = furthestSeconds;
|
||||
policy.onSeekBlocked?.();
|
||||
}
|
||||
};
|
||||
|
||||
const onSeeked = () => {
|
||||
// Consume the `seeked` produced by our own clamp write, then settle.
|
||||
if (isReclamping) {
|
||||
isReclamping = false;
|
||||
isSeeking = false;
|
||||
hasBlockedThisSeek = false;
|
||||
seekBlockNotified = false;
|
||||
lastValidTime = player.currentTime;
|
||||
return;
|
||||
}
|
||||
|
||||
// Authoritative enforcement: if the seek landed past the limit (the
|
||||
// mid-seek clamp didn't hold, e.g. progressive MP4), snap back now —
|
||||
// a backward seek into buffered content, which holds reliably.
|
||||
if (isAheadOfLimit()) {
|
||||
isReclamping = true;
|
||||
notifySeekBlocked();
|
||||
player.currentTime = furthestSeconds;
|
||||
return;
|
||||
}
|
||||
|
||||
isSeeking = false;
|
||||
seekBlockNotified = false;
|
||||
lastValidTime = player.currentTime;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user