Skip to content

fix(file-viewer): make previewed video seekable and stop it on close - #284

Merged
Ark0N merged 1 commit into
masterfrom
fix/file-viewer-video
Aug 13, 2026
Merged

fix(file-viewer): make previewed video seekable and stop it on close#284
Ark0N merged 1 commit into
masterfrom
fix/file-viewer-video

Conversation

@Ark0N

Copy link
Copy Markdown
Owner

Two bugs in the File Viewer's media player, both reproduced in a real browser against an 18MB mp4 before and after the fix.

1. Closing the preview left the video playing.closeFilePreview() only dropped the overlay's visible class. That is display: none and nothing else, so the video kept playing with its audio audible and no visible player to pause. Detaching the element is not a fix either: a detached HTMLMediaElement plays on until it is garbage collected. _stopFilePreviewMedia() now pauses, drops src and load()s every media element in the preview body, which also aborts the in-flight download. It runs on close and on re-open (overwriting innerHTML had exactly the same detach-but-keep-playing effect when switching files).

2. The scrub bar was inert.file-raw read the whole file and answered 200 with no Accept-Ranges, so Chrome reported video.seekable as [0, 0] and silently reverted currentTime = x; Safari refuses to start such media at all. Raw bodies are now streamed and range-aware: Accept-Ranges: bytes on every response, 206 + Content-Range for a Range request, 416 for one past EOF, and a malformed spec ignored (200) per RFC 9110. Parsing is pure and unit tested in src/web/http-range.ts; the attachments /raw route gets the same treatment.

Measured on a 66.6s, 18MB mp4:

seekableseek to 56.6safter pressing X
before[0, 0]reverted to 3.9sstill playing
after[0, 66.56]landed at 60.2spaused, NETWORK_EMPTY

Range slices are byte-identical to dd, the full-file path is byte-identical to the file, and SVG octet-stream/attachment hardening plus the 50MB cap are unchanged (the cap is still checked before the range).

Tests:test/http-range.test.ts (14 parser cases), test/routes/file-routes-range.test.ts (206/416/Accept-Ranges/bounded-read/security-header contract), test/file-preview-media.test.ts (teardown; the 3 behavior cases were confirmed to fail against unfixed panels-ui.js). Full npm run test:ci green: 5068 passed. Lint, format, typecheck, frontend-syntax, knip all clean.

Two bugs in the File Viewer's media player, both reproduced in a real
browser against an 18MB mp4 before and after the fix.
1. Closing the preview left the video playing. closeFilePreview() only
dropped the overlay's `visible` class, which is display:none and
nothing else, so the audio kept going with no visible player to pause.
Detaching the element is not a fix either: a detached HTMLMediaElement
plays on until it is garbage collected. _stopFilePreviewMedia() now
pauses, drops src and load()s every media element (also on re-open,
where overwriting innerHTML had the same effect), which additionally
aborts the in-flight download.
2. The scrub bar was inert. file-raw read the whole file and answered
200 with no Accept-Ranges, so Chrome reported video.seekable as
[0, 0] and silently reverted `currentTime = x`; Safari refuses to
start such media at all. Raw bodies are now streamed and range-aware:
Accept-Ranges: bytes on every response, 206 + Content-Range for a
Range request, 416 for one past EOF, and a malformed spec ignored
(200) per RFC 9110. Parsing is pure in src/web/http-range.ts.
Measured on tmp/codeman-crt-v5-66s.mp4 (18MB, 66.6s):
before seekable [0, 0] seek to 56.6s reverted to 3.9s close: still playing
after seekable [0, 66.56] seek to 56.6s landed at 60.2s close: paused, NETWORK_EMPTY
Range slices are byte-identical to `dd`, the full-file path is
byte-identical to the file, and the SVG octet-stream/attachment
hardening and the 50MB cap are unchanged (the cap is still checked
before the range).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@Ark0N
Ark0N merged commit 405eb50 into masterAug 13, 2026
2 checks passed
@Ark0N
Ark0N deleted the fix/file-viewer-video branch August 13, 2026 23:00
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@Ark0N@claude