9cb19f42af0f06b178dad3de936fa1da1537aea6
The album continuation appended exactly ONE track and then waited for the next track start to append the one after, so a song started from search or an artist page showed a queue of one or two entries however long the record was. It still resolves one at a time -- a track cannot be queued before a peer with it is found -- but it no longer stops after the first. My Name Is Jonas cold: 1 to all 10 in under 12 seconds, in album order. The resume anchor moved to the LAST queued track so a fill cut short by going offline picks up where it stopped instead of being locked out by the "next already queued" guard. An adversarial review of that change found the hole it opened, and it is fixed here rather than shipped: dropping the second clause of the bail-out was wrong. streamSong installs autoAlbum only AFTER waitForStreamStart, which polls the GLOBAL player status, so a second play issued during that buffering window nulls autoAlbum and streamSong then re-installs its own context over the top -- and the fill would go on appending one album's tracks to the other album's live queue. The anchor must also still BE in the queue, which survives our own appends and disappears exactly when the queue is replaced; and streamSong no longer installs a context it no longer owns. advanceGaplessly reported a pre-buffered track as zero-of-zero. streamTotal === 0 is the UI's "no byte counts yet" state, so a finished track showed the indeterminate "Streaming from <peer>" sweep with no further event ever coming to correct it. Gapless is only offered for a fully cached file, so its size IS its received count. The buffering handler mirrors the store rather than zeroing it for the same reason -- those counters are what a window restore copies back, and zeroing them turned a complete transfer back into the sweep on minimize and restore. tryAppendNext set its appendedNextPath guard AFTER its await -- check then act. Harmless with one caller; the moment the cached-play event gave it a second same-tick caller both passed the guard and appended the same source to the sink twice, which puts the panel a whole track ahead of the audio from the next boundary on. It claims the slot before awaiting and gives it back on failure. ui.nowPlayingDragging is here because App.svelte's grid column has to leave the 0.28s ease at the same instant the panel does.
Languages
Rust
48.3%
Svelte
38.1%
JavaScript
13.4%
CSS
0.2%