Files
yellowjacket/frontend/src/store/explore-cache.ts
T
yonlu 8096b28d17 feat: MBIDs in library models + local-first search + explore cache
Backend:
- Added mbid column to sqlc schemas for artists and release_groups
- Regenerated sqlc queries to SELECT mbid in artist/album queries
- Added MBID field to library.Artist and library.Album Go structs
- All GetAllArtists/GetAllAlbums variants now populate MBID

Frontend:
- Updated Wails models.ts with MBID fields on Artist and Album
- Added cachedArtists/cachedAlbums getters to LibraryStore
- searchLibraryCache now includes MBIDs and local cover art URLs
  so library results can navigate to explore detail pages
- Added mergeWithLibrary() — when full MB results arrive, library
  entries are enriched with local images and 'In Library' flags
  rather than being replaced by MB-only versions
- Created ExploreCache store for cross-page data sharing: search
  results populate the cache, detail pages can read from it to
  avoid redundant API calls for already-fetched data
2026-03-29 18:54:22 -04:00

108 lines
3.1 KiB
TypeScript

/**
* ExploreCache — a simple in-memory cache for explore data that
* persists across page navigations within a session. Populated by
* search results and consumed by detail pages to avoid redundant
* API calls.
*
* Data flows:
* search results → cache artist images, album art, release groups
* artist detail page → check cache before API calls
* album detail page → check cache before API calls
*/
import type { MBReleaseGroup, LBTopRecording } from '@go/explore/Service';
/** Cached artist data from search results. */
export interface CachedArtist {
mbid: string;
name: string;
imageURL?: string; // resolved artist image
imageSmall?: string; // library small image
imageMedium?: string; // library medium image
}
/** Cached album data from search results. */
export interface CachedAlbum {
mbid: string;
title: string;
artistName: string;
coverArt?: string; // local cover art URL
year?: string;
}
class ExploreCacheStore {
private artists = new Map<string, CachedArtist>();
private albums = new Map<string, CachedAlbum>();
private artistAlbums = new Map<string, MBReleaseGroup[]>();
private artistTopTracks = new Map<string, LBTopRecording[]>();
// -- Artists --
setArtist(mbid: string, data: CachedArtist) {
if (mbid) this.artists.set(mbid, data);
}
getArtist(mbid: string): CachedArtist | undefined {
return this.artists.get(mbid);
}
// -- Albums --
setAlbum(mbid: string, data: CachedAlbum) {
if (mbid) this.albums.set(mbid, data);
}
getAlbum(mbid: string): CachedAlbum | undefined {
return this.albums.get(mbid);
}
// -- Artist → Albums (release groups) --
setArtistAlbums(artistMBID: string, albums: MBReleaseGroup[]) {
if (artistMBID) this.artistAlbums.set(artistMBID, albums);
}
getArtistAlbums(artistMBID: string): MBReleaseGroup[] | undefined {
return this.artistAlbums.get(artistMBID);
}
// -- Artist → Top tracks --
setArtistTopTracks(artistMBID: string, tracks: LBTopRecording[]) {
if (artistMBID) this.artistTopTracks.set(artistMBID, tracks);
}
getArtistTopTracks(artistMBID: string): LBTopRecording[] | undefined {
return this.artistTopTracks.get(artistMBID);
}
// -- Bulk populate from search results --
populateFromSearch(artists: any[], releaseGroups: any[]) {
for (const a of artists) {
if (a.mbid) {
this.setArtist(a.mbid, {
mbid: a.mbid,
name: a.name,
imageSmall: a._imageSmall,
imageMedium: a._imageMedium,
});
}
}
for (const rg of releaseGroups) {
if (rg.mbid) {
this.setAlbum(rg.mbid, {
mbid: rg.mbid,
title: rg.title,
artistName: rg.artistCredit || '',
coverArt: rg._coverArt,
year: rg.firstReleaseDate,
});
}
}
}
}
export const exploreCache = new ExploreCacheStore();