From 7058559ddc7143b599a3acd03c03816b2c8bc30e Mon Sep 17 00:00:00 2001 From: value1338 Date: Fri, 3 Oct 2025 19:47:51 +0200 Subject: [PATCH 1/4] Add button to auto-delete already downloaded files and retry failed ones --- SpotiFLAC.py | 66 ++++++++++++++++++++++++++++++++++++++++++++++++---- version.json | 2 +- 2 files changed, 62 insertions(+), 6 deletions(-) diff --git a/SpotiFLAC.py b/SpotiFLAC.py index e60b1b8..9b1321d 100644 --- a/SpotiFLAC.py +++ b/SpotiFLAC.py @@ -59,7 +59,7 @@ class MetadataFetchWorker(QThread): self.error.emit(f'Failed to fetch metadata: {str(e)}') class DownloadWorker(QThread): - finished = pyqtSignal(bool, str, list) + finished = pyqtSignal(bool, str, list, list) progress = pyqtSignal(str, int) def __init__(self, tracks, outpath, is_single_track=False, is_album=False, is_playlist=False, @@ -82,6 +82,7 @@ class DownloadWorker(QThread): self.is_paused = False self.is_stopped = False self.failed_tracks = [] + self.successful_tracks = [] def get_formatted_filename(self, track): if self.filename_format == "artist_title": @@ -294,6 +295,7 @@ class DownloadWorker(QThread): self.progress.emit(f"Successfully downloaded: {track.title} - {track.artists}", int((i + 1) / total_tracks * 100)) + self.successful_tracks.append(track) except Exception as e: self.failed_tracks.append((track.title, track.artists, str(e))) self.progress.emit(f"Failed to download: {track.title} - {track.artists}\nError: {str(e)}", @@ -304,10 +306,12 @@ class DownloadWorker(QThread): success_message = "Download completed!" if self.failed_tracks: success_message += f"\n\nFailed downloads: {len(self.failed_tracks)} tracks" - self.finished.emit(True, success_message, self.failed_tracks) + if self.successful_tracks: + success_message += f"\n\nSuccessful downloads: {len(self.successful_tracks)} tracks" + self.finished.emit(True, success_message, self.failed_tracks, self.successful_tracks) except Exception as e: - self.finished.emit(False, str(e), self.failed_tracks) + self.finished.emit(False, str(e), self.failed_tracks, self.successful_tracks) def pause(self): self.is_paused = True @@ -643,6 +647,7 @@ class SpotiFLACGUI(QWidget): self.current_version = "4.6" self.tracks = [] self.all_tracks = [] + self.successful_downloads = [] self.reset_state() self.settings = QSettings('SpotiFLAC', 'Settings') @@ -1016,19 +1021,24 @@ class SpotiFLACGUI(QWidget): control_layout = QHBoxLayout() self.stop_btn = QPushButton('Stop') self.pause_resume_btn = QPushButton('Pause') + self.remove_successful_btn = QPushButton('Remove Successful Downloads') self.stop_btn.setFixedWidth(120) self.pause_resume_btn.setFixedWidth(120) + self.remove_successful_btn.setFixedWidth(200) self.stop_btn.setCursor(Qt.CursorShape.PointingHandCursor) self.pause_resume_btn.setCursor(Qt.CursorShape.PointingHandCursor) + self.remove_successful_btn.setCursor(Qt.CursorShape.PointingHandCursor) self.stop_btn.clicked.connect(self.stop_download) self.pause_resume_btn.clicked.connect(self.toggle_pause_resume) + self.remove_successful_btn.clicked.connect(self.remove_successful_downloads) control_layout.addStretch() control_layout.addWidget(self.stop_btn) control_layout.addWidget(self.pause_resume_btn) + control_layout.addWidget(self.remove_successful_btn) control_layout.addStretch() process_layout.addLayout(control_layout) @@ -1041,6 +1051,7 @@ class SpotiFLACGUI(QWidget): self.time_label.hide() self.stop_btn.hide() self.pause_resume_btn.hide() + self.remove_successful_btn.hide() def setup_settings_tab(self): settings_tab = QWidget() @@ -1953,7 +1964,7 @@ class SpotiFLACGUI(QWidget): qobuz_region, qobuz_mode ) - self.worker.finished.connect(self.on_download_finished) + self.worker.finished.connect(lambda success, message, failed_tracks, successful_tracks: self.on_download_finished(success, message, failed_tracks, successful_tracks)) self.worker.progress.connect(self.update_progress) self.worker.start() self.start_timer() @@ -1987,13 +1998,23 @@ class SpotiFLACGUI(QWidget): self.stop_timer() self.on_download_finished(True, "Download stopped by user.", []) - def on_download_finished(self, success, message, failed_tracks): + def on_download_finished(self, success, message, failed_tracks, successful_tracks=None): self.progress_bar.hide() self.stop_btn.hide() self.pause_resume_btn.hide() self.pause_resume_btn.setText('Pause') self.stop_timer() + # Store successful downloads for later removal + if successful_tracks is not None: + self.successful_downloads = successful_tracks + + # Show remove successful button if there are successful downloads + if hasattr(self, 'successful_downloads') and self.successful_downloads: + self.remove_successful_btn.show() + else: + self.remove_successful_btn.hide() + self.download_selected_btn.setEnabled(True) self.download_all_btn.setEnabled(True) @@ -2024,6 +2045,41 @@ class SpotiFLACGUI(QWidget): self.worker.pause() self.pause_resume_btn.setText('Resume') + def remove_successful_downloads(self): + """Remove successfully downloaded tracks from the dashboard""" + if not hasattr(self, 'successful_downloads') or not self.successful_downloads: + # Show message on process tab since user is still there + self.log_output.append("No successful downloads to remove.") + return + + # Find successful tracks in the track list + tracks_to_remove = [] + for track in self.tracks: + for successful_track in self.successful_downloads: + if (track.title == successful_track.title and + track.artists == successful_track.artists and + track.album == successful_track.album): + tracks_to_remove.append(track) + break + + if tracks_to_remove: + # Remove tracks from both lists + for track in tracks_to_remove: + if track in self.tracks: + self.tracks.remove(track) + if track in self.all_tracks: + self.all_tracks.remove(track) + + self.update_track_list_display() + self.log_output.append(f"Removed {len(tracks_to_remove)} successfully downloaded tracks from the list.") + # Switch to dashboard after showing the message + self.tab_widget.setCurrentIndex(0) + else: + self.log_output.append("No matching tracks found in the current list.") + + # Hide the button after use + self.remove_successful_btn.hide() + def remove_selected_tracks(self): if not self.is_single_track: selected_items = self.track_list.selectedItems() diff --git a/version.json b/version.json index a925abd..e570051 100644 --- a/version.json +++ b/version.json @@ -1,3 +1,3 @@ { - "version": "4.6" + "version": "4.7" } From 9e403ab1bafde050516b3d3aad8c021f7affcc94 Mon Sep 17 00:00:00 2001 From: value1338 Date: Fri, 3 Oct 2025 20:21:12 +0200 Subject: [PATCH 2/4] deleted comments in the code --- SpotiFLAC.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/SpotiFLAC.py b/SpotiFLAC.py index 9b1321d..d54ede1 100644 --- a/SpotiFLAC.py +++ b/SpotiFLAC.py @@ -2005,11 +2005,9 @@ class SpotiFLACGUI(QWidget): self.pause_resume_btn.setText('Pause') self.stop_timer() - # Store successful downloads for later removal if successful_tracks is not None: self.successful_downloads = successful_tracks - # Show remove successful button if there are successful downloads if hasattr(self, 'successful_downloads') and self.successful_downloads: self.remove_successful_btn.show() else: @@ -2048,11 +2046,9 @@ class SpotiFLACGUI(QWidget): def remove_successful_downloads(self): """Remove successfully downloaded tracks from the dashboard""" if not hasattr(self, 'successful_downloads') or not self.successful_downloads: - # Show message on process tab since user is still there self.log_output.append("No successful downloads to remove.") return - # Find successful tracks in the track list tracks_to_remove = [] for track in self.tracks: for successful_track in self.successful_downloads: @@ -2063,7 +2059,6 @@ class SpotiFLACGUI(QWidget): break if tracks_to_remove: - # Remove tracks from both lists for track in tracks_to_remove: if track in self.tracks: self.tracks.remove(track) @@ -2072,12 +2067,10 @@ class SpotiFLACGUI(QWidget): self.update_track_list_display() self.log_output.append(f"Removed {len(tracks_to_remove)} successfully downloaded tracks from the list.") - # Switch to dashboard after showing the message self.tab_widget.setCurrentIndex(0) else: self.log_output.append("No matching tracks found in the current list.") - # Hide the button after use self.remove_successful_btn.hide() def remove_selected_tracks(self): From e2ad51da34264c68c02246acf80d45a2d01cd90e Mon Sep 17 00:00:00 2001 From: value1338 Date: Sat, 4 Oct 2025 13:03:10 +0200 Subject: [PATCH 3/4] included Skipped Songs for Removal from Playlist --- SpotiFLAC.py | 60 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 47 insertions(+), 13 deletions(-) diff --git a/SpotiFLAC.py b/SpotiFLAC.py index d54ede1..d150a50 100644 --- a/SpotiFLAC.py +++ b/SpotiFLAC.py @@ -59,7 +59,7 @@ class MetadataFetchWorker(QThread): self.error.emit(f'Failed to fetch metadata: {str(e)}') class DownloadWorker(QThread): - finished = pyqtSignal(bool, str, list, list) + finished = pyqtSignal(bool, str, list, list, list) progress = pyqtSignal(str, int) def __init__(self, tracks, outpath, is_single_track=False, is_album=False, is_playlist=False, @@ -83,6 +83,7 @@ class DownloadWorker(QThread): self.is_stopped = False self.failed_tracks = [] self.successful_tracks = [] + self.skipped_tracks = [] def get_formatted_filename(self, track): if self.filename_format == "artist_title": @@ -157,6 +158,7 @@ class DownloadWorker(QThread): self.progress.emit(f"File already exists: {new_filename}. Skipping download.", 0) self.progress.emit(f"Skipped: {track.title} - {track.artists}", int((i + 1) / total_tracks * 100)) + self.skipped_tracks.append(track) continue if self.service == "qobuz": @@ -205,6 +207,7 @@ class DownloadWorker(QThread): elif isinstance(download_result_details, dict) and (download_result_details.get("status") == "all_skipped" or download_result_details.get("status") == "skipped_exists"): self.progress.emit(f"File already exists or skipped: {new_filename}",0) downloaded_file = new_filepath + self.skipped_tracks.append(track) else: downloaded_file = None raise Exception(f"Tidal download failed or returned unexpected result: {download_result_details}") @@ -281,6 +284,7 @@ class DownloadWorker(QThread): self.progress.emit(f"File already exists: {new_filename}", 0) self.progress.emit(f"Skipped: {track.title} - {track.artists}", int((i + 1) / total_tracks * 100)) + self.skipped_tracks.append(track) continue if downloaded_file != new_filepath: @@ -308,10 +312,12 @@ class DownloadWorker(QThread): success_message += f"\n\nFailed downloads: {len(self.failed_tracks)} tracks" if self.successful_tracks: success_message += f"\n\nSuccessful downloads: {len(self.successful_tracks)} tracks" - self.finished.emit(True, success_message, self.failed_tracks, self.successful_tracks) + if self.skipped_tracks: + success_message += f"\n\nSkipped (already exists): {len(self.skipped_tracks)} tracks" + self.finished.emit(True, success_message, self.failed_tracks, self.successful_tracks, self.skipped_tracks) except Exception as e: - self.finished.emit(False, str(e), self.failed_tracks, self.successful_tracks) + self.finished.emit(False, str(e), self.failed_tracks, self.successful_tracks, self.skipped_tracks) def pause(self): self.is_paused = True @@ -1021,7 +1027,7 @@ class SpotiFLACGUI(QWidget): control_layout = QHBoxLayout() self.stop_btn = QPushButton('Stop') self.pause_resume_btn = QPushButton('Pause') - self.remove_successful_btn = QPushButton('Remove Successful Downloads') + self.remove_successful_btn = QPushButton('Remove Finished Songs') self.stop_btn.setFixedWidth(120) self.pause_resume_btn.setFixedWidth(120) @@ -1964,7 +1970,7 @@ class SpotiFLACGUI(QWidget): qobuz_region, qobuz_mode ) - self.worker.finished.connect(lambda success, message, failed_tracks, successful_tracks: self.on_download_finished(success, message, failed_tracks, successful_tracks)) + self.worker.finished.connect(lambda success, message, failed_tracks, successful_tracks, skipped_tracks: self.on_download_finished(success, message, failed_tracks, successful_tracks, skipped_tracks)) self.worker.progress.connect(self.update_progress) self.worker.start() self.start_timer() @@ -1996,9 +2002,9 @@ class SpotiFLACGUI(QWidget): if hasattr(self, 'worker'): self.worker.stop() self.stop_timer() - self.on_download_finished(True, "Download stopped by user.", []) + self.on_download_finished(True, "Download stopped by user.", [], [], []) - def on_download_finished(self, success, message, failed_tracks, successful_tracks=None): + def on_download_finished(self, success, message, failed_tracks, successful_tracks=None, skipped_tracks=None): self.progress_bar.hide() self.stop_btn.hide() self.pause_resume_btn.hide() @@ -2007,8 +2013,10 @@ class SpotiFLACGUI(QWidget): if successful_tracks is not None: self.successful_downloads = successful_tracks + if skipped_tracks is not None: + self.skipped_downloads = skipped_tracks - if hasattr(self, 'successful_downloads') and self.successful_downloads: + if (hasattr(self, 'successful_downloads') and self.successful_downloads) or (hasattr(self, 'skipped_downloads') and self.skipped_downloads): self.remove_successful_btn.show() else: self.remove_successful_btn.hide() @@ -2044,20 +2052,35 @@ class SpotiFLACGUI(QWidget): self.pause_resume_btn.setText('Resume') def remove_successful_downloads(self): - """Remove successfully downloaded tracks from the dashboard""" - if not hasattr(self, 'successful_downloads') or not self.successful_downloads: - self.log_output.append("No successful downloads to remove.") + """Remove successfully downloaded and skipped tracks from the dashboard""" + successful_tracks = getattr(self, 'successful_downloads', []) + skipped_tracks = getattr(self, 'skipped_downloads', []) + + if not successful_tracks and not skipped_tracks: + self.log_output.append("No downloaded or skipped tracks to remove.") return tracks_to_remove = [] + + # Check for successful downloads for track in self.tracks: - for successful_track in self.successful_downloads: + for successful_track in successful_tracks: if (track.title == successful_track.title and track.artists == successful_track.artists and track.album == successful_track.album): tracks_to_remove.append(track) break + # Check for skipped tracks (already exists) + for track in self.tracks: + for skipped_track in skipped_tracks: + if (track.title == skipped_track.title and + track.artists == skipped_track.artists and + track.album == skipped_track.album): + if track not in tracks_to_remove: # Avoid duplicates + tracks_to_remove.append(track) + break + if tracks_to_remove: for track in tracks_to_remove: if track in self.tracks: @@ -2066,7 +2089,18 @@ class SpotiFLACGUI(QWidget): self.all_tracks.remove(track) self.update_track_list_display() - self.log_output.append(f"Removed {len(tracks_to_remove)} successfully downloaded tracks from the list.") + successful_count = len([t for t in tracks_to_remove if t in successful_tracks]) + skipped_count = len([t for t in tracks_to_remove if t in skipped_tracks]) + + message = f"Removed {len(tracks_to_remove)} tracks from the list" + if successful_count > 0: + message += f" ({successful_count} downloaded" + if skipped_count > 0: + message += f", {skipped_count} already existed" if successful_count > 0 else f" ({skipped_count} already existed" + if successful_count > 0 or skipped_count > 0: + message += ")" + + self.log_output.append(message + ".") self.tab_widget.setCurrentIndex(0) else: self.log_output.append("No matching tracks found in the current list.") From f0e71261a501fec018fd2a395af150eb9dd3bc87 Mon Sep 17 00:00:00 2001 From: afkarxyz Date: Sun, 5 Oct 2025 03:39:40 +0700 Subject: [PATCH 4/4] Update version.json --- version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.json b/version.json index e570051..a925abd 100644 --- a/version.json +++ b/version.json @@ -1,3 +1,3 @@ { - "version": "4.7" + "version": "4.6" }