fix(queue): complete album_id and artist_id propagation for track navigation
Ensure album_id and artist_id are passed through all queue track creation paths: - trackActions.ts build functions (Qobuz, album, playlist, local tracks) - Session persistence (both frontend and Rust backend) - buildAlbumQueueTrack wrapper function - Session restoration
This commit is contained in:
1 parent
2ea767f37c
commit
1684df7752
4 files changed
+79
-16
No files matched your search
@@ -16,6 +16,10 @@ pub struct PersistedQueueTrack {
|
|||||||
pub hires: bool,
|
pub hires: bool,
|
||||||
pub bit_depth: Option<u32>,
|
pub bit_depth: Option<u32>,
|
||||||
pub sample_rate: Option<f64>,
|
pub sample_rate: Option<f64>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub is_local: bool,
|
||||||
|
pub album_id: Option<String>,
|
||||||
|
pub artist_id: Option<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents the full persisted session state
|
/// Represents the full persisted session state
|
||||||
@@ -120,6 +124,25 @@ impl SessionStore {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add is_local, album_id, artist_id columns if they don't exist
|
||||||
|
let has_is_local: bool = conn
|
||||||
|
.query_row(
|
||||||
|
"SELECT COUNT(*) FROM pragma_table_info('queue_tracks') WHERE name = 'is_local'",
|
||||||
|
[],
|
||||||
|
|row| row.get(0),
|
||||||
|
)
|
||||||
|
.unwrap_or(0) > 0;
|
||||||
|
|
||||||
|
if !has_is_local {
|
||||||
|
let _ = conn.execute_batch(
|
||||||
|
"
|
||||||
|
ALTER TABLE queue_tracks ADD COLUMN is_local INTEGER NOT NULL DEFAULT 0;
|
||||||
|
ALTER TABLE queue_tracks ADD COLUMN album_id TEXT;
|
||||||
|
ALTER TABLE queue_tracks ADD COLUMN artist_id INTEGER;
|
||||||
|
"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(Self { conn })
|
Ok(Self { conn })
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,8 +166,8 @@ impl SessionStore {
|
|||||||
// Insert queue tracks
|
// Insert queue tracks
|
||||||
for (pos, track) in session.queue_tracks.iter().enumerate() {
|
for (pos, track) in session.queue_tracks.iter().enumerate() {
|
||||||
if let Err(e) = self.conn.execute(
|
if let Err(e) = self.conn.execute(
|
||||||
"INSERT INTO queue_tracks (position, track_id, title, artist, album, duration_secs, artwork_url, hires, bit_depth, sample_rate)
|
"INSERT INTO queue_tracks (position, track_id, title, artist, album, duration_secs, artwork_url, hires, bit_depth, sample_rate, is_local, album_id, artist_id)
|
||||||
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10)",
|
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13)",
|
||||||
params![
|
params![
|
||||||
pos as i64,
|
pos as i64,
|
||||||
track.id as i64,
|
track.id as i64,
|
||||||
@@ -156,6 +179,9 @@ impl SessionStore {
|
|||||||
track.hires as i64,
|
track.hires as i64,
|
||||||
track.bit_depth.map(|v| v as i64),
|
track.bit_depth.map(|v| v as i64),
|
||||||
track.sample_rate,
|
track.sample_rate,
|
||||||
|
track.is_local as i64,
|
||||||
|
track.album_id,
|
||||||
|
track.artist_id.map(|v| v as i64),
|
||||||
],
|
],
|
||||||
) {
|
) {
|
||||||
let _ = self.conn.execute("ROLLBACK", []);
|
let _ = self.conn.execute("ROLLBACK", []);
|
||||||
@@ -217,7 +243,7 @@ impl SessionStore {
|
|||||||
|
|
||||||
// Load queue tracks
|
// Load queue tracks
|
||||||
let mut stmt = self.conn
|
let mut stmt = self.conn
|
||||||
.prepare("SELECT track_id, title, artist, album, duration_secs, artwork_url, hires, bit_depth, sample_rate FROM queue_tracks ORDER BY position")
|
.prepare("SELECT track_id, title, artist, album, duration_secs, artwork_url, hires, bit_depth, sample_rate, is_local, album_id, artist_id FROM queue_tracks ORDER BY position")
|
||||||
.map_err(|e| format!("Failed to prepare queue query: {}", e))?;
|
.map_err(|e| format!("Failed to prepare queue query: {}", e))?;
|
||||||
|
|
||||||
let tracks: Vec<PersistedQueueTrack> = stmt
|
let tracks: Vec<PersistedQueueTrack> = stmt
|
||||||
@@ -232,6 +258,9 @@ impl SessionStore {
|
|||||||
hires: row.get::<_, i64>(6).unwrap_or(0) != 0,
|
hires: row.get::<_, i64>(6).unwrap_or(0) != 0,
|
||||||
bit_depth: row.get::<_, Option<i64>>(7)?.map(|v| v as u32),
|
bit_depth: row.get::<_, Option<i64>>(7)?.map(|v| v as u32),
|
||||||
sample_rate: row.get(8)?,
|
sample_rate: row.get(8)?,
|
||||||
|
is_local: row.get::<_, i64>(9).unwrap_or(0) != 0,
|
||||||
|
album_id: row.get(10)?,
|
||||||
|
artist_id: row.get::<_, Option<i64>>(11)?.map(|v| v as u64),
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.map_err(|e| format!("Failed to query queue tracks: {}", e))?
|
.map_err(|e| format!("Failed to query queue tracks: {}", e))?
|
||||||
|
|||||||
@@ -17,6 +17,9 @@ export interface PersistedQueueTrack {
|
|||||||
hires?: boolean;
|
hires?: boolean;
|
||||||
bit_depth?: number | null;
|
bit_depth?: number | null;
|
||||||
sample_rate?: number | null;
|
sample_rate?: number | null;
|
||||||
|
is_local?: boolean;
|
||||||
|
album_id?: string | null;
|
||||||
|
artist_id?: number | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PersistedSession {
|
export interface PersistedSession {
|
||||||
|
|||||||
@@ -37,11 +37,20 @@ export function buildQueueTrackFromQobuz(track: QobuzTrack): BackendQueueTrack {
|
|||||||
hires: track.hires_streamable ?? false,
|
hires: track.hires_streamable ?? false,
|
||||||
bit_depth: track.maximum_bit_depth ?? null,
|
bit_depth: track.maximum_bit_depth ?? null,
|
||||||
sample_rate: track.maximum_sampling_rate ?? null,
|
sample_rate: track.maximum_sampling_rate ?? null,
|
||||||
is_local: false
|
is_local: false,
|
||||||
|
album_id: track.album?.id || null,
|
||||||
|
artist_id: track.performer?.id ?? null
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function buildQueueTrackFromAlbumTrack(track: Track, albumArtwork: string, albumArtist: string, albumTitle: string): BackendQueueTrack {
|
export function buildQueueTrackFromAlbumTrack(
|
||||||
|
track: Track,
|
||||||
|
albumArtwork: string,
|
||||||
|
albumArtist: string,
|
||||||
|
albumTitle: string,
|
||||||
|
albumId?: string,
|
||||||
|
artistId?: number
|
||||||
|
): BackendQueueTrack {
|
||||||
return {
|
return {
|
||||||
id: track.id,
|
id: track.id,
|
||||||
title: track.title,
|
title: track.title,
|
||||||
@@ -52,7 +61,9 @@ export function buildQueueTrackFromAlbumTrack(track: Track, albumArtwork: string
|
|||||||
hires: track.hires ?? false,
|
hires: track.hires ?? false,
|
||||||
bit_depth: track.bitDepth ?? null,
|
bit_depth: track.bitDepth ?? null,
|
||||||
sample_rate: track.samplingRate ?? null,
|
sample_rate: track.samplingRate ?? null,
|
||||||
is_local: false
|
is_local: false,
|
||||||
|
album_id: track.albumId || albumId || null,
|
||||||
|
artist_id: track.artistId ?? artistId ?? null
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,7 +78,9 @@ export function buildQueueTrackFromPlaylistTrack(track: PlaylistTrack): BackendQ
|
|||||||
hires: track.hires ?? false,
|
hires: track.hires ?? false,
|
||||||
bit_depth: track.bitDepth ?? null,
|
bit_depth: track.bitDepth ?? null,
|
||||||
sample_rate: track.samplingRate ?? null,
|
sample_rate: track.samplingRate ?? null,
|
||||||
is_local: false
|
is_local: false,
|
||||||
|
album_id: track.albumId || null,
|
||||||
|
artist_id: track.artistId ?? null
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,7 +98,9 @@ export function buildQueueTrackFromLocalTrack(track: LocalLibraryTrack): Backend
|
|||||||
hires: isHires,
|
hires: isHires,
|
||||||
bit_depth: track.bit_depth ?? null,
|
bit_depth: track.bit_depth ?? null,
|
||||||
sample_rate: track.sample_rate ?? null,
|
sample_rate: track.sample_rate ?? null,
|
||||||
is_local: true
|
is_local: true,
|
||||||
|
album_id: null, // Local tracks don't have Qobuz album IDs
|
||||||
|
artist_id: null // Local tracks don't have Qobuz artist IDs
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+24
-8
@@ -518,7 +518,9 @@
|
|||||||
track,
|
track,
|
||||||
selectedAlbum?.artwork || '',
|
selectedAlbum?.artwork || '',
|
||||||
selectedAlbum?.artist || 'Unknown Artist',
|
selectedAlbum?.artist || 'Unknown Artist',
|
||||||
selectedAlbum?.title || ''
|
selectedAlbum?.title || '',
|
||||||
|
selectedAlbum?.id,
|
||||||
|
selectedAlbum?.artistId
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -548,7 +550,9 @@
|
|||||||
hires: t.hires ?? false,
|
hires: t.hires ?? false,
|
||||||
bit_depth: t.bitDepth ?? null,
|
bit_depth: t.bitDepth ?? null,
|
||||||
sample_rate: t.samplingRate ?? null,
|
sample_rate: t.samplingRate ?? null,
|
||||||
is_local: false
|
is_local: false,
|
||||||
|
album_id: album.id,
|
||||||
|
artist_id: t.artistId ?? album.artistId
|
||||||
}));
|
}));
|
||||||
|
|
||||||
await setQueue(queueTracks, 0, true);
|
await setQueue(queueTracks, 0, true);
|
||||||
@@ -591,7 +595,9 @@
|
|||||||
hires: t.hires ?? false,
|
hires: t.hires ?? false,
|
||||||
bit_depth: t.bitDepth ?? null,
|
bit_depth: t.bitDepth ?? null,
|
||||||
sample_rate: t.samplingRate ?? null,
|
sample_rate: t.samplingRate ?? null,
|
||||||
is_local: false
|
is_local: false,
|
||||||
|
album_id: album.id,
|
||||||
|
artist_id: t.artistId ?? album.artistId
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
showToast(`Playing ${album.tracks.length} tracks next`, 'success');
|
showToast(`Playing ${album.tracks.length} tracks next`, 'success');
|
||||||
@@ -612,7 +618,9 @@
|
|||||||
hires: t.hires ?? false,
|
hires: t.hires ?? false,
|
||||||
bit_depth: t.bitDepth ?? null,
|
bit_depth: t.bitDepth ?? null,
|
||||||
sample_rate: t.samplingRate ?? null,
|
sample_rate: t.samplingRate ?? null,
|
||||||
is_local: false
|
is_local: false,
|
||||||
|
album_id: album.id,
|
||||||
|
artist_id: t.artistId ?? album.artistId
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const success = await addTracksToQueue(queueTracks);
|
const success = await addTracksToQueue(queueTracks);
|
||||||
@@ -743,7 +751,9 @@
|
|||||||
hires: t.hires ?? false,
|
hires: t.hires ?? false,
|
||||||
bit_depth: t.bitDepth ?? null,
|
bit_depth: t.bitDepth ?? null,
|
||||||
sample_rate: t.samplingRate ?? null,
|
sample_rate: t.samplingRate ?? null,
|
||||||
is_local: false
|
is_local: false,
|
||||||
|
album_id: selectedAlbum?.id,
|
||||||
|
artist_id: t.artistId ?? selectedAlbum?.artistId
|
||||||
}));
|
}));
|
||||||
|
|
||||||
console.log('[Album Queue] Mapped to', queueTracks.length, 'queue tracks, startIndex:', trackIndex);
|
console.log('[Album Queue] Mapped to', queueTracks.length, 'queue tracks, startIndex:', trackIndex);
|
||||||
@@ -1080,7 +1090,9 @@
|
|||||||
hires: t.hires ?? false,
|
hires: t.hires ?? false,
|
||||||
bit_depth: t.bitDepth ?? null,
|
bit_depth: t.bitDepth ?? null,
|
||||||
sample_rate: t.samplingRate ?? null,
|
sample_rate: t.samplingRate ?? null,
|
||||||
is_local: false
|
is_local: false,
|
||||||
|
album_id: selectedAlbum?.id,
|
||||||
|
artist_id: t.artistId ?? selectedAlbum?.artistId
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
showToast(`Playing ${selectedAlbum.tracks.length} tracks next`, 'success');
|
showToast(`Playing ${selectedAlbum.tracks.length} tracks next`, 'success');
|
||||||
@@ -1101,7 +1113,9 @@
|
|||||||
hires: t.hires ?? false,
|
hires: t.hires ?? false,
|
||||||
bit_depth: t.bitDepth ?? null,
|
bit_depth: t.bitDepth ?? null,
|
||||||
sample_rate: t.samplingRate ?? null,
|
sample_rate: t.samplingRate ?? null,
|
||||||
is_local: false
|
is_local: false,
|
||||||
|
album_id: selectedAlbum?.id,
|
||||||
|
artist_id: t.artistId ?? selectedAlbum?.artistId
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const success = await addTracksToQueue(queueTracks);
|
const success = await addTracksToQueue(queueTracks);
|
||||||
@@ -1529,7 +1543,9 @@
|
|||||||
hires: t.hires ?? false,
|
hires: t.hires ?? false,
|
||||||
bit_depth: t.bit_depth ?? null,
|
bit_depth: t.bit_depth ?? null,
|
||||||
sample_rate: t.sample_rate ?? null,
|
sample_rate: t.sample_rate ?? null,
|
||||||
is_local: t.is_local ?? false
|
is_local: t.is_local ?? false,
|
||||||
|
album_id: t.album_id ?? null,
|
||||||
|
artist_id: t.artist_id ?? null
|
||||||
}));
|
}));
|
||||||
|
|
||||||
await setQueue(tracks, session.current_index ?? 0, true);
|
await setQueue(tracks, session.current_index ?? 0, true);
|
||||||
|
|||||||
Reference in new issue
Block a user