feat: Library Only mode — toggle, search, artist page, similar artists
Backend: - Migration 17: similar_artist_map table stores per-artist similar artist relationships (source_mbid → similar_mbid + name + score) - Tier 4 index build now persists similar artists to this table - GetLibrarySimilarArtists(mbid) queries similar artists filtered by JOIN with the artists table (library-only, no API calls) - Added db field to explore.Service for direct queries Frontend: - ExploreSettingsStore with libraryOnly toggle, persisted to localStorage - Top bar toggle button with active/inactive styling - Explore search: skips full MB/LB pipeline when library-only, uses only searchLibraryCache (pure JS, instant) - Artist detail page: in library-only mode, skips all API calls (no top tracks, no top releases, no LB play count, no MB artist lookup). Uses library store for discography, calls GetLibrarySimilarArtists for similar artists. - Similar artists section: changed from horizontal scroll to wrapping flex layout with collapsible toggle (Show all N) - Removed debug artist ranking log
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* ExploreSettingsStore — global settings for the explore feature.
|
||||
* Persists to localStorage so the toggle state survives restarts.
|
||||
*/
|
||||
|
||||
type Listener = () => void;
|
||||
|
||||
class ExploreSettingsStore {
|
||||
private _libraryOnly: boolean;
|
||||
private listeners = new Set<Listener>();
|
||||
|
||||
constructor() {
|
||||
this._libraryOnly = localStorage.getItem('explore:libraryOnly') === 'true';
|
||||
}
|
||||
|
||||
get libraryOnly(): boolean {
|
||||
return this._libraryOnly;
|
||||
}
|
||||
|
||||
setLibraryOnly(value: boolean) {
|
||||
if (this._libraryOnly === value) return;
|
||||
this._libraryOnly = value;
|
||||
localStorage.setItem('explore:libraryOnly', String(value));
|
||||
this.notify();
|
||||
}
|
||||
|
||||
toggle() {
|
||||
this.setLibraryOnly(!this._libraryOnly);
|
||||
}
|
||||
|
||||
subscribe(fn: Listener): () => void {
|
||||
this.listeners.add(fn);
|
||||
return () => this.listeners.delete(fn);
|
||||
}
|
||||
|
||||
private notify() {
|
||||
for (const fn of this.listeners) fn();
|
||||
}
|
||||
}
|
||||
|
||||
export const exploreSettings = new ExploreSettingsStore();
|
||||
Reference in New Issue
Block a user