diff --git a/ui/pages/__pycache__/artists.cpython-312.pyc b/ui/pages/__pycache__/artists.cpython-312.pyc index 490dfbc0..7735fcd2 100644 Binary files a/ui/pages/__pycache__/artists.cpython-312.pyc and b/ui/pages/__pycache__/artists.cpython-312.pyc differ diff --git a/ui/pages/__pycache__/dashboard.cpython-312.pyc b/ui/pages/__pycache__/dashboard.cpython-312.pyc index 248a1538..d87e17ed 100644 Binary files a/ui/pages/__pycache__/dashboard.cpython-312.pyc and b/ui/pages/__pycache__/dashboard.cpython-312.pyc differ diff --git a/ui/pages/artists.py b/ui/pages/artists.py index ba13cdce..9147b677 100644 --- a/ui/pages/artists.py +++ b/ui/pages/artists.py @@ -2666,34 +2666,65 @@ class DownloadMissingAlbumTracksModal(QDialog): failed_count = len(self.permanently_failed_tracks) wishlist_added_count = 0 + # DEBUG: Log failed tracks details + logger.info(f"DEBUG: Processing {failed_count} failed tracks from album modal") + for i, track_info in enumerate(self.permanently_failed_tracks): + logger.info(f"DEBUG: Failed track {i+1}: keys={list(track_info.keys())}") + if 'spotify_track' in track_info: + st = track_info['spotify_track'] + logger.info(f"DEBUG: Spotify track: {getattr(st, 'name', 'NO_NAME')} by {getattr(st, 'artists', 'NO_ARTISTS')}") + if self.permanently_failed_tracks: try: # Add failed tracks to wishlist + # Handle artist name safely - could be string or dict + artist_name = 'Unknown Artist' + if hasattr(self.album, 'artists') and self.album.artists: + first_artist = self.album.artists[0] + if isinstance(first_artist, str): + artist_name = first_artist + elif isinstance(first_artist, dict): + artist_name = first_artist.get('name', 'Unknown Artist') + else: + artist_name = str(first_artist) + source_context = { 'album_name': getattr(self.album, 'name', 'Unknown Album'), 'album_id': getattr(self.album, 'id', None), - 'artist_name': getattr(self.album, 'artists', [{}])[0].get('name', 'Unknown Artist') if hasattr(self.album, 'artists') else 'Unknown Artist', + 'artist_name': artist_name, 'added_from': 'artists_page_modal', 'timestamp': datetime.now().isoformat() } - for failed_track_info in self.permanently_failed_tracks: + logger.info(f"DEBUG: Source context: {source_context}") + + for i, failed_track_info in enumerate(self.permanently_failed_tracks): try: + logger.info(f"DEBUG: Attempting to add track {i+1} to wishlist...") success = self.wishlist_service.add_failed_track_from_modal( track_info=failed_track_info, source_type='album', source_context=source_context ) + logger.info(f"DEBUG: Track {i+1} add result: {success}") if success: wishlist_added_count += 1 + else: + logger.warning(f"DEBUG: Track {i+1} was NOT added to wishlist (returned False)") except Exception as e: - logger.error(f"Failed to add album track to wishlist: {e}") + logger.error(f"Failed to add album track {i+1} to wishlist: {e}") + import traceback + logger.error(f"Full traceback: {traceback.format_exc()}") if wishlist_added_count > 0: logger.info(f"Added {wishlist_added_count} failed tracks to wishlist from album '{self.album.name}'") + else: + logger.warning(f"NO TRACKS were added to wishlist despite {failed_count} failed tracks!") except Exception as e: logger.error(f"Error adding failed album tracks to wishlist: {e}") + import traceback + logger.error(f"Full outer traceback: {traceback.format_exc()}") # Determine the final message based on success or failure if self.permanently_failed_tracks: @@ -3879,9 +3910,20 @@ class ArtistsPage(QWidget): self.toast_manager.info(f"Downloads already in progress for '{album.name}'") return elif existing_modal: - # Modal exists but is not visible - might be finished/cancelled - print("⚠️ Found hidden modal - likely finished or cancelled, creating fresh modal") - del self.active_album_sessions[album.id] + # Modal exists but is not visible - check if downloads are still in progress + if hasattr(existing_modal, 'download_in_progress') and existing_modal.download_in_progress: + print(f"🔄 Resuming hidden modal with active downloads for album: {album.name}") + # Show the existing modal to resume progress tracking + existing_modal.show() + existing_modal.activateWindow() + existing_modal.raise_() + if hasattr(self, 'toast_manager') and self.toast_manager: + self.toast_manager.info(f"Resuming downloads for '{album.name}'") + return + else: + # Modal finished or cancelled, safe to create fresh one + print("⚠️ Found finished modal, creating fresh modal") + del self.active_album_sessions[album.id] else: # No modal reference, clean up stale session print("⚠️ Stale session found, cleaning up") @@ -3970,13 +4012,24 @@ class ArtistsPage(QWidget): # Clean up the session when modal is definitely closing if album_id in self.active_album_sessions: - # Always remove session when modal closes (whether accepted or cancelled) - # This ensures a fresh modal is created when user clicks the album again - del self.active_album_sessions[album_id] + session = self.active_album_sessions[album_id] + modal = session.get('modal') + + # Only remove session if downloads are completely finished or cancelled if result == 1: # QDialog.Accepted = 1 (downloads completed or all tracks exist) + del self.active_album_sessions[album_id] print(f"🗑️ Removed completed session for album {album_id}") + elif modal and hasattr(modal, 'cancel_requested') and modal.cancel_requested: + # User explicitly cancelled - remove session for fresh modal on next click + del self.active_album_sessions[album_id] + print(f"🗑️ Removed cancelled session for album {album_id} - user requested cancellation") + elif modal and hasattr(modal, 'download_in_progress') and not modal.download_in_progress: + # Downloads are not in progress, safe to remove session + del self.active_album_sessions[album_id] + print(f"🗑️ Removed finished session for album {album_id} - no downloads in progress") else: - print(f"🗑️ Removed cancelled session for album {album_id} - fresh modal will be created on next click") + # Downloads still in progress and not cancelled - keep session alive for resumption + print(f"💾 Keeping session for album {album_id} - downloads still in progress, can be resumed") if album_card: try: @@ -3988,12 +4041,17 @@ class ArtistsPage(QWidget): else: # Modal was cancelled/closed - reset the card to allow reopening (but keep session) # Reset any download-in-progress indicators - if hasattr(album_card, 'progress_overlay') and album_card.progress_overlay: + if hasattr(album_card, 'progress_overlay') and album_card.progress_overlay is not None: try: album_card.progress_overlay.hide() + print(f"🔄 Hidden progress overlay for album {album_id}") except RuntimeError: pass + # Also call the safe hide method if available + if hasattr(album_card, 'safe_hide_overlay'): + album_card.safe_hide_overlay() + # Reset the card to allow clicking again (if not already owned) if not album_card.is_owned: # Show a visual indicator that this album has an active session diff --git a/ui/pages/dashboard.py b/ui/pages/dashboard.py index 9f675d26..0ee781a9 100644 --- a/ui/pages/dashboard.py +++ b/ui/pages/dashboard.py @@ -725,7 +725,7 @@ class DownloadMissingWishlistTracksModal(QDialog): source_key = f"{getattr(slskd_result, 'username', 'unknown')}_{slskd_result.filename}" track_info['used_sources'].add(source_key) spotify_based_result = self.create_spotify_based_search_result_from_validation(slskd_result, spotify_metadata) - self.track_table.setItem(table_index, 4, QTableWidgetItem("... Queued")) + self.track_table.setItem(table_index, 3, QTableWidgetItem("... Queued")) self.start_matched_download_via_infrastructure_parallel(spotify_based_result, track_index, table_index, download_index) def start_matched_download_via_infrastructure_parallel(self, spotify_based_result, track_index, table_index, download_index): @@ -783,7 +783,7 @@ class DownloadMissingWishlistTracksModal(QDialog): self.on_parallel_track_completed(download_index, success=True) elif new_status == 'downloading': progress = result.get('progress', 0) - self.track_table.setItem(download_info['table_index'], 4, QTableWidgetItem(f"⏬ Downloading ({progress}%)")) + self.track_table.setItem(download_info['table_index'], 3, QTableWidgetItem(f"⏬ Downloading ({progress}%)")) if 'queued_start_time' in download_info: del download_info['queued_start_time'] if progress < 1: if 'downloading_start_time' not in download_info: @@ -795,7 +795,7 @@ class DownloadMissingWishlistTracksModal(QDialog): else: if 'downloading_start_time' in download_info: del download_info['downloading_start_time'] elif new_status == 'queued': - self.track_table.setItem(download_info['table_index'], 4, QTableWidgetItem("... Queued")) + self.track_table.setItem(download_info['table_index'], 3, QTableWidgetItem("... Queued")) if 'queued_start_time' not in download_info: download_info['queued_start_time'] = time.time() elif time.time() - download_info['queued_start_time'] > 90: @@ -838,7 +838,7 @@ class DownloadMissingWishlistTracksModal(QDialog): if not next_candidate: self.on_parallel_track_failed(download_index, "No alternative sources in cache") return - self.track_table.setItem(failed_download_info['table_index'], 4, QTableWidgetItem(f"🔄 Retrying ({track_info['retry_count']})...")) + self.track_table.setItem(failed_download_info['table_index'], 3, QTableWidgetItem(f"🔄 Retrying ({track_info['retry_count']})...")) self.start_validated_download_parallel(next_candidate, track_info['spotify_track'], track_info['track_index'], track_info['table_index'], download_index) def on_parallel_track_completed(self, download_index, success): @@ -846,7 +846,7 @@ class DownloadMissingWishlistTracksModal(QDialog): if not track_info or track_info.get('completed', False): return track_info['completed'] = True if success: - self.track_table.setItem(track_info['table_index'], 4, QTableWidgetItem("✅ Downloaded")) + self.track_table.setItem(track_info['table_index'], 3, QTableWidgetItem("✅ Downloaded")) self.downloaded_tracks_count += 1 self.downloaded_count_label.setText(str(self.downloaded_tracks_count)) self.successful_downloads += 1 @@ -856,7 +856,7 @@ class DownloadMissingWishlistTracksModal(QDialog): logger.info(f"Successfully downloaded and removed '{track_info['spotify_track'].name}' from wishlist.") else: - self.track_table.setItem(track_info['table_index'], 4, QTableWidgetItem("❌ Failed")) + self.track_table.setItem(track_info['table_index'], 3, QTableWidgetItem("❌ Failed")) self.failed_downloads += 1 if track_info not in self.permanently_failed_tracks: self.permanently_failed_tracks.append(track_info) @@ -916,7 +916,7 @@ class DownloadMissingWishlistTracksModal(QDialog): final_message += "All tracks were downloaded successfully!" logger.info("Wishlist processing complete. Scheduling next run in 60 minutes.") self.parent_dashboard.wishlist_retry_timer.start(3600000) # 60 minutes - QMessageBox.information(self, "Downloads Complete", final_message) + # Removed success modal - users don't need to see completion notification def on_cancel_clicked(self): self.cancel_operations()