fix(spf): load final segment when seeking to exact end (#1828) - #1852
Merged
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
📦 Bundle Size Report🎨 @videojs/html — no changesPresets (7)
Media (10)
Players (5)
Skins (30)
UI Components (39)
Sizes are marginal over the root entry point. ⚛️ @videojs/react — no changesPresets (7)
Media (9)
Skins (27)
UI Components (33)
Sizes are marginal over the root entry point. 🧩 @videojs/core — no changesEntries (68)
🏷️ @videojs/element — no changesEntries (2)
📦 @videojs/store — no changesEntries (3)
🔧 @videojs/utils — no changesEntries (11)
📦 @videojs/spf — no changesEntries (4)
ℹ️ How to interpretJS sizes are initial static graph totals (minified + brotli). Lazy dynamic chunks are shown separately when present.
Run |
`getSegmentsToLoad` used a strict `endTime > currentTime` overlap test, so seeking to `currentTime === duration` selected no segment: the final segment's end equals `currentTime`. The last segment never loaded, `endOfStream()` never fired, the MediaSource stayed `open`, and the seek stalled indefinitely (readyState 1, seeking stuck true). Include the final segment at the end boundary (`isLast && endTime >= currentTime`); interior boundaries keep strict `>` so a just-finished segment isn't reloaded. General segment-loader edge — reproduces on native 0-based sources, independent of non-zero-PTS relocation. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
cjpillsbury
force-pushed
the
fix/spf-exact-end-seek-stall
branch
from
July 27, 2026 19:01
5d0f367 to
f19e8a8
Compare
✅ Deploy Preview for vjs10-site ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 7a3ea38. Configure here.
Extends the exact-end seek fix. After the first end, `endOfStream()` clamps `MediaSource.duration` to the true buffered end, which can run slightly past the model's EXTINF-derived last-segment `endTime`. A later seek to that grown duration — e.g. seeking to the end again after a `loop` restart — landed just past the model `endTime`, so `getSegmentsToLoad` dropped the final segment: it never loaded, the loader went idle, and the seek stalled (`seeking` stuck true, `MediaSource` `open`). The terminal segment has no successor and no reachable position past it (the playhead is clamped to the presentation's range), so it needs no upper-bound overlap check — it's loadable whenever the forward window reaches it. Interior segments keep the strict `>` so a just-finished segment isn't reloaded. No duration value is consulted. In-code live note: for an un-ended presentation `isLast` is the sliding edge, and loading it eagerly is benign today but the live effort should confirm the edge / end-of-stream interaction. Adds unit regression tests (exact-end and post-loop overshoot); reproduced and verified fixed in Chromium and Firefox (play, seek to duration, loop, seek to duration again -> loops cleanly instead of stalling). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
cjpillsbury
force-pushed
the
fix/spf-exact-end-seek-stall
branch
from
July 27, 2026 21:34
7a3ea38 to
1ef1590
Compare
spuppo-mux
approved these changes
Jul 27, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Fixes #1828.
Summary
Seeking to
currentTime === durationexactly (while playing) stalled indefinitely — the final segment was never selected by the forward-load window, soendOfStream()never fired and the seek couldn't complete.Root cause
getSegmentsToLoadfiltered segments with a strictendTime > currentTimeoverlap test. AtcurrentTime === durationthe final segment'sendTime === duration, so it was excluded, never loaded, and theMediaSourcestayedopen(readyState 1,seekingstuck true).Fix
Include the final segment at the end boundary (
isLast && endTime >= currentTime) ingetSegmentsToLoad; interior boundaries keep strict>so a just-finished segment isn't reloaded. (packages/spf/src/media/buffer/forward-buffer.ts)Smoke test
Deploy preview (this PR's Vercel branch build), looping so the end boundary is exercised:
https://v10-sandbox-git-fix-spf-exact-end-seek-stall-mux.vercel.app/spf-segment-loading/?muted=true&autoplay=true&loop=true&preload=auto
Watch it reach the end (drag the scrubber near the end to get there quickly). Confirm across Chromium, Firefox, and Safari/WebKit:
loop=true(the link above): the stream reaches the end and restarts cleanly from the beginning — no stall at the boundary.&loop=true: the stream reaches the end and stops cleanly atended(not frozen mid-seek), and pressing play again restarts from the start.Pre-fix, the stream instead stalled at the very end — the final segment never loaded, so it neither ended nor looped. Any VOD exercises this (a general segment-loader edge, not relocation-specific); the page default is a Mux VOD.
Testing
forward-buffer21/21,segment-loaderactor 5/5, typecheck + biome clean./spf-segment-loading/, Mux VOD, seek to exactdurationwhile playing): reachesendedin ~0.5s — last segment loads,MediaSource→ended, buffered extends to the full end. On the same harness pre-fix: stalls (seekingstuck true,MediaSourceopen, buffered never reaches the end).Notes
feat/spf-non-zero-pts-relocationand targets it for a clean diff, but touches only pre-existing code, so it's cleanly cherry-pickable tomainif it should land independently.🤖 Generated with Claude Code
Note
Medium Risk
Touches core forward-buffer segment selection used by the segment loader; behavior change is narrow (terminal segment only) but affects end-of-VOD and loop seeks across all SPF playback.
Overview
Fixes #1828 by changing how
getSegmentsToLoaddecides whether a segment overlaps the playhead. Interior segments still requiresegmentEnd > currentTimeso a segment you just finished at a boundary is not re-fetched; the last segment is always treated as overlapping when it falls in the forward window, so seeks tocurrentTime === duration(and slight overshoot after loop/MediaSource.durationclamping) still queue the final segment for load.Without that, the last segment was dropped at the exact end,
endOfStream()never ran, and playback could stall withseekingstuck. Tests were updated for the “past all segments” case and new exact-end regressions plus a mid-stream boundary guard.Reviewed by Cursor Bugbot for commit 1ef1590. Bugbot is set up for automated code reviews on this repo. Configure here.