* feat(offline): show cached albums from all servers in Offline Library
List every offline album regardless of active server; load cover art per
source server and switch before play/enqueue. Sidebar, mobile nav, and
disconnect auto-nav use any cached content; multi-server cards show a label.
* docs(changelog): link offline library PR #719
* chore(pr-719): address review — CHANGELOG in Added, helper tests
Move release note to ## Added per team changelog policy; cover
offlineAlbumCoverArt and ensureServerForOfflineAlbum in unit tests.
* 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).
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).