diff --git a/src/components.js b/src/components.js
index 3940cfa..909074f 100644
--- a/src/components.js
+++ b/src/components.js
@@ -71,7 +71,7 @@ export function makeGlobalTrackItem(t, idx, list) {
el.className = 'gtrack-item';
const art = t.artworkUrl60 || t.artworkUrl100 || '';
el.innerHTML = `
-
${esc(t.trackName||t.collectionName||'โ')}${t.trackExplicitness==='explicit'?'E':''}
${esc(t.artistName||'โ')} ยท ${esc(t.collectionName||'')} ${t.releaseDate?'ยท '+new Date(t.releaseDate).getFullYear():''}
diff --git a/src/spotify.js b/src/spotify.js
index 1ca5738..a0ac455 100644
--- a/src/spotify.js
+++ b/src/spotify.js
@@ -1,5 +1,6 @@
import { S } from './state.js';
import { esc, toast } from './utils.js';
+import { itunesSearch } from './api.js';
// Circular imports โ safe (only used inside function bodies)
import { makeGlobalTrackItem } from './components.js';
import { openDlModal } from './ui.js';
@@ -159,43 +160,47 @@ function _renderSpotifyPreview(data) {
}
async function _loadSpotifyTrackArtwork(tracks, listEl) {
- try {
- const artEls = listEl.querySelectorAll('.gtrack-art');
+ const artEls = listEl.querySelectorAll('.gtrack-art');
- // Render any artwork already present in the Spotify data immediately
- tracks.forEach((t, i) => {
- const url = t.artworkUrl100 || t.artworkUrl60 || '';
- if (!url) return;
- const el = artEls[i];
- if (!el) return;
- const img = document.createElement('img');
- img.src = url; img.loading = 'lazy';
- el.innerHTML = ''; el.appendChild(img);
- });
+ // Show any Spotify artwork that's already present immediately
+ tracks.forEach((t, i) => {
+ const url = t.artworkUrl100 || t.artworkUrl60 || '';
+ if (!url) return;
+ const el = artEls[i];
+ if (!el) return;
+ _setArt(el, url);
+ });
- const payload = tracks.map((t, i) => ({
- idx: i,
- trackName: t.trackName,
- artistName: t.artistName,
- existingArt: t.artworkUrl100 || t.artworkUrl60 || '',
+ // Enrich each track with iTunes data โ same call as global search
+ const CONC = 8;
+ for (let i = 0; i < tracks.length; i += CONC) {
+ const batch = tracks.slice(i, i + CONC);
+ await Promise.all(batch.map(async (t, bi) => {
+ const idx = i + bi;
+ try {
+ const firstArtist = (t.artistName || '').split(/\s*[,/โข]\s*/)[0].trim();
+ const results = await itunesSearch(`${t.trackName} ${firstArtist}`, 'musicTrack', 1);
+ const match = results[0];
+ if (!match) return;
+ // Enrich track object so downloads get correct metadata
+ if (match.artworkUrl100) t.artworkUrl100 = match.artworkUrl100;
+ if (match.collectionName) t.collectionName = match.collectionName;
+ if (match.releaseDate) t.releaseDate = match.releaseDate;
+ if (match.trackNumber) t.trackNumber = match.trackNumber;
+ if (match.trackExplicitness) t.trackExplicitness = match.trackExplicitness;
+ if (window._spotifyResolved?.tracks?.[idx]) Object.assign(window._spotifyResolved.tracks[idx], t);
+ const url = match.artworkUrl100 || match.artworkUrl60 || '';
+ if (url) _setArt(artEls[idx], url);
+ } catch { /* non-critical */ }
}));
- const res = await fetch(`${S.cfg.backendUrl}/api/spotify/track-artwork`, {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({ tracks: payload }),
- });
- if (!res.ok) return;
- const { results } = await res.json();
- for (const r of results) {
- if (!r.artworkUrl || r.idx == null) continue;
- const el = artEls[r.idx];
- if (!el) continue;
- const img = document.createElement('img');
- img.src = r.artworkUrl; img.loading = 'lazy';
- el.innerHTML = ''; el.appendChild(img);
- if (window._spotifyResolved?.tracks?.[r.idx]) {
- window._spotifyResolved.tracks[r.idx].artworkUrl100 = r.artworkUrl;
- }
- }
- } catch { /* artwork loading is non-critical */ }
+ }
+}
+
+function _setArt(el, url) {
+ if (!el) return;
+ const img = document.createElement('img');
+ img.loading = 'lazy';
+ img.onerror = () => { el.innerHTML = '
๐ต
'; };
+ img.src = url;
+ el.innerHTML = ''; el.appendChild(img);
}