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 <noreply@anthropic.com>
This commit is contained in:
2026-03-12 08:36:24 +00:00
parent 882dad57e2
commit 3dd043689e
2 changed files with 22 additions and 10 deletions

View File

@@ -49,10 +49,11 @@ function normalizeRelease(release) {
})); }));
}); });
let coverArtUrl = null; // Always generate the CAA URL when an id is present; the browser/onError
if (release['cover-art-archive'] && release['cover-art-archive'].front) { // handles 404s for releases that have no front cover.
coverArtUrl = `https://coverartarchive.org/release/${release.id}/front-250`; const coverArtUrl = release.id
} ? `https://coverartarchive.org/release/${release.id}/front-250`
: null;
return { return {
mbId: String(release.id || ''), mbId: String(release.id || ''),
@@ -92,7 +93,7 @@ class MusicBrainzService {
url.searchParams.set('query', q); url.searchParams.set('query', q);
url.searchParams.set('fmt', 'json'); url.searchParams.set('fmt', 'json');
url.searchParams.set('limit', '10'); 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 { try {
const data = await mbFetch(url.toString()); const data = await mbFetch(url.toString());

View File

@@ -7,6 +7,21 @@ import { InputText } from 'primereact/inputtext';
import { InputNumber } from 'primereact/inputnumber'; import { InputNumber } from 'primereact/inputnumber';
import { Checkbox } from 'primereact/checkbox'; import { Checkbox } from 'primereact/checkbox';
function CoverThumb({ url, alt }) {
const [failed, setFailed] = useState(false);
if (!url || failed) {
return <div className="poster-thumb-lg poster-fallback">-</div>;
}
return (
<img
src={url}
alt={alt}
className="poster-thumb-lg"
onError={() => setFailed(true)}
/>
);
}
function formatDurationMs(ms) { function formatDurationMs(ms) {
const totalSec = Math.round((ms || 0) / 1000); const totalSec = Math.round((ms || 0) / 1000);
const min = Math.floor(totalSec / 60); const min = Math.floor(totalSec / 60);
@@ -135,11 +150,7 @@ export default function CdMetadataDialog({
const mbTitleBody = (row) => ( const mbTitleBody = (row) => (
<div className="mb-result-row"> <div className="mb-result-row">
{row.coverArtUrl ? ( <CoverThumb url={row.coverArtUrl} alt={row.title} />
<img src={row.coverArtUrl} alt={row.title} className="poster-thumb-lg" />
) : (
<div className="poster-thumb-lg poster-fallback">-</div>
)}
<div> <div>
<div><strong>{row.title}</strong></div> <div><strong>{row.title}</strong></div>
<small>{row.artist}{row.year ? ` | ${row.year}` : ''}</small> <small>{row.artist}{row.year ? ` | ${row.year}` : ''}</small>