From 69cb51cc137b7a139ef19f8affec2376826d29b3 Mon Sep 17 00:00:00 2001 From: BoulderBadgeDad Date: Tue, 23 Jun 2026 11:12:29 -0700 Subject: [PATCH] #911: album Redownload uses the stored match id, not a fresh search MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Enhanced-view album Redownload only honoured album.spotify_album_id. For an iTunes-matched album (no spotify id) it fell through to a fresh /api/enhanced-search and grabbed the FIRST hit — which can be a different edition than the one you have (issue: matched the 66-track 'Original Soundtrack Collection', got the 19-track 'Volume 1'). Now it prefers the album row's stored source id (spotify, then iTunes — the iTunes endpoint already returns a Spotify-shaped payload) and only searches when neither exists. Also fixed the search fallback to fetch from the MATCHING source endpoint instead of always hitting Spotify (latent bug for iTunes search hits). Frontend-only orchestration fix; no JS test runner in the repo, the album endpoints are unchanged. --- webui/static/library.js | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/webui/static/library.js b/webui/static/library.js index c654d211..6be1e029 100644 --- a/webui/static/library.js +++ b/webui/static/library.js @@ -5416,20 +5416,34 @@ function _pollRedownloadProgress(taskId, overlay) { async function redownloadLibraryAlbum(album, artistName, btn) { const albumName = album.title || ''; const spotifyAlbumId = album.spotify_album_id || ''; + const itunesAlbumId = album.itunes_album_id || ''; - if (!spotifyAlbumId && !albumName) { + if (!spotifyAlbumId && !itunesAlbumId && !albumName) { showToast('No album ID or name available for redownload', 'warning'); return; } + // Fetch a specific album edition by its source id. The iTunes endpoint returns a + // Spotify-shaped payload, so all the downstream handling is identical. + const fetchAlbumBySource = (source, id, name, artist) => { + const params = new URLSearchParams({ name: name || albumName, artist: artist || artistName || '' }); + const base = source === 'itunes' ? '/api/itunes/album/' : '/api/spotify/album/'; + return fetch(`${base}${encodeURIComponent(id)}?${params}`); + }; + const origText = btn ? btn.innerHTML : ''; try { if (btn) { btn.disabled = true; btn.textContent = 'Loading...'; } + // #911 — redownload the edition the user ACTUALLY matched, using the album row's + // stored source id. A fresh search can resolve to a different edition (e.g. a + // single-volume release instead of the matched full collection), so use the + // spotify/iTunes id when present and only fall back to a search if neither exists. let response; if (spotifyAlbumId) { - const params = new URLSearchParams({ name: albumName, artist: artistName || '' }); - response = await fetch(`/api/spotify/album/${encodeURIComponent(spotifyAlbumId)}?${params}`); + response = await fetchAlbumBySource('spotify', spotifyAlbumId); + } else if (itunesAlbumId) { + response = await fetchAlbumBySource('itunes', itunesAlbumId); } if (!response || !response.ok) { @@ -5441,13 +5455,15 @@ async function redownloadLibraryAlbum(album, artistName, btn) { }); if (!searchResp.ok) throw new Error('Album search failed'); const searchData = await searchResp.json(); - const found = searchData.spotify_albums?.[0] || searchData.itunes_albums?.[0]; + const spotHit = searchData.spotify_albums?.[0]; + const found = spotHit || searchData.itunes_albums?.[0]; if (!found || !found.id) { showToast(`Could not find "${albumName}" by ${artistName || 'unknown'}`, 'warning'); return; } - const params = new URLSearchParams({ name: found.name || albumName, artist: found.artist || artistName || '' }); - response = await fetch(`/api/spotify/album/${encodeURIComponent(found.id)}?${params}`); + // Fetch from the MATCHING source endpoint — the old fallback always hit the + // Spotify endpoint, which is wrong for an iTunes search hit. + response = await fetchAlbumBySource(spotHit ? 'spotify' : 'itunes', found.id, found.name, found.artist); } if (!response.ok) throw new Error(`Failed to load album: ${response.status}`);