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:
+33
-14
@@ -26,6 +26,7 @@ type Service struct {
|
||||
artProxy *CoverArtProxy
|
||||
artistImg *ArtistImageProvider
|
||||
libMBID *LibraryMBIDIndex
|
||||
db *database.DB
|
||||
logger *slog.Logger
|
||||
ctx context.Context
|
||||
}
|
||||
@@ -61,6 +62,7 @@ func NewExploreService(logger *slog.Logger, db *database.DB) *Service {
|
||||
artProxy: artProxy,
|
||||
artistImg: artistImg,
|
||||
libMBID: libMBID,
|
||||
db: db,
|
||||
logger: logger,
|
||||
ctx: context.Background(),
|
||||
}
|
||||
@@ -235,6 +237,37 @@ func (e *Service) GetArtistPlayCount(artistMBID string) int {
|
||||
return pop[artistMBID]
|
||||
}
|
||||
|
||||
// GetLibrarySimilarArtists returns similar artists to the given
|
||||
// MBID that are also in the user's local library. Uses the
|
||||
// pre-computed similar_artist_map table (populated during Tier 4
|
||||
// index build) joined with the artists table. No API calls.
|
||||
func (e *Service) GetLibrarySimilarArtists(artistMBID string) []LBSimilarArtist {
|
||||
rows, err := e.db.QueryContext(`
|
||||
SELECT s.similar_artist_mbid, s.similar_artist_name, s.score
|
||||
FROM similar_artist_map s
|
||||
JOIN artists a ON a.mbid = s.similar_artist_mbid
|
||||
WHERE s.source_artist_mbid = ?
|
||||
ORDER BY s.score DESC
|
||||
`, artistMBID)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
defer func() { _ = rows.Close() }()
|
||||
|
||||
var result []LBSimilarArtist
|
||||
|
||||
for rows.Next() {
|
||||
var a LBSimilarArtist
|
||||
|
||||
if err := rows.Scan(&a.ArtistMBID, &a.Name, &a.Score); err == nil {
|
||||
result = append(result, a)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Cover Art Archive
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -582,20 +615,6 @@ func (e *Service) Search(query string) (*MBSearchResult, error) {
|
||||
// even when The Beatles have vastly more listens.
|
||||
e.boostNameMatches(query, &result)
|
||||
|
||||
// Debug: log artist scores before filtering.
|
||||
if len(result.Artists) > 0 {
|
||||
for i, a := range result.Artists {
|
||||
if i < 20 {
|
||||
e.logger.Info("search artist ranking",
|
||||
"pos", i+1,
|
||||
"name", a.Name,
|
||||
"score", a.Score,
|
||||
"mbid", a.MBID[:8],
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Phase 6: filter low-scoring results and cap counts.
|
||||
filterAndCap(&result)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user