Fix Last.fm scrobbles/now-playing appearing one song ahead
Summary
Last.fm was showing scrobbles/now-playing "one song ahead" of what was actually playing. Root cause: onTrackStart was being called synchronously inside playTrack() — the moment a track transition was decided, not when audio actually started producing output.
-
playTrack()setsaudio.srcand calls.play()(async — browser then buffers) butonTrackStart(file)fires/api/lastfm/now-playingimmediately, so Last.fm shows the new track while the user is still hearing the tail of the old one or silence. - At auto-advance,
handleAudioEnded→playTrack(N+1)→onTrackStart(N+1)reassigns the scrobble module'scurrentTrackbefore any pendingtimeupdatefor track N has a chance to flush.
Fix
- Move
onTrackStartout ofplayTrack/startFadeInand into the<audio onplaying>handler, keyed off apendingStartFileIdflag set when the newsrcis assigned. The flag is cleared after firing and on stop/fade-out, so pause→resume doesn't re-fire now-playing or reset the scrobble timestamp. - On the random page, gate
onTimeUpdateby active element so timeupdate events from the fading-out audio element can't feed the shared scrobble module during a crossfade.
No changes to src/lib/scrobble.ts — the module's contract is unchanged; only the timing of the calls moves.
Test plan
-
pnpm run buildpasses (verified locally) -
Play an album with a short (<1:00) interlude between longer tracks; confirm now-playing updates to each track only after it audibly starts, and the interlude still doesn't scrobble but its neighbours do -
Click a different track mid-play; confirm now-playing updates only when the new track actually begins producing audio -
Pause and resume; confirm no duplicate now-playing update and the scrobble timestamp isn't reset -
On the random page, hit Skip mid-track during a crossfade; confirm no spurious scrobble fires from the fading-out element