From 3dd043689e55aba23f9551e5867977114d82e0c8 Mon Sep 17 00:00:00 2001 From: mboehmlaender Date: Thu, 12 Mar 2026 08:36:24 +0000 Subject: [PATCH] fix: always generate CAA cover art URL, handle missing covers with onError Per CAA API docs, front-250 URLs are predictable from mbId. Remove the cover-art-archive.front check (unreliable in search results) and always construct the URL. A CoverThumb component handles 404s gracefully. Co-Authored-By: Claude Sonnet 4.6 --- backend/src/services/musicBrainzService.js | 11 +++++----- frontend/src/components/CdMetadataDialog.jsx | 21 +++++++++++++++----- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/backend/src/services/musicBrainzService.js b/backend/src/services/musicBrainzService.js index 925f1a4..96bf1a0 100644 --- a/backend/src/services/musicBrainzService.js +++ b/backend/src/services/musicBrainzService.js @@ -49,10 +49,11 @@ function normalizeRelease(release) { })); }); - let coverArtUrl = null; - if (release['cover-art-archive'] && release['cover-art-archive'].front) { - coverArtUrl = `https://coverartarchive.org/release/${release.id}/front-250`; - } + // Always generate the CAA URL when an id is present; the browser/onError + // handles 404s for releases that have no front cover. + const coverArtUrl = release.id + ? `https://coverartarchive.org/release/${release.id}/front-250` + : null; return { mbId: String(release.id || ''), @@ -92,7 +93,7 @@ class MusicBrainzService { url.searchParams.set('query', q); url.searchParams.set('fmt', 'json'); url.searchParams.set('limit', '10'); - url.searchParams.set('inc', 'artist-credits+labels+recordings+cover-art-archive'); + url.searchParams.set('inc', 'artist-credits+labels+recordings'); try { const data = await mbFetch(url.toString()); diff --git a/frontend/src/components/CdMetadataDialog.jsx b/frontend/src/components/CdMetadataDialog.jsx index f99a1f0..ba757c5 100644 --- a/frontend/src/components/CdMetadataDialog.jsx +++ b/frontend/src/components/CdMetadataDialog.jsx @@ -7,6 +7,21 @@ import { InputText } from 'primereact/inputtext'; import { InputNumber } from 'primereact/inputnumber'; import { Checkbox } from 'primereact/checkbox'; +function CoverThumb({ url, alt }) { + const [failed, setFailed] = useState(false); + if (!url || failed) { + return
-
; + } + return ( + {alt} setFailed(true)} + /> + ); +} + function formatDurationMs(ms) { const totalSec = Math.round((ms || 0) / 1000); const min = Math.floor(totalSec / 60); @@ -135,11 +150,7 @@ export default function CdMetadataDialog({ const mbTitleBody = (row) => (
- {row.coverArtUrl ? ( - {row.title} - ) : ( -
-
- )} +
{row.title}
{row.artist}{row.year ? ` | ${row.year}` : ''}