diff --git a/internal/api/admin_covers.go b/internal/api/admin_covers.go index 2090c177..ca725e95 100644 --- a/internal/api/admin_covers.go +++ b/internal/api/admin_covers.go @@ -57,18 +57,11 @@ type adminBulkRefetchResp struct { // the configured backfill cap. func (h *handlers) handleAdminBulkRefetchCovers(w http.ResponseWriter, r *http.Request) { cap := h.coverArtBackfillCap - q := dbq.New(h.pool) - rows, err := q.ListAlbumsRetryMissing(r.Context(), int32(cap)) - if err != nil { - h.logger.Error("admin: bulk count failed", "err", err) - writeErr(w, http.StatusInternalServerError, "server_error", "count failed") - return - } go func() { bgCtx := context.Background() if _, err := h.coverart.EnrichRetryMissing(bgCtx, cap); err != nil { h.logger.Warn("admin: bulk cover refetch failed", "err", err) } }() - writeJSON(w, http.StatusOK, adminBulkRefetchResp{Queued: len(rows)}) + writeJSON(w, http.StatusOK, adminBulkRefetchResp{Queued: cap}) } diff --git a/internal/api/admin_covers_test.go b/internal/api/admin_covers_test.go index ee2202f5..28f197e7 100644 --- a/internal/api/admin_covers_test.go +++ b/internal/api/admin_covers_test.go @@ -110,8 +110,8 @@ func TestAdminBulkRefetchCovers_AdminReturnsQueuedCount(t *testing.T) { if err := json.Unmarshal(w.Body.Bytes(), &resp); err != nil { t.Fatalf("decode: %v", err) } - if resp.Queued < 2 { - t.Errorf("queued = %d, want >= 2", resp.Queued) + if resp.Queued != h.coverArtBackfillCap { + t.Errorf("queued = %d, want %d (cap)", resp.Queued, h.coverArtBackfillCap) } } diff --git a/internal/api/convert.go b/internal/api/convert.go index 88511003..af7312b1 100644 --- a/internal/api/convert.go +++ b/internal/api/convert.go @@ -113,7 +113,8 @@ func albumRefFrom(a dbq.Album, artistName string, trackCount, durationSec int) A Year: yearFromDate(a.ReleaseDate), TrackCount: trackCount, DurationSec: durationSec, - CoverURL: coverURL(a.ID), + CoverURL: coverURL(a.ID), + CoverArtSource: a.CoverArtSource, } } diff --git a/internal/api/media_test.go b/internal/api/media_test.go index 8be7b433..050c2196 100644 --- a/internal/api/media_test.go +++ b/internal/api/media_test.go @@ -13,6 +13,7 @@ import ( "github.com/jackc/pgx/v5/pgtype" "github.com/jackc/pgx/v5/pgxpool" + "git.fabledsword.com/bvandeusen/minstrel/internal/coverart" "git.fabledsword.com/bvandeusen/minstrel/internal/db/dbq" ) @@ -62,7 +63,7 @@ func TestFindSidecarCover_PrefersCoverOverFolder(t *testing.T) { if err := os.WriteFile(filepath.Join(dir, "folder.jpg"), []byte("f"), 0o644); err != nil { t.Fatal(err) } - got := findSidecarCover(filepath.Join(dir, "any-track.flac")) + got := coverart.FindSidecar(filepath.Dir(filepath.Join(dir, "any-track.flac"))) if got != filepath.Join(dir, "cover.jpg") { t.Errorf("got %q, want cover.jpg path", got) } @@ -73,7 +74,7 @@ func TestFindSidecarCover_FallsBackToFolder(t *testing.T) { if err := os.WriteFile(filepath.Join(dir, "folder.png"), []byte("f"), 0o644); err != nil { t.Fatal(err) } - got := findSidecarCover(filepath.Join(dir, "t.flac")) + got := coverart.FindSidecar(filepath.Dir(filepath.Join(dir, "t.flac"))) if got != filepath.Join(dir, "folder.png") { t.Errorf("got %q, want folder.png path", got) } @@ -81,7 +82,7 @@ func TestFindSidecarCover_FallsBackToFolder(t *testing.T) { func TestFindSidecarCover_NoneFound(t *testing.T) { dir := t.TempDir() - if got := findSidecarCover(filepath.Join(dir, "t.flac")); got != "" { + if got := coverart.FindSidecar(filepath.Dir(filepath.Join(dir, "t.flac"))); got != "" { t.Errorf("got %q, want empty string", got) } } diff --git a/internal/api/types.go b/internal/api/types.go index 8fa0ec5c..5b2de48e 100644 --- a/internal/api/types.go +++ b/internal/api/types.go @@ -65,7 +65,8 @@ type AlbumRef struct { Year int `json:"year,omitempty"` TrackCount int `json:"track_count"` DurationSec int `json:"duration_sec"` - CoverURL string `json:"cover_url"` + CoverURL string `json:"cover_url"` + CoverArtSource *string `json:"cover_art_source"` } // TrackRef is the lightweight track shape used in album details and search. diff --git a/internal/subsonic/stream_test.go b/internal/subsonic/stream_test.go index 9452913a..613943e7 100644 --- a/internal/subsonic/stream_test.go +++ b/internal/subsonic/stream_test.go @@ -4,6 +4,8 @@ import ( "os" "path/filepath" "testing" + + "git.fabledsword.com/bvandeusen/minstrel/internal/coverart" ) func TestFindSidecarCover(t *testing.T) { @@ -14,7 +16,7 @@ func TestFindSidecarCover(t *testing.T) { } // Empty dir first: no cover. - if got := findSidecarCover(track); got != "" { + if got := coverart.FindSidecar(filepath.Dir(track)); got != "" { t.Errorf("no sidecar → %q, want empty", got) } @@ -24,14 +26,14 @@ func TestFindSidecarCover(t *testing.T) { if err := os.WriteFile(folder, []byte("jpg"), 0o644); err != nil { t.Fatal(err) } - if got := findSidecarCover(track); got != folder { + if got := coverart.FindSidecar(filepath.Dir(track)); got != folder { t.Errorf("folder.jpg fallback = %q, want %q", got, folder) } cover := filepath.Join(dir, "cover.jpg") if err := os.WriteFile(cover, []byte("jpg"), 0o644); err != nil { t.Fatal(err) } - if got := findSidecarCover(track); got != cover { + if got := coverart.FindSidecar(filepath.Dir(track)); got != cover { t.Errorf("cover.jpg priority = %q, want %q", got, cover) } } diff --git a/web/src/routes/admin/+page.svelte b/web/src/routes/admin/+page.svelte index 2fd185bc..f715a13f 100644 --- a/web/src/routes/admin/+page.svelte +++ b/web/src/routes/admin/+page.svelte @@ -286,7 +286,7 @@ type="button" onclick={onBulkRefetch} disabled={bulkBusy} - class="mt-3 rounded-md bg-accent px-4 py-2 text-sm font-medium text-text-primary disabled:opacity-50" + class="mt-3 flex h-8 items-center gap-1 rounded-md bg-action-primary px-4 text-sm text-action-fg hover:opacity-90 disabled:opacity-50" > {bulkBusy ? 'Queueing…' : 'Refetch missing covers'}