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
+10 -10
View File
@@ -76,7 +76,7 @@ func TestTheAudioDB_FetchAlbumCover_Success(t *testing.T) {
defer srv.Close()
p := newTheAudioDBProviderForTest(t, srv.URL)
body, err := p.FetchAlbumCover(context.Background(), "test-mbid")
body, err := p.FetchAlbumCover(context.Background(), AlbumRef{MBID: "test-mbid"})
if err != nil {
t.Fatalf("FetchAlbumCover err = %v, want nil", err)
}
@@ -93,7 +93,7 @@ func TestTheAudioDB_FetchAlbumCover_NotFound(t *testing.T) {
defer srv.Close()
p := newTheAudioDBProviderForTest(t, srv.URL)
_, err := p.FetchAlbumCover(context.Background(), "missing-mbid")
_, err := p.FetchAlbumCover(context.Background(), AlbumRef{MBID: "missing-mbid"})
if !errors.Is(err, ErrNotFound) {
t.Errorf("err = %v, want ErrNotFound", err)
}
@@ -107,7 +107,7 @@ func TestTheAudioDB_FetchAlbumCover_NullThumbURL(t *testing.T) {
defer srv.Close()
p := newTheAudioDBProviderForTest(t, srv.URL)
_, err := p.FetchAlbumCover(context.Background(), "mbid")
_, err := p.FetchAlbumCover(context.Background(), AlbumRef{MBID: "mbid"})
if !errors.Is(err, ErrNotFound) {
t.Errorf("err = %v, want ErrNotFound when thumb URL is null", err)
}
@@ -127,7 +127,7 @@ func TestTheAudioDB_FetchAlbumCover_429TriggersRetry(t *testing.T) {
defer srv.Close()
p := newTheAudioDBProviderForTest(t, srv.URL)
_, err := p.FetchAlbumCover(context.Background(), "mbid")
_, err := p.FetchAlbumCover(context.Background(), AlbumRef{MBID: "mbid"})
if attempts.Load() < 2 {
t.Errorf("attempts = %d, want >= 2 (retry should have run)", attempts.Load())
}
@@ -164,7 +164,7 @@ func TestTheAudioDB_FetchArtistArt_BothPresent(t *testing.T) {
defer srv.Close()
p := newTheAudioDBProviderForTest(t, srv.URL)
thumb, fanart, err := p.FetchArtistArt(context.Background(), "mbid")
thumb, fanart, err := p.FetchArtistArt(context.Background(), ArtistRef{MBID: "mbid"})
if err != nil {
t.Fatalf("err = %v", err)
}
@@ -193,7 +193,7 @@ func TestTheAudioDB_FetchArtistArt_ThumbOnly(t *testing.T) {
defer srv.Close()
p := newTheAudioDBProviderForTest(t, srv.URL)
thumb, fanart, err := p.FetchArtistArt(context.Background(), "mbid")
thumb, fanart, err := p.FetchArtistArt(context.Background(), ArtistRef{MBID: "mbid"})
if err != nil {
t.Fatalf("err = %v", err)
}
@@ -213,7 +213,7 @@ func TestTheAudioDB_FetchArtistArt_BothEmpty(t *testing.T) {
defer srv.Close()
p := newTheAudioDBProviderForTest(t, srv.URL)
_, _, err := p.FetchArtistArt(context.Background(), "mbid")
_, _, err := p.FetchArtistArt(context.Background(), ArtistRef{MBID: "mbid"})
if !errors.Is(err, ErrNotFound) {
t.Errorf("err = %v, want ErrNotFound", err)
}
@@ -241,7 +241,7 @@ func TestTheAudioDB_DefaultsToTestKeyOnEmpty(t *testing.T) {
t.Fatalf("Configure: %v", err)
}
_, _ = p.FetchAlbumCover(context.Background(), "mbid")
_, _ = p.FetchAlbumCover(context.Background(), AlbumRef{MBID: "mbid"})
}
func TestTheAudioDB_DisabledReturnsNotFound(t *testing.T) {
@@ -253,12 +253,12 @@ func TestTheAudioDB_DisabledReturnsNotFound(t *testing.T) {
p := newTheAudioDBProviderForTest(t, srv.URL)
p.enabled.Store(false)
_, err := p.FetchAlbumCover(context.Background(), "any")
_, err := p.FetchAlbumCover(context.Background(), AlbumRef{MBID: "any"})
if !errors.Is(err, ErrNotFound) {
t.Errorf("err = %v, want ErrNotFound (disabled)", err)
}
_, _, err = p.FetchArtistArt(context.Background(), "any")
_, _, err = p.FetchArtistArt(context.Background(), ArtistRef{MBID: "any"})
if !errors.Is(err, ErrNotFound) {
t.Errorf("artist err = %v, want ErrNotFound (disabled)", err)
}