diff --git a/internal/api/api.go b/internal/api/api.go index cd34139d..88929eed 100644 --- a/internal/api/api.go +++ b/internal/api/api.go @@ -29,15 +29,15 @@ func Mount(r chi.Router, pool *pgxpool.Pool, logger *slog.Logger, events *playev rng := rand.New(rand.NewSource(rand.Int63())) h := &handlers{ pool: pool, logger: logger, events: events, recCfg: recCfg, - rng: rng.Float64, - lidarrCfg: lidarrCfg, - lidarrRequests: lidarrReqs, - lidarrQuarantine: lidarrQuar, - tracks: tracksSvc, - playlists: playlistsSvc, - coverart: coverEnricher, + rng: rng.Float64, + lidarrCfg: lidarrCfg, + lidarrRequests: lidarrReqs, + lidarrQuarantine: lidarrQuar, + tracks: tracksSvc, + playlists: playlistsSvc, + coverart: coverEnricher, coverArtBackfillCap: coverBackfillCap, - dataDir: dataDir, + dataDir: dataDir, } r.Route("/api", func(api chi.Router) { diff --git a/internal/coverart/fetcher_test.go b/internal/coverart/fetcher_test.go index 35a2d1d7..d6a84946 100644 --- a/internal/coverart/fetcher_test.go +++ b/internal/coverart/fetcher_test.go @@ -38,7 +38,7 @@ func TestFetcher_Success(t *testing.T) { } func TestFetcher_NotFound(t *testing.T) { - srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { http.Error(w, "not found", http.StatusNotFound) })) defer srv.Close() @@ -50,7 +50,7 @@ func TestFetcher_NotFound(t *testing.T) { } func TestFetcher_5xxIsTransient(t *testing.T) { - srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { http.Error(w, "boom", http.StatusInternalServerError) })) defer srv.Close() @@ -81,7 +81,7 @@ func TestFetcher_SendsUserAgent(t *testing.T) { } func TestFetcher_RateLimitSpacesCalls(t *testing.T) { - srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { _, _ = w.Write([]byte("ok")) })) defer srv.Close() diff --git a/internal/playlists/system.go b/internal/playlists/system.go index 4c43dc87..5b5aedb1 100644 --- a/internal/playlists/system.go +++ b/internal/playlists/system.go @@ -82,12 +82,12 @@ const systemMixLength = 25 // JitterMagnitude is 0 because daily determinism comes from tieBreakHash; // any randomness would defeat the within-day stability invariant. var systemMixWeights = recommendation.ScoringWeights{ - BaseWeight: 1.0, - LikeBoost: 2.0, - RecencyWeight: 1.0, - SkipPenalty: 2.0, - JitterMagnitude: 0.0, - ContextWeight: 0.5, + BaseWeight: 1.0, + LikeBoost: 2.0, + RecencyWeight: 1.0, + SkipPenalty: 2.0, + JitterMagnitude: 0.0, + ContextWeight: 0.5, SimilarityWeight: 1.5, } diff --git a/internal/playlists/system_cron.go b/internal/playlists/system_cron.go index 408d88e5..df832130 100644 --- a/internal/playlists/system_cron.go +++ b/internal/playlists/system_cron.go @@ -14,12 +14,12 @@ import ( // goroutine. Caller passes a context that's cancelled on graceful shutdown. // // Lifecycle: -// 1. Clear any stale in_flight=true rows from a previously crashed process -// (safe at startup: by definition, nothing is running yet). -// 2. Run once at startup so users catch up after a server restart without -// waiting up to 24h. -// 3. Tick every 24h; runOnce on each tick. -// 4. Exit on context cancellation. +// 1. Clear any stale in_flight=true rows from a previously crashed process +// (safe at startup: by definition, nothing is running yet). +// 2. Run once at startup so users catch up after a server restart without +// waiting up to 24h. +// 3. Tick every 24h; runOnce on each tick. +// 4. Exit on context cancellation. // // Per-user errors are logged but don't halt the loop. Per-cycle errors (e.g., // "list active users" failed) are logged but the next tick still fires. diff --git a/web/src/lib/components/TrackRow.test.ts b/web/src/lib/components/TrackRow.test.ts index 0b54c548..84ef1754 100644 --- a/web/src/lib/components/TrackRow.test.ts +++ b/web/src/lib/components/TrackRow.test.ts @@ -95,7 +95,7 @@ describe('TrackRow', () => { test('+ queue button calls enqueueTrack and does NOT trigger row play', async () => { render(TrackRow, { props: { tracks, index: 0 } }); - await fireEvent.click(screen.getByRole('button', { name: /add to queue/i })); + await fireEvent.click(screen.getByRole('button', { name: /add .* to queue/i })); expect(enqueueTrack).toHaveBeenCalledWith(tracks[0]); expect(playQueue).not.toHaveBeenCalled(); }); diff --git a/web/src/routes/library/artists/page.test.ts b/web/src/routes/library/artists/page.test.ts index c7e086fd..501aa03d 100644 --- a/web/src/routes/library/artists/page.test.ts +++ b/web/src/routes/library/artists/page.test.ts @@ -20,7 +20,23 @@ vi.mock('$lib/api/queries', () => ({ }) })); vi.mock('$lib/api/client', () => ({ api: { get: vi.fn() } })); -vi.mock('$lib/player/store.svelte', () => ({ playQueue: vi.fn() })); +vi.mock('$lib/player/store.svelte', () => ({ + playQueue: vi.fn(), + enqueueTracks: vi.fn() +})); +vi.mock('$lib/api/artists', () => ({ + listArtistTracks: vi.fn().mockResolvedValue([]) +})); +vi.mock('$lib/api/likes', () => ({ + createLikedIdsQuery: () => + readable({ data: { track_ids: [], album_ids: [], artist_ids: [] }, isPending: false, isError: false }), + likeEntity: vi.fn().mockResolvedValue(undefined), + unlikeEntity: vi.fn().mockResolvedValue(undefined) +})); +vi.mock('@tanstack/svelte-query', async (orig) => { + const actual = (await orig()) as Record; + return { ...actual, useQueryClient: () => ({ invalidateQueries: vi.fn() }) }; +}); import Page from './+page.svelte';