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

@@ -19,6 +19,7 @@ component AlbumGrid inherits Rectangle {
in property <length> card-height: 266px;
in property <length> card-gap: 24px;
in property <bool> show-favorite: true;
in property <bool> show-source-badge: false;
callback open-album(string);
callback open-artist(string);
callback media-action(string, string, string);
@@ -38,6 +39,7 @@ component AlbumGrid inherits Rectangle {
height: root.card-height;
album: album;
show-favorite: root.show-favorite;
show-source-badge: root.show-source-badge;
clicked(id) => {
root.open-album(id);
}
@@ -60,6 +62,9 @@ export component AlbumCollectionView inherits VerticalLayout {
// Forwarded to AlbumCard — hide the favorite heart in non-favoritable
// contexts (Local Library albums).
in property <bool> show-favorite: true;
// Forwarded to AlbumCard — show the always-visible source badge on the
// grid card art (Local Library: local | qobuz-offline | plex).
in property <bool> show-source-badge: false;
in property <length> card-width: 220px;
in property <length> card-height: 266px;
in property <length> card-gap: 24px;
@@ -109,6 +114,7 @@ export component AlbumCollectionView inherits VerticalLayout {
if root.view-mode != "list": AlbumGrid {
albums: section.albums;
show-favorite: root.show-favorite;
show-source-badge: root.show-source-badge;
card-width: root.card-width;
card-height: root.card-height;
card-gap: root.card-gap;
@@ -129,6 +135,7 @@ export component AlbumCollectionView inherits VerticalLayout {
if !root.is-grouped && root.view-mode == "grid" && root.albums.length > 0: AlbumGrid {
albums: root.albums;
show-favorite: root.show-favorite;
show-source-badge: root.show-source-badge;
card-width: root.card-width;
card-height: root.card-height;
card-gap: root.card-gap;