feat: add artist images to similar artists section
After similar artists load, fetch images for each via GetArtistImageURL in parallel. Images pop in as they resolve — letter avatars remain as fallback for artists without images. Each image is cached on disk after first resolution, so subsequent views are instant.
This commit is contained in:
@@ -91,6 +91,7 @@ export class ExploreArtistDetails extends LitElement {
|
||||
@state() private similarArtists: LBSimilarArtist[] = [];
|
||||
@state() private loadingSimilar = true;
|
||||
@state() private artistImageURL = '';
|
||||
@state() private similarImageURLs = new Map<string, string>();
|
||||
private libraryMBIDs = new Set<string>();
|
||||
|
||||
/* ── Styles ── */
|
||||
@@ -474,6 +475,13 @@ export class ExploreArtistDetails extends LitElement {
|
||||
text-transform: uppercase;
|
||||
user-select: none;
|
||||
flex-shrink: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.similar-avatar img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.similar-name {
|
||||
@@ -587,6 +595,31 @@ export class ExploreArtistDetails extends LitElement {
|
||||
} finally {
|
||||
this.loadingSimilar = false;
|
||||
}
|
||||
|
||||
// Fire-and-forget: resolve images for similar artists in parallel.
|
||||
if (this.similarArtists.length > 0) {
|
||||
void this.fetchSimilarArtistImages();
|
||||
}
|
||||
}
|
||||
|
||||
private async fetchSimilarArtistImages() {
|
||||
const artists = this.similarArtists;
|
||||
// Fetch in parallel — each call is cached after first resolution.
|
||||
await Promise.allSettled(
|
||||
artists.map(async (a) => {
|
||||
try {
|
||||
const url = await GetArtistImageURL(a.artistMbid);
|
||||
if (url) {
|
||||
this.similarImageURLs = new Map(this.similarImageURLs).set(
|
||||
a.artistMbid,
|
||||
url,
|
||||
);
|
||||
}
|
||||
} catch {
|
||||
// No image — letter avatar stays.
|
||||
}
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
private async fetchArtistImage(mbid: string) {
|
||||
@@ -675,6 +708,12 @@ export class ExploreArtistDetails extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
/** On similar-artist image error, remove the img so the letter initial shows. */
|
||||
private handleSimilarImageError(e: Event) {
|
||||
const img = e.target as HTMLImageElement;
|
||||
img.remove();
|
||||
}
|
||||
|
||||
/* ── Helpers ── */
|
||||
|
||||
private getInitial(name: string): string {
|
||||
@@ -977,6 +1016,7 @@ export class ExploreArtistDetails extends LitElement {
|
||||
<div class="horizontal-row">
|
||||
${this.similarArtists.map((a) => {
|
||||
const hue = nameToHue(a.name);
|
||||
const imgURL = this.similarImageURLs.get(a.artistMbid);
|
||||
return html`
|
||||
<div
|
||||
class="similar-artist-card"
|
||||
@@ -997,7 +1037,13 @@ export class ExploreArtistDetails extends LitElement {
|
||||
class="similar-avatar"
|
||||
style="background: hsl(${hue}, 45%, 35%)"
|
||||
>
|
||||
${a.name.charAt(0).toUpperCase()}
|
||||
${imgURL
|
||||
? html`<img
|
||||
src="${imgURL}"
|
||||
alt="${a.name}"
|
||||
@error=${this.handleSimilarImageError}
|
||||
/>`
|
||||
: a.name.charAt(0).toUpperCase()}
|
||||
</div>
|
||||
<div
|
||||
class="similar-name"
|
||||
|
||||
Reference in New Issue
Block a user