Files
Psychotoxical-psysonic/src/cover/resolveEntry.test.ts
T
cucadmuh 42aec6720c fix(cover): stop per-song over-fetch + log failed cover downloads (#944)
* fix(cover): stop per-song cover over-fetch (album/mf-* explosion)

album_has_distinct_disc_covers returned true as soon as two tracks on the same
disc had different cover ids. On Navidrome every song has its own mf-<id>
coverArt, so almost every album was flagged "distinct disc covers" and backfill
warmed one cover per track (~520k for ~170k tracks), filling album/ with mf-*
dirs instead of ~one cover per album.

Treat a release as having distinct disc covers only when each disc has a single
consistent cover that differs across discs (genuine box set); per-song ids now
collapse to one cover per album. Mirror the same fix in the TS
albumHasDistinctDiscCovers used by on-demand warming. Adds regression tests on
both sides.

* docs(changelog): record per-song cover over-fetch fix (PR #944)

Give the album/mf-* over-fetch fix its own [1.47.0] Fixed entry and a
settingsCredits line under PR #944.

* feat(cover): log failed cover downloads with album/artist name

A non-200 (or network-failed) getCoverArt download was swallowed silently. Now
the failure is logged with the resolved album/artist name and the server error,
so a server refusing covers under backfill load (5xx/429/timeouts) is visible.

- cover_resolve: describe_cover_entity() resolves a human label from the local
  index (album "Name" — Artist / artist "Name"), best-effort with id fallback.
- cover_cache: log_cover_fetch_failure() in ensure_inner logs on the download
  error path; threads optional library_server_id through CoverCacheEnsureArgs so
  the name lookup happens only on failure. Backfill logs at normal level,
  on-demand misses at debug level.
2026-06-02 10:58:39 +03:00

83 lines
2.7 KiB
TypeScript

import { describe, expect, it } from 'vitest';
import {
albumHasDistinctDiscCovers,
resolveAlbumCoverEntry,
resolveArtistCoverEntry,
resolveSongFetchCoverArtId,
resolveTrackCoverEntry,
} from './resolveEntry';
describe('resolveAlbumCoverEntry', () => {
it('uses bare Navidrome album id on disk', () => {
const e = resolveAlbumCoverEntry('0DurV2S7arIOBQVEknOPWX', 'al-0Dur_abc');
expect(e?.cacheEntityId).toBe('0DurV2S7arIOBQVEknOPWX');
expect(e?.fetchCoverArtId).toBe('al-0Dur_abc');
});
it('ignores mf fetch unless distinctDiscCovers', () => {
expect(resolveAlbumCoverEntry('al-box', 'mf-d2')?.cacheEntityId).toBe('al-box');
expect(resolveAlbumCoverEntry('al-box', 'mf-d2', true)?.cacheEntityId).toBe('mf-d2');
});
});
describe('resolveArtistCoverEntry', () => {
it('keys by artist id', () => {
const e = resolveArtistCoverEntry('03b645ef2100dfc4', 'ar-03b645ef');
expect(e?.cacheKind).toBe('artist');
expect(e?.cacheEntityId).toBe('03b645ef2100dfc4');
expect(e?.fetchCoverArtId).toBe('ar-03b645ef');
});
});
describe('resolveTrackCoverEntry', () => {
it('defaults to album bucket', () => {
const e = resolveTrackCoverEntry({
id: 't1',
albumId: 'al-1',
coverArt: 'mf-a',
});
expect(e?.cacheEntityId).toBe('al-1');
expect(e?.fetchCoverArtId).toBe('mf-a');
});
});
describe('resolveSongFetchCoverArtId', () => {
it('falls back to albumId when coverArt echoes track id', () => {
expect(
resolveSongFetchCoverArtId({ id: 'tr-1', coverArt: 'tr-1', albumId: 'al-42' }),
).toBe('al-42');
});
});
describe('albumHasDistinctDiscCovers', () => {
it('true when discs differ', () => {
expect(
albumHasDistinctDiscCovers([
{ id: 't1', albumId: 'al-1', coverArt: 'mf-a', discNumber: 1 },
{ id: 't2', albumId: 'al-1', coverArt: 'mf-b', discNumber: 2 },
]),
).toBe(true);
});
it('false for per-song ids within a single disc (Navidrome)', () => {
expect(
albumHasDistinctDiscCovers([
{ id: 't1', albumId: 'al-1', coverArt: 'mf-1', discNumber: 1 },
{ id: 't2', albumId: 'al-1', coverArt: 'mf-2', discNumber: 1 },
{ id: 't3', albumId: 'al-1', coverArt: 'mf-3', discNumber: 1 },
]),
).toBe(false);
});
it('false for per-song ids across discs (no shared disc cover)', () => {
expect(
albumHasDistinctDiscCovers([
{ id: 't1', albumId: 'al-1', coverArt: 'mf-1', discNumber: 1 },
{ id: 't2', albumId: 'al-1', coverArt: 'mf-2', discNumber: 1 },
{ id: 't3', albumId: 'al-1', coverArt: 'mf-3', discNumber: 2 },
{ id: 't4', albumId: 'al-1', coverArt: 'mf-4', discNumber: 2 },
]),
).toBe(false);
});
});