* 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.
Seven domain-eng splits peel ~200 LOC of read endpoints out of
`api/subsonic.ts`:
- `subsonicStreamUrl.ts` — `buildStreamUrl`, `coverArtCacheKey`,
`buildCoverArtUrl`, `buildDownloadUrl` (token-signed URL builders
for the four /rest endpoints we hand to the browser).
- `subsonicStarRating.ts` — `getStarred`, `star`, `unstar`,
`setRating`, `probeEntityRatingSupport`. `setRating` still triggers
the lazy `navidromeBrowse` cache invalidation; the same-folder
lazy import path is preserved.
- `subsonicSearch.ts` — `search`, `searchSongsPaged`.
- `subsonicScrobble.ts` — `scrobbleSong`, `reportNowPlaying`,
`getNowPlaying`.
- `subsonicAlbumInfo.ts` — `getAlbumInfo2`.
- `subsonicLyrics.ts` — `getLyricsBySongId`.
- `subsonicGenres.ts` — `getGenres`, `getAlbumsByGenre`.
63 external call sites migrated to direct imports. Four `vi.mock`
targets in the store-level tests pointed at `../api/subsonic` and
were updated to the new module paths.
Pure code-move. subsonic.ts: 762 → 561 LOC (−201).
The ~150-LOC `applyQueueHistorySnapshot` helper that lived inside the
playerStore `create((set, get) => { … })` closure moves out into
`src/store/applyQueueHistorySnapshot.ts`. The function now takes the
zustand `set` / `get` references as explicit parameters; the two
caller sites (`undoLastQueueEdit`, `redoLastQueueEdit`) pass them
through unchanged.
Side-cleanup: four imports that only fed the moved helper drop from
playerStore (getPlaybackSourceKind, queueUndoRestoreAudioEngine,
setPendingQueueListScrollTop, shallowCloneQueueTracks).
playerStore 1706 → 1550 LOC (−156).
The undo/redo flow keeps behaving 1:1 — the function is exported and
deterministic; the closure capture only existed for the set/get pair
which is trivial to pass through.