fix(server,web/m7-353): post-review fixes (test compilation, AlbumRef field, bulk handler, design system)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-04 15:21:24 -04:00
parent 28617df5bd
commit 4e3bd46d69
7 changed files with 17 additions and 19 deletions
+1 -8
View File
@@ -57,18 +57,11 @@ type adminBulkRefetchResp struct {
// the configured backfill cap. // the configured backfill cap.
func (h *handlers) handleAdminBulkRefetchCovers(w http.ResponseWriter, r *http.Request) { func (h *handlers) handleAdminBulkRefetchCovers(w http.ResponseWriter, r *http.Request) {
cap := h.coverArtBackfillCap 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() { go func() {
bgCtx := context.Background() bgCtx := context.Background()
if _, err := h.coverart.EnrichRetryMissing(bgCtx, cap); err != nil { if _, err := h.coverart.EnrichRetryMissing(bgCtx, cap); err != nil {
h.logger.Warn("admin: bulk cover refetch failed", "err", err) 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})
} }
+2 -2
View File
@@ -110,8 +110,8 @@ func TestAdminBulkRefetchCovers_AdminReturnsQueuedCount(t *testing.T) {
if err := json.Unmarshal(w.Body.Bytes(), &resp); err != nil { if err := json.Unmarshal(w.Body.Bytes(), &resp); err != nil {
t.Fatalf("decode: %v", err) t.Fatalf("decode: %v", err)
} }
if resp.Queued < 2 { if resp.Queued != h.coverArtBackfillCap {
t.Errorf("queued = %d, want >= 2", resp.Queued) t.Errorf("queued = %d, want %d (cap)", resp.Queued, h.coverArtBackfillCap)
} }
} }
+2 -1
View File
@@ -113,7 +113,8 @@ func albumRefFrom(a dbq.Album, artistName string, trackCount, durationSec int) A
Year: yearFromDate(a.ReleaseDate), Year: yearFromDate(a.ReleaseDate),
TrackCount: trackCount, TrackCount: trackCount,
DurationSec: durationSec, DurationSec: durationSec,
CoverURL: coverURL(a.ID), CoverURL: coverURL(a.ID),
CoverArtSource: a.CoverArtSource,
} }
} }
+4 -3
View File
@@ -13,6 +13,7 @@ import (
"github.com/jackc/pgx/v5/pgtype" "github.com/jackc/pgx/v5/pgtype"
"github.com/jackc/pgx/v5/pgxpool" "github.com/jackc/pgx/v5/pgxpool"
"git.fabledsword.com/bvandeusen/minstrel/internal/coverart"
"git.fabledsword.com/bvandeusen/minstrel/internal/db/dbq" "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 { if err := os.WriteFile(filepath.Join(dir, "folder.jpg"), []byte("f"), 0o644); err != nil {
t.Fatal(err) 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") { if got != filepath.Join(dir, "cover.jpg") {
t.Errorf("got %q, want cover.jpg path", got) 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 { if err := os.WriteFile(filepath.Join(dir, "folder.png"), []byte("f"), 0o644); err != nil {
t.Fatal(err) 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") { if got != filepath.Join(dir, "folder.png") {
t.Errorf("got %q, want folder.png path", got) 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) { func TestFindSidecarCover_NoneFound(t *testing.T) {
dir := t.TempDir() 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) t.Errorf("got %q, want empty string", got)
} }
} }
+2 -1
View File
@@ -65,7 +65,8 @@ type AlbumRef struct {
Year int `json:"year,omitempty"` Year int `json:"year,omitempty"`
TrackCount int `json:"track_count"` TrackCount int `json:"track_count"`
DurationSec int `json:"duration_sec"` 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. // TrackRef is the lightweight track shape used in album details and search.
+5 -3
View File
@@ -4,6 +4,8 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"testing" "testing"
"git.fabledsword.com/bvandeusen/minstrel/internal/coverart"
) )
func TestFindSidecarCover(t *testing.T) { func TestFindSidecarCover(t *testing.T) {
@@ -14,7 +16,7 @@ func TestFindSidecarCover(t *testing.T) {
} }
// Empty dir first: no cover. // 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) 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 { if err := os.WriteFile(folder, []byte("jpg"), 0o644); err != nil {
t.Fatal(err) 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) t.Errorf("folder.jpg fallback = %q, want %q", got, folder)
} }
cover := filepath.Join(dir, "cover.jpg") cover := filepath.Join(dir, "cover.jpg")
if err := os.WriteFile(cover, []byte("jpg"), 0o644); err != nil { if err := os.WriteFile(cover, []byte("jpg"), 0o644); err != nil {
t.Fatal(err) 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) t.Errorf("cover.jpg priority = %q, want %q", got, cover)
} }
} }
+1 -1
View File
@@ -286,7 +286,7 @@
type="button" type="button"
onclick={onBulkRefetch} onclick={onBulkRefetch}
disabled={bulkBusy} 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'} {bulkBusy ? 'Queueing…' : 'Refetch missing covers'}
</button> </button>