diff --git a/core/deezer_download_client.py b/core/deezer_download_client.py index f20a963d..82d7dce4 100644 --- a/core/deezer_download_client.py +++ b/core/deezer_download_client.py @@ -315,20 +315,41 @@ class DeezerDownloadClient: break raw_tracks.extend(page_tracks) - # Batch-fetch release dates for unique albums + # Batch-fetch release dates for unique albums (cache-first) album_ids = set() for t in raw_tracks: aid = t.get('album', {}).get('id') if aid: album_ids.add(str(aid)) album_release_dates = {} + try: + from core.metadata_cache import get_metadata_cache + cache = get_metadata_cache() + except Exception: + cache = None for aid in album_ids: + # Check metadata cache first + if cache: + try: + cached = cache.get_entity('deezer', 'album', aid) + if cached and cached.get('release_date'): + album_release_dates[aid] = cached['release_date'] + continue + except Exception: + pass + # Cache miss — fetch from API try: time.sleep(0.3) # Respect rate limits a_resp = self._session.get(f'https://api.deezer.com/album/{aid}', timeout=10) if a_resp.ok: a_data = a_resp.json() album_release_dates[aid] = a_data.get('release_date', '') + # Store in metadata cache for future use + if cache: + try: + cache.store_entity('deezer', 'album', aid, a_data) + except Exception: + pass except Exception: pass diff --git a/webui/static/script.js b/webui/static/script.js index b8a9bfb6..3eb63314 100644 --- a/webui/static/script.js +++ b/webui/static/script.js @@ -10195,7 +10195,29 @@ async function rehydrateModal(processInfo, userRequested = false) { return; } - // Handle regular Spotify playlist processes + // Handle Deezer ARL playlist processes — ensure playlist data is in spotifyPlaylists for modal reuse + if (playlist_id.startsWith('deezer_arl_') && !spotifyPlaylists.find(p => p.id === playlist_id)) { + const rawId = playlist_id.replace('deezer_arl_', ''); + const deezerPlaylist = deezerArlPlaylists.find(p => String(p.id) === rawId); + if (deezerPlaylist) { + spotifyPlaylists.push({ + id: playlist_id, + name: deezerPlaylist.name, + track_count: deezerPlaylist.track_count || 0, + image_url: deezerPlaylist.image_url || '', + owner: deezerPlaylist.owner || '', + }); + } else { + // Playlists not loaded yet — use process info as fallback + spotifyPlaylists.push({ + id: playlist_id, + name: playlist_name || 'Deezer Playlist', + track_count: 0, + }); + } + } + + // Handle regular Spotify / Deezer ARL playlist processes let playlistData = spotifyPlaylists.find(p => p.id === playlist_id); if (!playlistData) { console.warn(`Cannot rehydrate modal: Playlist data for ${playlist_id} not loaded.`); @@ -11707,7 +11729,10 @@ async function openDownloadMissingModal(playlistId) { let tracks = playlistTrackCache[playlistId]; if (!tracks) { try { - const response = await fetch(`/api/spotify/playlist/${playlistId}`); + const fetchUrl = playlistId.startsWith('deezer_arl_') + ? `/api/deezer/arl-playlist/${playlistId.replace('deezer_arl_', '')}` + : `/api/spotify/playlist/${playlistId}`; + const response = await fetch(fetchUrl); const fullPlaylist = await response.json(); if (fullPlaylist.error) throw new Error(fullPlaylist.error); tracks = fullPlaylist.tracks; @@ -26570,6 +26595,27 @@ async function loadDeezerArlPlaylists() { renderDeezerArlPlaylists(); deezerArlPlaylistsLoaded = true; + // Check for active syncs or downloads and rehydrate UI + await checkForActiveProcesses(); + for (const p of deezerArlPlaylists) { + const arlId = `deezer_arl_${p.id}`; + try { + const syncResp = await fetch(`/api/sync/status/${arlId}`); + if (syncResp.ok) { + const syncState = await syncResp.json(); + if (syncState.status === 'syncing') { + // Re-attach sync polling and update card UI + if (!spotifyPlaylists.find(sp => sp.id === arlId)) { + spotifyPlaylists.push({ id: arlId, name: p.name, track_count: p.track_count || 0, image_url: p.image_url || '', owner: p.owner || '' }); + } + updateCardToSyncing(arlId, syncState.progress?.progress || 0, syncState.progress); + startSyncPolling(arlId); + console.log(`🔄 Rehydrated active sync for Deezer ARL playlist: ${p.name}`); + } + } + } catch (e) { /* No active sync — normal */ } + } + } catch (error) { container.innerHTML = `