From a6db3d037b99a9b0206583c29e66f1bc14b07205 Mon Sep 17 00:00:00 2001 From: Broque Thomas Date: Fri, 8 Aug 2025 14:57:12 -0700 Subject: [PATCH] modal issue --- ui/pages/__pycache__/artists.cpython-312.pyc | Bin 245155 -> 248377 bytes .../__pycache__/dashboard.cpython-312.pyc | Bin 185257 -> 185162 bytes ui/pages/artists.py | 80 +++++++++++++++--- ui/pages/dashboard.py | 14 +-- 4 files changed, 76 insertions(+), 18 deletions(-) diff --git a/ui/pages/__pycache__/artists.cpython-312.pyc b/ui/pages/__pycache__/artists.cpython-312.pyc index 490dfbc0b4c741f8bf7b623e395f0d5b902d5f83..7735fcd2d21a4127cb68696250ec2cc1e435a123 100644 GIT binary patch delta 9008 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 delta 6350 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 diff --git a/ui/pages/__pycache__/dashboard.cpython-312.pyc b/ui/pages/__pycache__/dashboard.cpython-312.pyc index 248a1538a946fa749542c15f44735b67cfd2b8db..d87e17ed41028f64539ed7a0834e4483da57d754 100644 GIT binary patch delta 119 zcmZ3vocq)=Zr;+Zh71)`acC9#3%^fN)+ zjA@&9T~B9bsbtU;-yD2<8zYmZ_+V#6n;+cYsK_kA>fJttk#YMJMy72S0X)_~Q~&?~ 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()