diff --git a/frontend/src/components/explore-artist-details/explore-artist-details.ts b/frontend/src/components/explore-artist-details/explore-artist-details.ts index c252f89..2f52f43 100644 --- a/frontend/src/components/explore-artist-details/explore-artist-details.ts +++ b/frontend/src/components/explore-artist-details/explore-artist-details.ts @@ -773,15 +773,26 @@ export class ExploreArtistDetails extends LitElement { * Shows cached data instantly before API calls complete. */ private hydrateFromCache(mbid: string) { - // Artist image from explore cache (populated by search results). - const cachedArtist = exploreCache.getArtist(mbid); - if (cachedArtist) { - if (cachedArtist.imageURL) { - this.artistImageURL = cachedArtist.imageURL; - } else if (cachedArtist.imageMedium) { - this.artistImageURL = cachedArtist.imageMedium; - } else if (cachedArtist.imageSmall) { - this.artistImageURL = cachedArtist.imageSmall; + // Artist image: check explore cache first, then library store. + if (!this.artistImageURL) { + const cachedArtist = exploreCache.getArtist(mbid); + if (cachedArtist) { + this.artistImageURL = cachedArtist.imageURL + || cachedArtist.imageMedium + || cachedArtist.imageSmall + || ''; + } + } + + if (!this.artistImageURL) { + const cachedArtists = libraryStore.cachedArtists; + if (cachedArtists) { + for (const a of cachedArtists) { + if (a.MBID === mbid) { + this.artistImageURL = a.ImageMedium || a.ImageSmall || ''; + break; + } + } } } @@ -930,6 +941,30 @@ export class ExploreArtistDetails extends LitElement { } private async checkLibrary() { + // Check frontend-side first. + const cachedAlbums = libraryStore.cachedAlbums; + if (cachedAlbums) { + const localMBIDs = new Set(); + for (const a of cachedAlbums) { + if (a.MBID) localMBIDs.add(a.MBID); + } + + let updated = false; + + for (const rg of this.releaseGroups) { + if (rg.mbid && localMBIDs.has(rg.mbid)) { + this.libraryMBIDs.add(rg.mbid); + updated = true; + } + } + + if (updated) { + this.requestUpdate(); + return; + } + } + + // Fallback to backend. const mbids: string[] = []; for (const rg of this.releaseGroups) { diff --git a/frontend/src/components/explore-view/explore-view.ts b/frontend/src/components/explore-view/explore-view.ts index 9e4aafd..fdf6185 100644 --- a/frontend/src/components/explore-view/explore-view.ts +++ b/frontend/src/components/explore-view/explore-view.ts @@ -858,7 +858,27 @@ export class ExploreView extends LitElement { return; } - // Collect MBIDs that need fetching. + // Seed thumbnails from library album cover art (instant, no API). + const cachedAlbums = libraryStore.cachedAlbums; + if (cachedAlbums) { + const libAlbumsByMBID = new Map(); + for (const a of cachedAlbums) { + if (a.MBID && (a.CoverArtMedium || a.CoverArtSmall)) { + libAlbumsByMBID.set(a.MBID, a.CoverArtMedium || a.CoverArtSmall); + } + } + + for (const rg of this.results.releaseGroups) { + if (!this.thumbnailCache.has(rg.mbid)) { + const localArt = libAlbumsByMBID.get(rg.mbid) || (rg as any)._coverArt; + if (localArt) { + this.thumbnailCache.set(rg.mbid, localArt); + } + } + } + } + + // Collect MBIDs that still need fetching from the API. const requests: ThumbnailRequest[] = []; for (const rg of this.results.releaseGroups) { @@ -917,7 +937,29 @@ export class ExploreView extends LitElement { private async loadArtistImages() { if (!this.results?.artists?.length) return; - // Load sequentially to avoid hammering the MB rate limiter. + // Seed from library store first (instant, no API). + const cachedArtists = libraryStore.cachedArtists; + if (cachedArtists) { + const libByMBID = new Map(); + for (const a of cachedArtists) { + if (a.MBID && (a.ImageMedium || a.ImageSmall)) { + libByMBID.set(a.MBID, a.ImageMedium || a.ImageSmall); + } + } + + for (const a of this.results.artists) { + if (!this.artistImageCache.has(a.mbid) && a.mbid) { + const local = libByMBID.get(a.mbid) || (a as any)._imageMedium || (a as any)._imageSmall; + if (local) { + this.artistImageCache.set(a.mbid, local); + } + } + } + + this.requestUpdate(); + } + + // Fetch remaining from API (only artists not yet resolved). for (const a of this.results.artists) { if (this.artistImageCache.has(a.mbid)) continue; @@ -942,14 +984,50 @@ export class ExploreView extends LitElement { private async checkLibrary() { if (!this.results) return; - const mbids: string[] = []; + // Check frontend-side first using library store MBIDs. + const cachedArtists = libraryStore.cachedArtists; + const cachedAlbums = libraryStore.cachedAlbums; + const localMBIDs = new Set(); + + if (cachedArtists) { + for (const a of cachedArtists) { + if (a.MBID) localMBIDs.add(a.MBID); + } + } + + if (cachedAlbums) { + for (const a of cachedAlbums) { + if (a.MBID) localMBIDs.add(a.MBID); + } + } + + let updated = false; for (const a of this.results.artists ?? []) { - if (a.mbid) mbids.push(a.mbid); + if (a.mbid && localMBIDs.has(a.mbid)) { + this.libraryMBIDs.add(a.mbid); + updated = true; + } } for (const rg of this.results.releaseGroups ?? []) { - if (rg.mbid) mbids.push(rg.mbid); + if (rg.mbid && localMBIDs.has(rg.mbid)) { + this.libraryMBIDs.add(rg.mbid); + updated = true; + } + } + + if (updated) { + this.requestUpdate(); + return; + } + + // Fallback to backend check for recordings and edge cases + // (recordings aren't in the library store cache). + const mbids: string[] = []; + + for (const r of this.results.recordings ?? []) { + if (r.mbid) mbids.push(r.mbid); } if (mbids.length === 0) return;