Repository navigation
Replace the audio player's native control with a scrubbable waveform - #54
Merged
Merged
Conversation
Audio assets and clips now play through a waveform you can click or drag
to seek, with a play/pause button and a time readout, in place of the
browser's plain <audio controls>.
The <audio> element is kept and only loses its native controls.
wavesurfer.js draws over it as `media`, so the start-at seek, transcript
click-to-seek, the clip editor and the out-point pause all keep working
unchanged. A clip shows its parent's waveform with everything outside its
in/out window dimmed.
The peaks come from a new GET /api/assets/{id}/peaks. It decodes once with
ffmpeg at 8 kHz, streamed so memory stays flat, max-pools to 2000 bars,
and caches the result as <key>.peaks.json beside the file. wavesurfer is
never left to build them itself, because that means downloading and
decoding the whole file in the browser. Until the peaks arrive, or if they
can't be made, the player scrubs on a flat line.
The cache is computed lazily, so there is no migration or backfill. It is
deleted with its file, counted with the derived files in storage usage,
and never offered as a stray.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V1geD3VLg4aqTvHVuRLA53
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.
What
Audio assets and audio clips now play through a waveform you can click or drag to seek. It has a play/pause button and a
0:20 / 0:40readout, and it replaces the browser's plain<audio controls>. Video is unchanged.How
Frontend. There is a new
WaveformPlayer, built onwavesurfer.jsv7 (BSD-3, no dependencies).<audio>element stays where it was and only loses its native controls. wavesurfer is given it asmediaand draws over it.attachPlayer's start-at seek, transcript click-to-seek, the clip editor's "set point here", and the clip's out-point pause.role="slider". Arrow keys seek ±5 s and Space plays or pauses.Backend. There is a new
GET /api/assets/{id}/peaks, which returns{"data": {"duration", "peaks"}}.ingest/waveform.pydecodes once with ffmpeg at 8 kHz mono, streamed so memory stays flat, and max-pools down to 2000 bars.services/waveforms.pycaches the result at<key>.peaks.jsonbeside the file. A clip uses its parent's file, so it shares its parent's cache.Testing
pytest -q: 1441 passed, including the newtests/test_peaks.py. It covers peaks, the cache hit, recomputing a corrupt cache, a clip sharing its parent's peaks,not_audio, 404 for another user's asset, a missing file, no ffmpeg, cleanup on delete, and that the cache is not counted as a stray.npm test: 447 passed, including the newWaveformPlayer.test.tsx.npm run lint,format:checkandbuildare clean.<audio>src is never reset, and wavesurfer makes zero fetches of the media file.Generated by Claude Code