Add gapless and crossfade playlist transitions with a mode toggle, and a waveform seek bar for audio-only playback
This commit is contained in:
22
CLAUDE.md
22
CLAUDE.md
@@ -115,6 +115,28 @@ JSON shapes mirror the Tauri Rust bridge exactly — don't change one side alone
|
||||
forever and Chrome killed the tab ("Target crashed" in Playwright, no JS
|
||||
error). Never cap with a loop whose exit depends on a deferred removal.
|
||||
|
||||
## Playlist transitions + waveform (`Transition` / `Wave` in app.js)
|
||||
- `data.settings.transition` = `off` | `gapless` | `crossfade` (`crossfadeSec`,
|
||||
default 6); the ↦/⇥/⤨ button cycles it with a 6-s toast. Applies only to
|
||||
playlist/queue playback with a next song, not with loop-one or an A-B loop.
|
||||
- A hidden **bridge `<audio>`** preloads the next song's audio ~25 s early
|
||||
(offline copy, else `/api/streams`). Crossfade starts it `crossfadeSec` early
|
||||
and ramps both volumes; gapless starts it when the song ends. Then the queue
|
||||
advances normally with `Player._handoff` set: `_startPlayback()` seeks the
|
||||
new track to the bridge's position, plays, and releases the bridge on
|
||||
`playing` (failsafe 5 s / 20 s). afterLoad skips resume/A-marker seeks
|
||||
during a handoff; `onTrackEnded` ignores `ended` while one runs.
|
||||
- iOS ignores `element.volume`, so crossfade degrades to gapless there.
|
||||
- Waveform: `GET /api/media/:id/peaks` = 400 RMS buckets (0..100, ^0.7 so
|
||||
quiet verses stay visible) from ffmpeg over the server-cached copy, memoised
|
||||
per file path (gen). Audio-only mode draws it on `#waveCanvas` BEHIND the
|
||||
range input (made transparent, still the control), + hover time tooltip and
|
||||
"⚡ Jump to the loudest part" (loudest ~5 s window). Not cached on the server
|
||||
→ plain seek bar. Envelopes are kept in localStorage (`ytpPeaks`, 80 songs).
|
||||
- Tested with real audio: a local server whose media_cache holds 20-s clips
|
||||
(upsertMedia rows + `<id>.1.m4a/.mp4` files) — Playwright's Chromium plays
|
||||
AAC; launch with `--autoplay-policy=no-user-gesture-required`.
|
||||
|
||||
## Phone remote (`server/remote.js`, `Remote` in app.js)
|
||||
- Desktop tab playing to a TV = **host**; phone = **remote**. Both are browser
|
||||
tabs of this app, so the server relays over `/ws/remote` (Bun `server.upgrade`
|
||||
|
||||
Reference in New Issue
Block a user