v4: an audio file's waveform is made once by the server, and the player seeks on one accessible scrubber — every player downloaded the whole file a second time and decoded all of it in the browser to draw 150 bars, so a long FLAC cost tens of megabytes of memory per page, and the waveform could only be clicked: no drag, no keyboard, no slider for a screen reader. GET /api/dumps/:id/waveform now answers an audio dump's peaks, which lib/ffmpeg.ts decodes with ffmpeg on first request, mono at 8 kHz and streamed, keeps beside the thumbnails as the response itself, and serves with an ETag (a ten-minute MP3 takes about a second, then a few hundred bytes). The peaks are taken by shared/waveform.ts's peaksOf, scaled to the loudest so a quiet recording fills the track, and the dump form's preview of a file not yet uploaded decodes it with the same function, at 8 kHz in an OfflineAudioContext. Scrubber replaces Waveform and SeekBar: a role="slider" that seeks where a pointer lets go, follows a drag (the clock shows where it is held), takes arrows, Home and End, and draws the bars as one path with the played part clipped by a nested svg, so it moves smoothly and a timeupdate redraws two attributes instead of 150 rects; audio without a waveform, and video, get a plain bar. MediaPlayer reads whether it plays from the element's events alone, so a click no longer reports the change twice, its handles for PlayerProvider are stable callbacks instead of refs to refs, the drag no longer reattaches every listener, and the <source> children that src made dead are gone, with the mime prop. The file, thumbnail and waveform routes resolve their dump, token and caching through lib/dump-media.ts, and what is generated from an upload is named and removed in lib/ffmpeg.ts, the custom thumbnail by dump-service's customThumbnailPath, instead of paths spelled out in each. The test setup's play() and pause() fire their events as a browser does. 277 backend tests and 684 frontend tests pass, and deno check, tsc, eslint, doc:lint and i18n:compile --strict are clean; checked in the app with a real FLAC on its dump page and in the global player at 1280 and 390px, seeking by keyboard.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
5
API.md
5
API.md
@@ -80,7 +80,8 @@ Every JSON endpoint answers the envelope of `shared/api.ts`:
|
||||
`{ "items", "hasMore" }` and takes `?page=` (from 1) and `?limit=` (20 by
|
||||
default, 100 at most). "Signed in" means a session token as
|
||||
`Authorization: Bearer …`. Media can't send a header, so a private file,
|
||||
thumbnail, cover or attachment takes the owner's media token as `?token=`.
|
||||
thumbnail, waveform, cover or attachment takes the owner's media token as
|
||||
`?token=`.
|
||||
|
||||
### me
|
||||
|
||||
@@ -134,6 +135,8 @@ thumbnail, cover or attachment takes the owner's media token as `?token=`.
|
||||
`dump:moderate`.
|
||||
- `GET`, `PUT`, `DELETE /api/dumps/:id/thumbnail` — the thumbnail; a custom
|
||||
one, set or removed by its poster or `dump:moderate`.
|
||||
- `GET /api/dumps/:id/waveform` — anyone who may see it. An audio file's
|
||||
waveform, `{ "peaks" }`, for the player to seek on.
|
||||
- `GET`, `POST /api/dumps/:id/comments` — anyone who may see the dump; posting
|
||||
signed in. Its comments.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user