fix(player): attach a cover to queued rows that were enqueued without one

The sibling of patch_plex_quality, for the other thing a row can learn after it
was enqueued. A disc carries no artwork — it is fetched, and the fetch outlives
the click that started playback — so a CD queued at second two is still holding
artwork_url: None when the cover lands at second ten. Every consumer downstream
reads the QUEUE row (the now-playing bar, the miniplayer, MPRIS through
art_url_for), so patching the session store alone left all of them blank.

Rows that already have art are left alone: this fills a gap rather than
overwriting a cover somebody else resolved. It answers two questions
separately, because they drive different work — any patch makes the queue
panel's thumbnails stale, only the current one needs the now-playing stamp
re-pushed.

cc
This commit is contained in:
vicrodh committed 2026-08-21 18:57:42 -06:00
1 parent b6deec0aaf
commit b38d6bd867
2 files changed
+59

No files matched your search

+17
View File
@@ -902,6 +902,23 @@ impl<A: FrontendAdapter + Send + Sync + 'static> QbzCore<A> {
current_patched
}
/// Attach a resolved cover to any queued track in `ids` that has none.
/// Frontend-agnostic hook for art that resolves AFTER the row was
/// enqueued — a disc's cover is fetched, and the fetch outlives the click
/// that started playback. Returns true if the CURRENT track was patched;
/// the caller then re-pushes the now-playing stamp.
pub async fn patch_queue_artwork(&self, ids: &[u64], url: &str) -> bool {
let queue = self.queue.write().await;
let (any, current_patched) = queue.patch_artwork(ids, url);
if any {
self.emit(CoreEvent::QueueUpdated {
state: queue.get_state(),
})
.await;
}
current_patched
}
// ==================== Search & Catalog ====================
/// Search for albums
+42
View File
@@ -119,6 +119,48 @@ impl QueueManager {
current_patched
}
/// Attach an artwork url to every queued track whose id is in `ids`.
///
/// The sibling of [`Self::patch_plex_quality`], for the other thing a row
/// can learn AFTER it was enqueued: a cover. A disc carries none — it is
/// fetched, and the fetch outlives the click that started playback — so a
/// CD queued at second two is still holding `artwork_url: None` when the
/// cover lands at second ten. Every consumer downstream reads the QUEUE
/// row (the now-playing bar, the miniplayer, MPRIS through
/// `art_url_for`), so patching the session store alone leaves all of them
/// blank.
///
/// Rows that already have art are left alone: this fills a gap, it does
/// not overwrite a cover somebody else resolved.
///
/// Returns `(any patched, the CURRENT track was patched)`. The two are
/// separate answers because they drive different work: any patch makes the
/// queue panel's thumbnails stale, while only the current one needs the
/// now-playing stamp re-pushed.
pub fn patch_artwork(&self, ids: &[u64], url: &str) -> (bool, bool) {
if ids.is_empty() || url.is_empty() {
return (false, false);
}
let mut state = self.state.lock().unwrap();
let current_idx = state.current_index;
let mut any = false;
let mut current_patched = false;
for (idx, track) in state.tracks.iter_mut().enumerate() {
if track.artwork_url.as_deref().is_some_and(|u| !u.is_empty()) {
continue;
}
if !ids.contains(&track.id) {
continue;
}
track.artwork_url = Some(url.to_string());
any = true;
if current_idx == Some(idx) {
current_patched = true;
}
}
(any, current_patched)
}
/// Add a track to the end of the queue
pub fn add_track(&self, track: QueueTrack) {
let mut state = self.state.lock().unwrap();