refactor(server/coverart): provider interface takes ArtistRef/AlbumRef

Changes the AlbumCoverProvider and ArtistArtProvider interfaces from
MBID-only string parameters to ref-struct signatures so name-based
providers (Deezer, Last.fm in upcoming tasks) can act on rows
without MBIDs.

Today, 53 of 213 artists in the dev DB have NULL MBIDs — featured
artists, remixers, and compilation contributors created from
track-tag splits where the primary-artist MBID is in the file but
collaborator IDs aren't. These rows are unreachable by the current
MBID-only chain. Refactoring the interface unblocks future
name-based providers from acting on them.

TheAudioDB and MBCAA keep MBID-only behavior internally: they return
ErrNotFound when ref.MBID is empty rather than attempting a
name-based fallback. The MBID guard inside EnrichAlbum/EnrichArtist
is removed; providers receive the ref unconditionally and decide
whether they can act on it.

GetAlbumWithFirstTrackPath now JOINs artists to return artist_name
alongside the existing fields, supporting AlbumRef construction.

No behavioral change today (only TheAudioDB + MBCAA registered, both
keep MBID-only behavior). The change unblocks T3 (Deezer) and T4
(Last.fm) which can now register and act on every artist/album
regardless of MBID presence.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-07 07:44:34 -04:00
parent 9a705d0ba4
commit 425f12db38
13 changed files with 99 additions and 58 deletions
+30 -11
View File
@@ -50,26 +50,45 @@ type ProviderSettings struct {
APIKey string
}
// ArtistRef is the lookup key passed to ArtistArtProvider.FetchArtistArt.
// MBID is preferred when present; Name is the always-populated fallback
// for providers that support name-based search (Deezer, Last.fm).
// MBID-only providers (TheAudioDB) return ErrNotFound when MBID is empty.
type ArtistRef struct {
MBID string
Name string
}
// AlbumRef is the lookup key passed to AlbumCoverProvider.FetchAlbumCover.
// Same MBID-preferred semantics as ArtistRef; ArtistName + AlbumTitle
// support name-based providers.
type AlbumRef struct {
MBID string
ArtistName string
AlbumTitle string
}
// AlbumCoverProvider is an opt-in capability: providers implementing
// it can fetch album cover art by MusicBrainz release MBID.
// it can fetch album cover art. MBID-only providers use ref.MBID and
// return ErrNotFound when it is empty; name-based providers (Deezer,
// Last.fm) fall back to ref.ArtistName + ref.AlbumTitle.
type AlbumCoverProvider interface {
Provider
// FetchAlbumCover returns the image bytes for the given release
// MBID, or ErrNotFound (terminal — no art available) /
// FetchAlbumCover returns the image bytes for the given album ref,
// or ErrNotFound (terminal — no art available) /
// ErrTransient (retry-eligible failure).
FetchAlbumCover(ctx context.Context, mbid string) ([]byte, error)
FetchAlbumCover(ctx context.Context, ref AlbumRef) ([]byte, error)
}
// ArtistArtProvider is an opt-in capability: providers implementing
// it can fetch artist images by MusicBrainz artist MBID. Returns
// thumb + fanart atomically at the JSON metadata step (one round-
// trip yields both URLs); the two image GETs are independent —
// partial success returns whatever bytes landed and the source is
// still stamped, so the enricher persists asymmetric results
// (thumb-only or fanart-only) gracefully.
// it can fetch artist images. Returns thumb + fanart atomically at
// the JSON metadata step (one round-trip yields both URLs); the two
// image GETs are independent — partial success returns whatever bytes
// landed and the source is still stamped, so the enricher persists
// asymmetric results (thumb-only or fanart-only) gracefully.
type ArtistArtProvider interface {
Provider
FetchArtistArt(ctx context.Context, mbid string) (thumb, fanart []byte, err error)
FetchArtistArt(ctx context.Context, ref ArtistRef) (thumb, fanart []byte, err error)
}
// TestableProvider is an opt-in capability: providers that can answer