fix(locallibrary): show offline/folder album covers + add source badge

Two fixes from the first Albums-grid test pass.

Offline/folder covers (the reported "cover exists in the folder but isn't
shown"): some albums — offline-cached CMAF bundles and folder downloads —
have no artwork_path in the index even though a cover.jpg sits in the track
folder (older offline-cache downloads didn't backfill it). Add a frontend-
agnostic LibraryDatabase::resolve_album_cover_fallback(group_key) that finds
a representative track, derives its folder (the path itself for a CMAF bundle
dir, else the parent), and returns <folder>/cover.jpg when it exists. The
Slint Albums mapper calls it whenever the album has no artwork. Verified
against the live index: it resolves the folder covers that exist on disk
(FLAC-layout + CMAF-with-cover). Older CMAF bundles that never downloaded a
cover (segments only) still show the placeholder — those need a cover
re-fetch (offline-cache maintenance), tracked separately.

Source badge: the Local Library album card now shows the always-visible
source badge inside the artwork (bottom-right) — a hard-drive glyph for local
files, the Qobuz logo for offline copies, the Plex logo for Plex. Added
AlbumCard.show-source-badge (default off; threaded through AlbumCollectionView
/AlbumGrid) + AlbumCard.source; album_map now carries the real source and
map_local_album maps user->local / qobuz_download / plex. Small rounded
square, not a pill (ADR-008). Logos copied into the Slint icon assets.

Built green (cargo check -p qbz-slint); runtime smoke-test pending.

cc
This commit is contained in:
vicrodh committed 2026-05-28 23:40:58 -06:00
1 parent 835a6cad85
commit 3fc724af84
8 files changed
+834 -8

No files matched your search

+26
View File
@@ -1958,6 +1958,32 @@ impl LibraryDatabase {
result
}
/// Resolve a folder cover for an album that has no `artwork_path` in the
/// index — e.g. an offline-cached (CMAF) album whose downloader wrote a
/// `cover.jpg` into the track folder but didn't backfill `artwork_path`.
/// Looks up a representative track for the metadata group, derives its
/// containing folder (the path itself when it is a directory, as for CMAF
/// bundles, else the parent dir), and returns `<folder>/cover.jpg` when
/// that file exists. Frontend-agnostic (no `tauri::State`).
pub fn resolve_album_cover_fallback(&self, group_key: &str) -> Option<String> {
let expr = crate::album_grouping::metadata_group_key_sql_expression();
let query = format!("SELECT file_path FROM local_tracks WHERE ({expr}) = ?1 LIMIT 1");
let file_path: String = self
.conn
.query_row(&query, rusqlite::params![group_key], |row| row.get(0))
.ok()?;
let p = std::path::Path::new(&file_path);
let folder = if p.is_dir() {
p.to_path_buf()
} else {
p.parent()?.to_path_buf()
};
let cover = folder.join("cover.jpg");
cover
.is_file()
.then(|| cover.to_string_lossy().into_owned())
}
fn get_albums_metadata_page_inner(
&self,
offset: u64,