feat: album art fallback for artists without images

When no artist image is available from any source (library store,
explore cache, MB/Wikidata API), fall back to using the artist's
most popular album's cover art. Uses local library data first.

Applied in three contexts:

1. Search results (explore-view):
   - After library image seed: checks library albums by artist name
   - After API fetch loop: final fallback for unresolved artists
   - Library-only search: checks album art in the seed pass

2. Artist detail page header (explore-artist-details):
   - In hydrateFromCache: checks library albums after image sources
   - After fetchArtistImage API call: fallback if API returned nothing

The album art is displayed as a circular crop in the artist avatar,
which naturally looks like an artist photo — no visual distinction
needed.
This commit is contained in:
2026-03-30 16:42:25 -04:00
parent cec69dede2
commit 9adebad31d
2 changed files with 93 additions and 1 deletions
@@ -818,6 +818,23 @@ export class ExploreArtistDetails extends LitElement {
this.loadingReleases = false;
}
}
// Fallback: use album cover art if no artist image found.
if (!this.artistImageURL && cachedAlbums) {
const artistName = this.artistName.toLowerCase();
for (const a of cachedAlbums) {
if (a.ArtistName.toLowerCase() === artistName) {
const art = a.CoverArtMedium || a.CoverArtSmall || a.CoverArtPath;
if (art) {
this.artistImageURL = art;
break;
}
}
}
}
}
private async fetchArtist(mbid: string) {
@@ -925,7 +942,27 @@ export class ExploreArtistDetails extends LitElement {
this.artistImageURL = url;
}
} catch {
// No image available — avatar stays as initial letter.
// No image available.
}
// Fallback: album cover art if no artist image resolved.
if (!this.artistImageURL) {
const cachedAlbums = libraryStore.cachedAlbums;
if (cachedAlbums) {
const artistName = this.artistName.toLowerCase();
for (const a of cachedAlbums) {
if (a.ArtistName.toLowerCase() === artistName) {
const art = a.CoverArtMedium || a.CoverArtSmall;
if (art) {
this.artistImageURL = art;
break;
}
}
}
}
}
}