diff --git a/webui/static/stats-automations.js b/webui/static/stats-automations.js index e16397b7..b5f2612b 100644 --- a/webui/static/stats-automations.js +++ b/webui/static/stats-automations.js @@ -829,52 +829,74 @@ async function openMirroredPlaylistModal(playlistId) { const tracks = data.tracks || []; const source = data.source || 'unknown'; const sourceRef = getMirroredSourceRef(data); - const sourceIcons = { spotify: '🎵', tidal: '🌊', youtube: '▶', beatport: '🎛' }; + const sourceIcons = { spotify: '🎵', spotify_public: '🎵', tidal: '🌊', youtube: '▶', beatport: '🎛', deezer: '🎧', qobuz: '♫' }; + const sourceLabels = { spotify: 'Spotify', spotify_public: 'Spotify', tidal: 'Tidal', youtube: 'YouTube', beatport: 'Beatport', deezer: 'Deezer', qobuz: 'Qobuz' }; const sourceIcon = sourceIcons[source] || '📋'; + const srcLabel = sourceLabels[source] || source; + + // Hero artwork: playlist cover → first track with art → gradient fallback. + const heroArt = data.image_url || (tracks.find(t => t.image_url) || {}).image_url || ''; + + // Total runtime for the meta line. + const totalMs = tracks.reduce((sum, t) => sum + (t.duration_ms || 0), 0); + const totalMin = Math.round(totalMs / 60000); + const totalLabel = totalMin >= 60 ? `${Math.floor(totalMin / 60)} hr ${totalMin % 60} min` : `${totalMin} min`; const trackRows = tracks.map(t => { const dur = t.duration_ms ? `${Math.floor(t.duration_ms / 60000)}:${String(Math.floor((t.duration_ms % 60000) / 1000)).padStart(2, '0')}` : ''; - return `