From aedfdbd86740ef7135d438d3318462938172e49c Mon Sep 17 00:00:00 2001 From: Broque Thomas Date: Wed, 23 Jul 2025 23:21:09 -0700 Subject: [PATCH] better --- .spotify_cache | 2 +- logs/app.log | 30 ++++++++ ui/pages/__pycache__/sync.cpython-312.pyc | Bin 170017 -> 171711 bytes ui/pages/sync.py | 81 ++++++++++++++++++---- 4 files changed, 98 insertions(+), 15 deletions(-) diff --git a/.spotify_cache b/.spotify_cache index e67b7df2..383f97a1 100644 --- a/.spotify_cache +++ b/.spotify_cache @@ -1 +1 @@ -{"access_token": "BQBcawhTowBatKdkvO7n3N80j8Pe7sZlSAoUGyWlT6Iyz-SHjUBxehwq0FomzdFUGEkJk2pQ3RKNoCY60Kvd9mDjgmh3rSFYphYE0LAEq71j1i0SR0vZnhpKV_5Ia7DdLWS3Z5em2t1XTe0dsnJoRHlvfguCDGFTGrgzOEUUtzJ6rUMqcWlgQTqWcqif0xAKij8l4hwiPI5fsWbRVQUdD-MXLqBveArU3tcJunylwDbqJfqSJ_8HxRNLDQoxtqfn", "token_type": "Bearer", "expires_in": 3600, "scope": "user-library-read user-read-private playlist-read-private playlist-read-collaborative user-read-email", "expires_at": 1753338014, "refresh_token": "AQDmfQkPCGObfJeTUIbW1hAAwhSqkuHRA3Qh2dqVYMRh0eCkFMQgPNJDDzF8y-BiaVbj80zePkK_XSfYH1aJutMtNbnsqRKWuxP31BTrMc7pdUdbE7Fma4oH8wpDUKdG3MM"} \ No newline at end of file +{"access_token": "BQCLT_slOYLk3v2BHMORcGETcy_0zWC43NqlAHsNvKZg6YnGZwlW3U98evnFP_mlm-PRC5LjSZc39mtX9Z5ikNILw13_nCpCLAYD5Qh0ZP4tUtCwlbmkCyDrhnzFXRgv7BaiFhCmxz4QV63j1YMhgk_NM95Bg8cMy8_K7jcdgNP5ApVC6LXbhNK4ytYFhuicULb-fTbJna2DAmp37QduR9dc1LHazfFYGb7Um_fAYfo7CjipUhyFI54NH3zy32aQ", "token_type": "Bearer", "expires_in": 3600, "scope": "user-library-read user-read-private playlist-read-private playlist-read-collaborative user-read-email", "expires_at": 1753341652, "refresh_token": "AQDmfQkPCGObfJeTUIbW1hAAwhSqkuHRA3Qh2dqVYMRh0eCkFMQgPNJDDzF8y-BiaVbj80zePkK_XSfYH1aJutMtNbnsqRKWuxP31BTrMc7pdUdbE7Fma4oH8wpDUKdG3MM"} \ No newline at end of file diff --git a/logs/app.log b/logs/app.log index b414ece3..58eb02f1 100644 --- a/logs/app.log +++ b/logs/app.log @@ -446604,3 +446604,33 @@ 2025-07-23 22:21:16 - newmusic.soulseek_client - DEBUG - _make_request:243 - Headers: {'Content-Type': 'application/json', 'X-API-Key': '1234567891234567'} 2025-07-23 22:21:16 - newmusic.soulseek_client - DEBUG - _make_request:254 - Response status: 200 2025-07-23 22:21:16 - newmusic.soulseek_client - DEBUG - _make_request:255 - Response text: [{"username":"DuckinthePond","directories":[{"directory":"@@qkrmw\\Music\\Flac Files\\Chart\\Billboard Top 100\\Billboard Top 100 - Hits of 2000-2009\\Billboard Top 100 - Hits of 2006","fileCount":1,"files":[{"id":"1c1afe3d-46fb-4d8a-ba73-1d1af559489c","username":"DuckinthePond","direction":"Download","filename":"@@qkrmw\\Music\\Flac Files\\Chart\\Billboard Top 100\\Billboard Top 100 - Hits of 2000-2009\\Billboard Top 100 - Hits of 2006\\035 - Ludacris feat Pharrell - Money Maker.flac","size":30... +2025-07-23 23:17:01 - newmusic - INFO - setup_logging:57 - Logging initialized with level: DEBUG +2025-07-23 23:17:01 - newmusic.main - INFO - main:211 - Starting NewMusic application +2025-07-23 23:17:01 - newmusic.spotify_client - INFO - _setup_client:179 - Spotify client initialized (user info will be fetched when needed) +2025-07-23 23:17:01 - newmusic.soulseek_client - INFO - _setup_client:220 - Soulseek client configured with slskd at http://localhost:5030 +2025-07-23 23:17:01 - newmusic.spotify_client - INFO - _setup_client:179 - Spotify client initialized (user info will be fetched when needed) +2025-07-23 23:17:02 - newmusic.main - INFO - change_page:163 - Changed to page: dashboard +2025-07-23 23:17:02 - newmusic.main - INFO - setup_media_player_connections:150 - Media player connections established between sidebar and downloads page +2025-07-23 23:17:02 - newmusic.plex_client - INFO - _find_music_library:116 - Found music library: Music +2025-07-23 23:17:02 - newmusic.plex_client - INFO - _setup_client:102 - Successfully connected to Plex server: PLEX-MACHINE +2025-07-23 23:17:10 - newmusic.main - INFO - change_page:163 - Changed to page: downloads +2025-07-23 23:17:10 - newmusic.main - INFO - change_page:163 - Changed to page: sync +2025-07-23 23:17:10 - newmusic.spotify_client - INFO - _ensure_user_id:195 - Successfully authenticated with Spotify as broquethomas +2025-07-23 23:17:11 - newmusic.spotify_client - INFO - get_user_playlists_metadata_only:256 - Retrieved 7 playlist metadata (first batch) +2025-07-23 23:20:35 - newmusic.main - INFO - closeEvent:176 - Closing application... +2025-07-23 23:20:35 - newmusic.main - INFO - closeEvent:181 - Cleaning up Downloads page threads... +2025-07-23 23:20:35 - newmusic.main - INFO - closeEvent:186 - Stopping status monitoring thread... +2025-07-23 23:20:36 - newmusic.main - INFO - closeEvent:191 - Closing Soulseek client... +2025-07-23 23:20:36 - newmusic.main - INFO - closeEvent:197 - Application closed successfully +2025-07-23 23:20:38 - newmusic - INFO - setup_logging:57 - Logging initialized with level: DEBUG +2025-07-23 23:20:38 - newmusic.main - INFO - main:211 - Starting NewMusic application +2025-07-23 23:20:38 - newmusic.spotify_client - INFO - _setup_client:179 - Spotify client initialized (user info will be fetched when needed) +2025-07-23 23:20:38 - newmusic.soulseek_client - INFO - _setup_client:220 - Soulseek client configured with slskd at http://localhost:5030 +2025-07-23 23:20:38 - newmusic.spotify_client - INFO - _setup_client:179 - Spotify client initialized (user info will be fetched when needed) +2025-07-23 23:20:39 - newmusic.main - INFO - change_page:163 - Changed to page: dashboard +2025-07-23 23:20:39 - newmusic.main - INFO - setup_media_player_connections:150 - Media player connections established between sidebar and downloads page +2025-07-23 23:20:39 - newmusic.plex_client - INFO - _find_music_library:116 - Found music library: Music +2025-07-23 23:20:39 - newmusic.plex_client - INFO - _setup_client:102 - Successfully connected to Plex server: PLEX-MACHINE +2025-07-23 23:20:52 - newmusic.main - INFO - change_page:163 - Changed to page: sync +2025-07-23 23:20:52 - newmusic.spotify_client - INFO - _ensure_user_id:195 - Successfully authenticated with Spotify as broquethomas +2025-07-23 23:20:52 - newmusic.spotify_client - INFO - get_user_playlists_metadata_only:256 - Retrieved 7 playlist metadata (first batch) diff --git a/ui/pages/__pycache__/sync.cpython-312.pyc b/ui/pages/__pycache__/sync.cpython-312.pyc index 1cb06597f22a88d6d6edae0ac36f2b22b67bbbd8..e222ab7dc371103c5a2890b64ffd2570e51f573e 100644 GIT binary patch delta 13783 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 O?})ytp?~q1_WuFqo&^yA delta 12592 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 F{})MI$}s={ diff --git a/ui/pages/sync.py b/ui/pages/sync.py index 867b4cf9..74b6c5d9 100644 --- a/ui/pages/sync.py +++ b/ui/pages/sync.py @@ -811,7 +811,9 @@ class PlaylistDetailsModal(QDialog): playlist_item_widget.download_modal = modal - self.parent_page.on_download_process_started(self.playlist.id, playlist_item_widget) + # --- FIX --- + # The call to on_download_process_started has been removed from here + # and moved to the modal's "Begin Search" button. self.accept() modal.show() @@ -1425,18 +1427,22 @@ class SyncPage(QWidget): playlist_item_widget.show_operation_status() self.refresh_btn.setEnabled(False) self.refresh_btn.setText("🔄 Working...") - # Connect the finished signal from the modal - playlist_item_widget.download_modal.process_finished.connect( - lambda: self.on_download_process_finished(playlist_id) - ) + # --- FIX: Connect the finished signal from the modal --- + # This ensures that when the modal is finished (or cancelled), the cleanup function is called. + if playlist_item_widget.download_modal: + playlist_item_widget.download_modal.process_finished.connect( + lambda: self.on_download_process_finished(playlist_id) + ) def on_download_process_finished(self, playlist_id): """Re-enables refresh button if no other downloads are active.""" - print(f"Download process finished for playlist: {playlist_id}.") + print(f"Download process finished or cancelled for playlist: {playlist_id}.") if playlist_id in self.active_download_processes: playlist_item_widget = self.active_download_processes.pop(playlist_id) - playlist_item_widget.download_modal = None - playlist_item_widget.hide_operation_status() + # --- FIX: Reset the UI state of the playlist item --- + if playlist_item_widget: + playlist_item_widget.download_modal = None + playlist_item_widget.hide_operation_status() if not self.active_download_processes: print("All download processes finished. Re-enabling refresh.") @@ -2833,6 +2839,10 @@ class DownloadMissingTracksModal(QDialog): def on_begin_search_clicked(self): """Handle Begin Search button click - starts Plex analysis""" + # --- FIX: Trigger the UI change on the main page --- + # This is the correct point to signal that the process has started. + self.parent_page.on_download_process_started(self.playlist.id, self.playlist_item) + self.begin_search_btn.hide() self.cancel_btn.show() self.analysis_progress.setVisible(True) @@ -2840,6 +2850,7 @@ class DownloadMissingTracksModal(QDialog): self.analysis_progress.setValue(0) self.download_in_progress = True # Set flag self.start_plex_analysis() + def start_plex_analysis(self): """Start Plex analysis using existing worker""" @@ -3179,24 +3190,66 @@ class DownloadMissingTracksModal(QDialog): f"Completed downloading {self.successful_downloads}/{len(self.missing_tracks)} missing tracks!") def on_cancel_clicked(self): - """Handle Cancel button - cancels operations and closes modal""" + """Handle Cancel button - cancels operations, emits finished signal, and closes modal.""" + # --- FIX: The full cancellation logic is now centralized here. --- self.cancel_operations() - self.reject() + self.process_finished.emit() # Signal the main page to clean up and reset the button. + self.reject() # Close the modal. def on_close_clicked(self): self.reject() def cancel_operations(self): - """Cancel any ongoing operations""" - self.cancel_requested = True + """Cancel any ongoing operations, including active slskd downloads.""" + print("🛑 Cancelling all operations for this playlist...") + self.cancel_requested = True # Flag to stop any new workers from starting. + + # --- FIX: Actively cancel downloads on the slskd server --- + if self.active_downloads: + print(f"Requesting cancellation for {len(self.active_downloads)} active download(s)...") + + import asyncio + try: + loop = asyncio.get_running_loop() + except RuntimeError: + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + + soulseek_client = self.parent_page.soulseek_client + + # Create tasks to cancel all active downloads concurrently + tasks = [] + for download_info in self.active_downloads: + download_id = download_info.get('download_id') + # Assumes the soulseek_client has a method to make raw API calls. + # A DELETE request is standard for cancellation in RESTful APIs like slskd's. + if download_id and hasattr(soulseek_client, '_make_request'): + tasks.append( + soulseek_client._make_request('DELETE', f'transfers/downloads/{download_id}') + ) + + if tasks: + try: + # Wait for all cancellation requests to be sent + loop.run_until_complete(asyncio.gather(*tasks, return_exceptions=True)) + print("All cancellation requests sent to slskd.") + except Exception as e: + print(f"An error occurred while sending cancellation requests: {e}") + + # Cancel background workers (like the initial Plex analysis) for worker in self.active_workers: - if hasattr(worker, 'cancel'): worker.cancel() + if hasattr(worker, 'cancel'): + worker.cancel() self.active_workers.clear() + + # Clean up any fallback thread pools for pool in self.fallback_pools: pool.waitForDone(1000) self.fallback_pools.clear() + + # Stop the status polling timer to prevent further checks self.download_status_timer.stop() - print("🛑 All operations cancelled successfully") + print("🛑 Modal operations cancelled successfully.") def closeEvent(self, event): """