Skip to content

media-time-range does not move backward for seeks smaller than 3% of duration #1306

Description

@DiFuks

Summary

media-time-range never moves backward when the seek is smaller than 3% of the media duration. The bar freezes at the pre-seek position and only starts moving again once playback catches up with it, so the freeze lasts exactly as long as the amount that was seeked back.

Steps to reproduce

  1. Play a long VOD (mine: 1:38:30, duration = 5909.6).
  2. While playing, seek backward by 20 s (arrow-key hotkey, media-seek-backward-button, or a mediaseekrequest with detail = currentTime - 20).
  3. Watch media-time-range.

Expected: the bar jumps back to the new position.
Actual: the bar stays where it was for the next 20 s of playback, then resumes normally.

Measured on the page (Chrome 150, VOD via hls.js 1.6, media-chrome 4.19.2), seek from 2301 s to 2281 s:

value
mediacurrenttime attribute 2281.01 → 2281.22 → 2281.49 … (correct)
timeRange.range.valueAsNumber 0.38936 (= 2301 s) for 20 s, unchanged

So state propagation is fine — only the range animation refuses to move.

Cause

dist/utils/range-animation.js:

update({ start, duration, playbackRate }) {
  const increase = start - this.#range.valueAsNumber;
  const durationDelta = Math.abs(duration - this.duration);
  if (increase > 0 || increase < -0.03 || durationDelta >= 0.5) {
    this.callback(start);
  }
  ...
}

start is normalized to 0..1, so the -0.03 guard means 3% of the media duration, not a fixed amount of time:

duration backward seeks that never move the bar
5 min < 9 s
1 h 38 min < 177 s
3 h < 324 s

When the callback is skipped, #animate takes the increase <= 0 branch and decays #lastRangeIncrease by 0.995 per frame, so the bar visually stands still instead of following the media.

Suggested fix

The guard looks intended to absorb the sub-second lag between timeupdate values and the position the animation has already advanced to — that intent is time-based, but the constant is expressed in fractions of duration. Something like:

if (increase > 0 || increase < -0.5 / duration || durationDelta >= 0.5) {

keeps the anti-jitter behaviour (0.5 s of tolerance) without scaling it with the media length.

Happy to send a PR if you agree with the approach.

Possibly related, separate

For seeks into an unbuffered range, the bar and media-time-display also stay at the old position for the whole buffering stall (measured: ~0.8 s on a fast connection, arbitrarily long on a slow one). mediaCurrentTime in the state mediator only updates on timeupdate/loadedmetadata, and the browser does not fire timeupdate until the seek completes, while MEDIA_SEEK_REQUEST in request-map.js sets media.currentTime without returning an optimistic state delta. Returning { mediaCurrentTime: value } there would make the UI reflect the requested position immediately. Let me know if you'd like that as its own issue.

Environment

  • media-chrome 4.19.2 (code is identical in 4.19.3-canary.1)
  • Chrome 150, macOS
  • hls.js 1.6.15, VOD stream

I searched open and closed issues for this and did not find a duplicate — apologies if I missed one.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions