* fix(playback): pin queue streams, cover art, and library links to queue server
When the active server changes while a queue from another server is playing,
keep streams and UI on queueServerId; switch back for artist/album links and
queue or player-bar context menus.
* fix(playback): switch to queue server when opening Now Playing
Ensure active server matches queueServerId before Subsonic fetches on the
Now Playing page, mobile player route, and queue info panel; scope caches
by server id.
* docs(credits): mention Now Playing in PR #717 contribution line
* fix(playback): route scrobble and queue sync to queue server
Address PR review: apiForServer for scrobble/now-playing/savePlayQueue,
clear queueServerId on server removal, mini-player queueServerId sync,
block cross-server enqueue with toast, and regression tests.
111 of 122 top-level src/utils/ files move into 16 topic folders (audio,
cache, cover, share, server, playback, playlist, deviceSync, waveform,
mix, format, export, changelog, ui, perf, componentHelpers). True
singletons with no cluster stay at the utils/ root.
Pure file-move: a path-aware codemod rewrote 539 relative-import
specifiers across 275 files; no logic touched. The hot-path coverage
gate list (.github/frontend-hot-path-files.txt) is updated to the new
paths for the 11 gated utils files — a mechanical consequence of the
move, not a CI change. tsc is green.
Three domain-eng modules peel ~316 LOC of fetch/mapping out of
`api/subsonic.ts`:
- `subsonicLibrary.ts` — browse + random + per-song fetch
(`getMusicDirectory`, `getMusicIndexes`, `getMusicFolders`,
`getRandomAlbums`, `getAlbumList`, `getRandomSongs`,
`getRandomSongsFiltered`, `getSong`, `getAlbum`,
`filterSongsToActiveLibrary`, `similarSongsRequestCount`, plus
the private `albumIdsInActiveLibraryScope` cache).
- `subsonicArtists.ts` — artist endpoints (`getArtists`, `getArtist`,
`getArtistInfo`, `getTopSongs`, `getSimilarSongs2`,
`getSimilarSongs`). Uses Library's `filterSongsToActiveLibrary` and
`similarSongsRequestCount` for the per-library scoping fallback.
- `subsonicRatings.ts` — `parseSubsonicEntityStarRating` parser plus
`prefetchArtistUserRatings` and `prefetchAlbumUserRatings` workers
with the shared 7-min cache. Calls back into Library/Artists for
the per-id fetch.
51 external call sites migrated to direct imports. No re-export
shims in `subsonic.ts`. Statistics endpoints still in `subsonic.ts`
keep their `RATING_CACHE_TTL` constant locally (same 7-min window).
subsonic.ts: 1078 → 762 LOC (−316).
Move the ~165-LOC `resume` action body into `runResume(set, get)`
in `src/store/resumeAction.ts`, following the helper-with-thin-wrapper
pattern from E.37 + E.38.
Covers all three resume branches:
- Orbit guest catch-up to host's live position (same-track → seek;
different-track → playTrack + deferred seek).
- Radio resume via HTML5 audio.
- Regular track resume: warm engine (audio_resume) or cold start
(hot-cache promote → getSong refetch → audio_play → seek to
persisted currentTime, with currentTrack fallback on fetch fail).
Pure code-move. playerStore.ts: 868 → 702 LOC (−166).