feat(locallibrary): album/list play + source-aware auto-advance (playback Stage 2)

A Local Library album, or the Tracks list, now plays through with auto-advance
across mixed local/offline sources.

The one change to the shared playback path is additive and provably safe for
Qobuz: play_audible gains a guard at the top — when the CURRENT queue track's
source is "local" (and its id matches), it plays the file from disk via
play_local_file_audible (read -> player.play_data + CUE seek); otherwise it
falls through to the EXISTING offline/Qobuz tier-walk, byte-for-byte unchanged.
Qobuz/offline queue tracks never carry source "local", so their behavior cannot
change. Auto-advance, next/previous and play-all all route through play_audible,
so they become source-aware for free. current_track() releases the queue read
lock before play (no nested lock / deadlock).

- qbz-player: QueueManager::current() (additive).
- qbz-core: QbzCore::current_track() (additive).
- qbz-slint playback.rs: source-aware play_audible + play_local_file_audible
  (extracted) + play_local_tracks_now + play_local_album
  (get_album_tracks_metadata) + play_local_tracks_from (search_with_filter);
  replaces the Stage-1 single-track helper.
- main.rs: album card "play" -> play the album; Tracks row "play" -> play from
  that row down the searched list. (play-next / queue still stubbed.)

Built green (cargo check). Local-file gapless isn't wired (local tracks aren't
prefetched, so local/mixed transitions use the simple track-ended -> next path);
Qobuz gapless is unchanged. Runtime smoke-test pending: (1) Qobuz streaming
still plays + advances, (2) an offline album advances, (3) a local album/list
advances.

cc
This commit is contained in:
vicrodh committed 2026-05-29 00:50:40 -06:00
1 parent 5349c947a6
commit bcfab8e078
4 files changed
+148 -66

No files matched your search

+8
View File
@@ -65,6 +65,14 @@ impl QueueManager {
}
}
/// The track at the current playback index, if any.
pub fn current(&self) -> Option<QueueTrack> {
let state = self.state.lock().unwrap();
state
.current_index
.and_then(|idx| state.tracks.get(idx).cloned())
}
/// Add a track to the end of the queue
pub fn add_track(&self, track: QueueTrack) {
let mut state = self.state.lock().unwrap();