From 306001ade896783a9c793ddcd06d062f8dde37d1 Mon Sep 17 00:00:00 2001 From: Broque Thomas Date: Thu, 4 Sep 2025 13:46:50 -0700 Subject: [PATCH] Improve artist download status updates and UI Added debounced updates for the artist downloads section to prevent rapid UI refreshes. Enhanced debug logging and error handling for download status changes and bulk completion. Introduced a utility to force refresh all artist download statuses. Updated CSS for better spacing and overflow handling in artist bubble containers and images. --- webui/static/script.js | 90 +++++++++++++++++++++++++++++++++++++++--- webui/static/style.css | 5 ++- 2 files changed, 88 insertions(+), 7 deletions(-) diff --git a/webui/static/script.js b/webui/static/script.js index d49a306e..2811f349 100644 --- a/webui/static/script.js +++ b/webui/static/script.js @@ -69,6 +69,7 @@ let artistsPageState = { // --- Artist Downloads Management State --- let artistDownloadBubbles = {}; // Track artist download bubbles: artistId -> { artist, downloads: [], element } let artistDownloadModalOpen = false; // Track if artist download modal is open +let downloadsUpdateTimeout = null; // Debounce downloads section updates let artistsSearchTimeout = null; let artistsSearchController = null; @@ -5267,6 +5268,7 @@ window.formatArtists = formatArtists; window.closeArtistDownloadModal = closeArtistDownloadModal; window.openArtistDownloadProcess = openArtistDownloadProcess; window.bulkCompleteArtistDownloads = bulkCompleteArtistDownloads; +window.refreshAllArtistDownloadStatuses = refreshAllArtistDownloadStatuses; // APPEND THIS JAVASCRIPT SNIPPET (B) @@ -10401,12 +10403,24 @@ function registerArtistDownload(artist, album, virtualPlaylistId, albumType) { artistDownloadBubbles[artistId].downloads.push(downloadInfo); // Show/update the artist downloads section - showArtistDownloadsSection(); + updateArtistDownloadsSection(); // Monitor this download for completion monitorArtistDownload(artistId, virtualPlaylistId); } +/** + * Debounced update for artist downloads section to prevent rapid updates + */ +function updateArtistDownloadsSection() { + if (downloadsUpdateTimeout) { + clearTimeout(downloadsUpdateTimeout); + } + downloadsUpdateTimeout = setTimeout(() => { + showArtistDownloadsSection(); + }, 300); // 300ms debounce +} + /** * Show or update the artist downloads section in search state */ @@ -10482,6 +10496,15 @@ function createArtistBubbleCard(artistBubbleData) { const completedCount = downloads.filter(d => d.status === 'view_results').length; const allCompleted = activeCount === 0 && completedCount > 0; + // Debug logging for bubble card creation + console.log(`🔵 Creating bubble for ${artist.name}:`, { + totalDownloads: downloads.length, + activeCount, + completedCount, + allCompleted, + downloadStatuses: downloads.map(d => `${d.album.name}: ${d.status}`) + }); + const imageUrl = artist.image_url || ''; const backgroundStyle = imageUrl ? `background-image: url('${imageUrl}');` : @@ -10530,9 +10553,17 @@ function monitorArtistDownload(artistId, virtualPlaylistId) { if (process.status === 'complete' && download.status === 'in_progress') { download.status = 'view_results'; console.log(`✅ Download completed for ${artistDownloadBubbles[artistId].artist.name} - ${download.album.name}`); + console.log(`📊 Artist ${artistId} downloads status:`, artistDownloadBubbles[artistId].downloads.map(d => `${d.album.name}: ${d.status}`)); // Update the downloads section - showArtistDownloadsSection(); + updateArtistDownloadsSection(); + + // Check if all downloads for this artist are now completed + const artistDownloads = artistDownloadBubbles[artistId].downloads; + const allCompleted = artistDownloads.every(d => d.status === 'view_results'); + if (allCompleted) { + console.log(`🟢 All downloads completed for ${artistDownloadBubbles[artistId].artist.name} - green checkmark should appear`); + } } // Continue monitoring if still active @@ -10637,7 +10668,11 @@ function startArtistDownloadModalMonitoring(artistId) { itemsContainer.innerHTML = activeDownloads.map((download, index) => { const process = activeDownloadProcesses[download.virtualPlaylistId]; if (process) { - download.status = process.status === 'complete' ? 'view_results' : 'in_progress'; + const newStatus = process.status === 'complete' ? 'view_results' : 'in_progress'; + if (download.status !== newStatus) { + console.log(`🔄 Modal: Updating ${download.album.name} status from ${download.status} to ${newStatus}`); + download.status = newStatus; + } } return createArtistDownloadItem(download, index); }).join(''); @@ -10685,17 +10720,31 @@ function bulkCompleteArtistDownloads(artistId) { console.log(`🎯 Bulk completing downloads for artist: ${artistId}`); const artistBubbleData = artistDownloadBubbles[artistId]; - if (!artistBubbleData) return; + if (!artistBubbleData) { + console.warn(`❌ No artist bubble data found for ${artistId}`); + return; + } // Find all downloads in 'view_results' state const completedDownloads = artistBubbleData.downloads.filter(d => d.status === 'view_results'); + console.log(`📋 Found ${completedDownloads.length} completed downloads to close:`, + completedDownloads.map(d => d.album.name)); + + if (completedDownloads.length === 0) { + console.warn(`⚠️ No completed downloads found for bulk close`); + showToast('No completed downloads to close', 'info'); + return; + } // Programmatically close all completed modals completedDownloads.forEach(download => { const process = activeDownloadProcesses[download.virtualPlaylistId]; if (process && process.modalElement) { + console.log(`🗑️ Closing modal for: ${download.album.name}`); // Trigger the close function which handles cleanup closeDownloadMissingModal(download.virtualPlaylistId); + } else { + console.warn(`⚠️ No active process or modal found for: ${download.album.name}`); } }); @@ -10724,12 +10773,43 @@ function cleanupArtistDownload(virtualPlaylistId) { } // Update the downloads section - showArtistDownloadsSection(); + updateArtistDownloadsSection(); break; } } } +/** + * Force refresh all artist download statuses (useful for debugging) + */ +function refreshAllArtistDownloadStatuses() { + console.log('🔄 Force refreshing all artist download statuses...'); + + for (const artistId in artistDownloadBubbles) { + const artistData = artistDownloadBubbles[artistId]; + let hasChanges = false; + + artistData.downloads.forEach(download => { + const process = activeDownloadProcesses[download.virtualPlaylistId]; + if (process) { + const expectedStatus = process.status === 'complete' ? 'view_results' : 'in_progress'; + if (download.status !== expectedStatus) { + console.log(`🔧 Fixing status for ${download.album.name}: ${download.status} → ${expectedStatus}`); + download.status = expectedStatus; + hasChanges = true; + } + } + }); + + if (hasChanges) { + console.log(`✅ Updated statuses for ${artistData.artist.name}`); + } + } + + // Force update the downloads section + showArtistDownloadsSection(); +} + /** * Extract dominant colors from an image for dynamic glow effects */ diff --git a/webui/static/style.css b/webui/static/style.css index a0c5e5b6..34b8fb43 100644 --- a/webui/static/style.css +++ b/webui/static/style.css @@ -6589,9 +6589,10 @@ body { .artist-bubble-container { display: flex; flex-wrap: wrap; - gap: 16px; + gap: 24px; justify-content: center; align-items: center; + padding: 12px; } /* Artist Bubble Card */ @@ -6602,7 +6603,6 @@ body { border-radius: 50%; cursor: pointer; transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); - overflow: hidden; background: linear-gradient(135deg, rgba(26, 26, 26, 0.95) 0%, @@ -6646,6 +6646,7 @@ body { background-position: center; background-repeat: no-repeat; border-radius: 50%; + overflow: hidden; } .artist-bubble-overlay {