feat(track): propagate version through queue builders and MPRIS (#360)

The previous two commits added the version field but several builder
helpers in routes/+page.svelte, miniplayer/+page.svelte, and view-
specific local Track interfaces still dropped it on the way to the
backend, so the on-screen rendering went back to the bare title for
queues built from anywhere except album/playlist detail.

Builders updated to pass version
--------------------------------
~50 inline `title: trk.title` / `title: track.title` assignments where
the destination is a BackendQueueTrack (sent to v2_replace_queue,
v2_add_to_queue_*, mixtape enqueue paths, infinite-radio start, etc.)
across:

  - src/routes/+page.svelte (album play, mixtape, search-result play,
    favorites/playlist play, history mapping, queue-from-session
    restore, infinite-radio resolution, dynamic suggest, etc.)
  - src/routes/miniplayer/+page.svelte (queue snapshot)
  - AlbumDetailView, ArtistDetailView, FavoritesView, FavQView,
    TopQView, LabelView, PurchasesView, PurchaseAlbumDetailView,
    SearchView, DynamicSuggestView, WeeklySuggestView
  - playbackService.ts (cast metadata, MPRIS metadata - via
    formatTrackTitle so MPRIS shows the full title with edition)
  - lyricsStore.ts (track context for lyrics queries)
  - immersive/panels/CoverflowPanel.svelte (rendered title in
    coverflow card uses formatTrackTitle directly)

Local Track interfaces extended with `version?: string | null`
--------------------------------------------------------------
- ArtistDetailView: Track and DisplayTrack interfaces
- LabelView: Track interface
- SearchView: Track interface
- FavoritesView: FavoriteTrack interface
- FavQView: FavTrack interface
- DynamicSuggestTrack (in src/lib/types/dynamicSuggest.ts)
- PurchasedTrack (in src/lib/types/purchases.ts)

Reverted (the auto-insert script touched these but the destination
type is not a track):
- AddToMixtapeItem: it's a wrapper for both album and track ops; the
  underlying track keeps version through other paths
- v2_set_media_metadata invoke and v2_cache_track_for_offline invoke:
  the backend command shapes don't have a version arg; can be added
  later if MPRIS/cache need to surface it independently
- Album-level constructions in some search paths: those build an
  Album (no edition concept at album-level for the search row)

Frontend npm run check: 0 errors. Backend cargo test: 196 passed.

cc
This commit is contained in:
vicrodh committed 2026-04-27 20:20:52 -06:00
1 parent 0129518d8f
commit 65cb9ad7c4
18 files changed
+443 -369

No files matched your search

+26
View File
@@ -1183,6 +1183,7 @@
return {
id: track.id,
title: track.title,
version: track.version ?? null,
artist: track.artist,
album: track.album,
artwork: track.artwork_url || '',
@@ -1585,6 +1586,7 @@
const queueTracks = playableTracks.map((trk) => ({
id: trk.id,
title: trk.title,
version: trk.version ?? null,
artist: trk.artist || converted.artist || 'Unknown Artist',
album: converted.title || '',
duration_secs: trk.durationSeconds,
@@ -1738,6 +1740,7 @@
.map((trk) => ({
id: trk.id,
title: trk.title,
version: trk.version ?? null,
artist: trk.artist || converted.artist || 'Unknown Artist',
album: albumTitle,
duration_secs: trk.durationSeconds,
@@ -2185,6 +2188,7 @@
const queueTracks: BackendQueueTrack[] = album.tracks.map(trk => ({
id: trk.id,
title: trk.title,
version: trk.version ?? null,
artist: trk.artist || album.artist || 'Unknown Artist',
album: album.title || '',
duration_secs: trk.durationSeconds,
@@ -2211,6 +2215,7 @@
await playTrack({
id: firstTrack.id,
title: firstTrack.title,
version: firstTrack.version ?? null,
artist: firstTrack.artist || album.artist || 'Unknown Artist',
album: album.title || '',
artwork,
@@ -2234,6 +2239,7 @@
const queued = await queueTrackNext({
id: trk.id,
title: trk.title,
version: trk.version ?? null,
artist: trk.artist || album.artist || 'Unknown Artist',
album: album.title || '',
duration_secs: trk.durationSeconds,
@@ -2267,6 +2273,7 @@
const queueTracks: BackendQueueTrack[] = album.tracks.map(trk => ({
id: trk.id,
title: trk.title,
version: trk.version ?? null,
artist: trk.artist || album.artist || 'Unknown Artist',
album: album.title || '',
duration_secs: trk.durationSeconds,
@@ -2342,6 +2349,7 @@
await cacheTracksForOfflineBatch(tracksToDownload.map(track => ({
id: track.id,
title: track.title,
version: track.version ?? null,
artist: track.artist || album.artist || 'Unknown',
album: album.title,
albumId: album.id,
@@ -2567,6 +2575,7 @@
await playTrack({
id: track.id,
title: track.title,
version: track.version ?? null,
artist: track.performer?.name || 'Unknown Artist',
album: track.album?.title || '',
artwork,
@@ -2625,6 +2634,7 @@
const queueTracks: BackendQueueTrack[] = playableTracks.map(trk => ({
id: trk.id,
title: trk.title,
version: trk.version ?? null,
artist: trk.artist || album.artist || 'Unknown Artist',
album: album.title || '',
duration_secs: trk.durationSeconds,
@@ -2652,6 +2662,7 @@
await playTrack({
id: track.id,
title: track.title,
version: track.version ?? null,
artist: track.artist || selectedAlbum?.artist || 'Unknown Artist',
album: selectedAlbum?.title || '',
artwork,
@@ -2955,6 +2966,7 @@
await playTrack({
id: track.id,
title: track.title,
version: track.version ?? null,
artist: track.artist,
album: track.album,
artwork: resolveQueueTrackArtwork(track.artwork_url),
@@ -3126,6 +3138,7 @@
await handleTrackPlay({
id: historyTrack.id,
title: historyTrack.title,
version: historyTrack.version ?? null,
performer: { name: historyTrack.artist },
album: { title: historyTrack.album, image: { large: historyTrack.artwork_url || '' } },
duration: historyTrack.duration_secs,
@@ -3207,6 +3220,7 @@
playTrack({
id: firstTrack.id,
title: firstTrack.title,
version: firstTrack.version ?? null,
artist: firstTrack.artist,
album: firstTrack.album,
artwork: firstTrack.artwork_url || '',
@@ -3241,6 +3255,7 @@
playTrack({
id: firstTrack.id,
title: firstTrack.title,
version: firstTrack.version ?? null,
artist: firstTrack.artist,
album: firstTrack.album,
artwork: firstTrack.artwork_url || '',
@@ -3276,6 +3291,7 @@
playTrack({
id: firstTrack.id,
title: firstTrack.title,
version: firstTrack.version ?? null,
artist: firstTrack.artist,
album: firstTrack.album,
artwork: firstTrack.artwork_url || '',
@@ -3317,6 +3333,7 @@
const queued = await queueTrackNext({
id: trk.id,
title: trk.title,
version: trk.version ?? null,
artist: trk.artist || album.artist || 'Unknown Artist',
album: album.title || '',
duration_secs: trk.durationSeconds,
@@ -3360,6 +3377,7 @@
const queueTracks: BackendQueueTrack[] = playableTracks.map(trk => ({
id: trk.id,
title: trk.title,
version: trk.version ?? null,
artist: trk.artist || album.artist || 'Unknown Artist',
album: album.title || '',
duration_secs: trk.durationSeconds,
@@ -3518,6 +3536,7 @@
await cacheTracksForOfflineBatch(tracksToDownload.map(track => ({
id: track.id,
title: track.title,
version: track.version ?? null,
artist: track.artist || album.artist || 'Unknown',
album: album.title,
albumId: album.id,
@@ -3552,6 +3571,7 @@
await cacheTracksForOfflineBatch(album.tracks.map(track => ({
id: track.id,
title: track.title,
version: track.version ?? null,
artist: track.artist || album.artist || 'Unknown',
album: album.title,
albumId: album.id,
@@ -3588,6 +3608,7 @@
await cacheTracksForOfflineBatch(album.tracks.items.map(track => ({
id: track.id,
title: track.title,
version: track.version ?? null,
artist: track.performer?.name || album.artist?.name || 'Unknown',
album: album.title,
albumId: album.id,
@@ -3693,6 +3714,7 @@
playTrack({
id: track.id,
title: track.title,
version: track.version ?? null,
artist: track.artist || 'Unknown Artist',
album: track.album || 'Playlist',
artwork: track.albumArt || '',
@@ -3723,6 +3745,7 @@
{
id: track.id,
title: track.title,
version: track.version ?? null,
artist: track.artist || 'Unknown Artist',
album: track.album || 'Playlist',
artwork: track.albumArt || '',
@@ -4066,6 +4089,7 @@
setCurrentTrack({
id: track.id,
title: track.title,
version: track.version ?? null,
artist: track.artist,
album: track.album,
artwork: resolveQueueTrackArtwork(track.artwork_url),
@@ -4271,6 +4295,7 @@
const allTracks: PersistedQueueTrack[] = tracks.map(track => ({
id: track.id,
title: track.title,
version: track.version ?? null,
artist: track.artist,
album: track.album,
duration_secs: track.duration_secs,
@@ -4467,6 +4492,7 @@
await playTrack({
id: next.id,
title: next.title,
version: next.version ?? null,
artist: next.artist,
album: next.album,
duration: next.duration_secs,
+1
View File
@@ -356,6 +356,7 @@
await playTrack({
id: track.id,
title: track.title,
version: track.version ?? null,
artist: track.artist,
album: track.album,
artwork: track.artwork_url || '',