feat(spotify): lazy-load per-track iTunes artwork for playlists/albums

Adds POST /api/spotify/track-artwork endpoint that takes an array of
{idx, trackName, artistName} and returns iTunes artwork URLs in batches
of 8 concurrent requests.

Frontend calls this after rendering the track list, then patches each
.gtrack-art element with the correct album cover as results arrive.
Also updates _spotifyResolved.tracks so downloads use the right artwork.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
HoneyandClaude Sonnet 4.6 committed 2026-04-27 18:19:08 +02:00
1 parent a305ec98e2
commit 5446d83ab3
2 files changed
+49

No files matched your search

+33
View File
@@ -1043,6 +1043,39 @@ function _renderSpotifyPreview(data) {
list.innerHTML = '';
(data.tracks || []).forEach((t, i) => list.appendChild(makeGlobalTrackItem(t, i, data.tracks)));
section.style.display = '';
// Lazy-load correct per-track artwork via iTunes in the background
if ((data.type === 'playlist' || data.type === 'album') && count > 0 && S.cfg.backendUrl) {
_loadSpotifyTrackArtwork(data.tracks, list);
}
}
async function _loadSpotifyTrackArtwork(tracks, listEl) {
try {
const payload = tracks.map((t, i) => ({ idx: i, trackName: t.trackName, artistName: t.artistName }));
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();
const artEls = listEl.querySelectorAll('.gtrack-art');
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);
// Update resolved data so downloads use the correct artwork
if (window._spotifyResolved?.tracks?.[r.idx]) {
window._spotifyResolved.tracks[r.idx].artworkUrl100 = r.artworkUrl;
}
}
} catch { /* artwork loading is non-critical */ }
}
// ─── HELPERS ───