v4.3
This commit is contained in:
+44
-45
@@ -58,9 +58,10 @@ class MetadataFetchWorker(QThread):
|
|||||||
class DownloadWorker(QThread):
|
class DownloadWorker(QThread):
|
||||||
finished = pyqtSignal(bool, str, list)
|
finished = pyqtSignal(bool, str, list)
|
||||||
progress = pyqtSignal(str, int)
|
progress = pyqtSignal(str, int)
|
||||||
|
|
||||||
def __init__(self, tracks, outpath, is_single_track=False, is_album=False, is_playlist=False,
|
def __init__(self, tracks, outpath, is_single_track=False, is_album=False, is_playlist=False,
|
||||||
album_or_playlist_name='', filename_format='title_artist', use_track_numbers=True,
|
album_or_playlist_name='', filename_format='title_artist', use_track_numbers=True,
|
||||||
use_album_subfolders=False, service="tidal", qobuz_region="us"):
|
use_artist_subfolders=False, use_album_subfolders=False, service="tidal", qobuz_region="us"):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.tracks = tracks
|
self.tracks = tracks
|
||||||
self.outpath = outpath
|
self.outpath = outpath
|
||||||
@@ -70,6 +71,7 @@ class DownloadWorker(QThread):
|
|||||||
self.album_or_playlist_name = album_or_playlist_name
|
self.album_or_playlist_name = album_or_playlist_name
|
||||||
self.filename_format = filename_format
|
self.filename_format = filename_format
|
||||||
self.use_track_numbers = use_track_numbers
|
self.use_track_numbers = use_track_numbers
|
||||||
|
self.use_artist_subfolders = use_artist_subfolders
|
||||||
self.use_album_subfolders = use_album_subfolders
|
self.use_album_subfolders = use_album_subfolders
|
||||||
self.service = service
|
self.service = service
|
||||||
self.qobuz_region = qobuz_region
|
self.qobuz_region = qobuz_region
|
||||||
@@ -96,11 +98,9 @@ class DownloadWorker(QThread):
|
|||||||
downloader = DeezerDownloader()
|
downloader = DeezerDownloader()
|
||||||
else:
|
else:
|
||||||
downloader = TidalDownloader()
|
downloader = TidalDownloader()
|
||||||
|
|
||||||
def progress_update(current, total):
|
def progress_update(current, total):
|
||||||
if total > 0:
|
if total <= 0:
|
||||||
percent = (current / total) * 100
|
|
||||||
self.progress.emit("", int(percent))
|
|
||||||
else:
|
|
||||||
self.progress.emit("Processing metadata...", 0)
|
self.progress.emit("Processing metadata...", 0)
|
||||||
|
|
||||||
downloader.set_progress_callback(progress_update)
|
downloader.set_progress_callback(progress_update)
|
||||||
@@ -119,14 +119,23 @@ class DownloadWorker(QThread):
|
|||||||
int((i) / total_tracks * 100))
|
int((i) / total_tracks * 100))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if self.is_playlist and self.use_album_subfolders:
|
if self.is_playlist:
|
||||||
album_folder = re.sub(r'[<>:"/\\|?*]', '_', track.album)
|
track_outpath = self.outpath
|
||||||
track_outpath = os.path.join(self.outpath, album_folder)
|
|
||||||
|
if self.use_artist_subfolders:
|
||||||
|
artist_name = track.artists.split(', ')[0] if ', ' in track.artists else track.artists
|
||||||
|
artist_folder = re.sub(r'[<>:"/\\|?*]', lambda m: "'" if m.group() == '"' else '_', artist_name)
|
||||||
|
track_outpath = os.path.join(track_outpath, artist_folder)
|
||||||
|
|
||||||
|
if self.use_album_subfolders:
|
||||||
|
album_folder = re.sub(r'[<>:"/\\|?*]', lambda m: "'" if m.group() == '"' else '_', track.album)
|
||||||
|
track_outpath = os.path.join(track_outpath, album_folder)
|
||||||
|
|
||||||
os.makedirs(track_outpath, exist_ok=True)
|
os.makedirs(track_outpath, exist_ok=True)
|
||||||
else:
|
else:
|
||||||
track_outpath = self.outpath
|
track_outpath = self.outpath
|
||||||
|
|
||||||
if (self.is_album or (self.is_playlist and self.use_album_subfolders)) and self.use_track_numbers:
|
if (self.is_album or self.is_playlist) and self.use_track_numbers:
|
||||||
new_filename = f"{track.track_number:02d} - {self.get_formatted_filename(track)}"
|
new_filename = f"{track.track_number:02d} - {self.get_formatted_filename(track)}"
|
||||||
else:
|
else:
|
||||||
new_filename = self.get_formatted_filename(track)
|
new_filename = self.get_formatted_filename(track)
|
||||||
@@ -564,7 +573,7 @@ class QobuzRegionComboBox(QComboBox):
|
|||||||
class SpotiFLACGUI(QWidget):
|
class SpotiFLACGUI(QWidget):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.current_version = "4.2"
|
self.current_version = "4.3"
|
||||||
self.tracks = []
|
self.tracks = []
|
||||||
self.all_tracks = []
|
self.all_tracks = []
|
||||||
self.reset_state()
|
self.reset_state()
|
||||||
@@ -575,6 +584,7 @@ class SpotiFLACGUI(QWidget):
|
|||||||
|
|
||||||
self.filename_format = self.settings.value('filename_format', 'title_artist')
|
self.filename_format = self.settings.value('filename_format', 'title_artist')
|
||||||
self.use_track_numbers = self.settings.value('use_track_numbers', False, type=bool)
|
self.use_track_numbers = self.settings.value('use_track_numbers', False, type=bool)
|
||||||
|
self.use_artist_subfolders = self.settings.value('use_artist_subfolders', False, type=bool)
|
||||||
self.use_album_subfolders = self.settings.value('use_album_subfolders', False, type=bool)
|
self.use_album_subfolders = self.settings.value('use_album_subfolders', False, type=bool)
|
||||||
self.service = self.settings.value('service', 'tidal')
|
self.service = self.settings.value('service', 'tidal')
|
||||||
self.qobuz_region = self.settings.value('qobuz_region', 'us')
|
self.qobuz_region = self.settings.value('qobuz_region', 'us')
|
||||||
@@ -798,7 +808,6 @@ class SpotiFLACGUI(QWidget):
|
|||||||
self.search_input.textChanged.connect(self.filter_tracks)
|
self.search_input.textChanged.connect(self.filter_tracks)
|
||||||
self.search_input.setFixedWidth(250)
|
self.search_input.setFixedWidth(250)
|
||||||
|
|
||||||
|
|
||||||
search_input_layout.addWidget(self.search_input)
|
search_input_layout.addWidget(self.search_input)
|
||||||
search_layout.addLayout(search_input_layout)
|
search_layout.addLayout(search_input_layout)
|
||||||
|
|
||||||
@@ -971,18 +980,24 @@ class SpotiFLACGUI(QWidget):
|
|||||||
|
|
||||||
checkbox_layout = QHBoxLayout()
|
checkbox_layout = QHBoxLayout()
|
||||||
|
|
||||||
self.track_number_checkbox = QCheckBox('Add Track Numbers to Album Files')
|
self.artist_subfolder_checkbox = QCheckBox('Artist Subfolder (Playlist)')
|
||||||
self.track_number_checkbox.setCursor(Qt.CursorShape.PointingHandCursor)
|
self.artist_subfolder_checkbox.setCursor(Qt.CursorShape.PointingHandCursor)
|
||||||
self.track_number_checkbox.setChecked(self.use_track_numbers)
|
self.artist_subfolder_checkbox.setChecked(self.use_artist_subfolders)
|
||||||
self.track_number_checkbox.toggled.connect(self.save_track_numbering)
|
self.artist_subfolder_checkbox.toggled.connect(self.save_artist_subfolder_setting)
|
||||||
checkbox_layout.addWidget(self.track_number_checkbox)
|
checkbox_layout.addWidget(self.artist_subfolder_checkbox)
|
||||||
|
|
||||||
self.album_subfolder_checkbox = QCheckBox('Create Album Subfolders for Playlist Downloads')
|
self.album_subfolder_checkbox = QCheckBox('Album Subfolder (Playlist)')
|
||||||
self.album_subfolder_checkbox.setCursor(Qt.CursorShape.PointingHandCursor)
|
self.album_subfolder_checkbox.setCursor(Qt.CursorShape.PointingHandCursor)
|
||||||
self.album_subfolder_checkbox.setChecked(self.use_album_subfolders)
|
self.album_subfolder_checkbox.setChecked(self.use_album_subfolders)
|
||||||
self.album_subfolder_checkbox.toggled.connect(self.save_album_subfolder_setting)
|
self.album_subfolder_checkbox.toggled.connect(self.save_album_subfolder_setting)
|
||||||
checkbox_layout.addWidget(self.album_subfolder_checkbox)
|
checkbox_layout.addWidget(self.album_subfolder_checkbox)
|
||||||
|
|
||||||
|
self.track_number_checkbox = QCheckBox('Track Number for Album')
|
||||||
|
self.track_number_checkbox.setCursor(Qt.CursorShape.PointingHandCursor)
|
||||||
|
self.track_number_checkbox.setChecked(self.use_track_numbers)
|
||||||
|
self.track_number_checkbox.toggled.connect(self.save_track_numbering)
|
||||||
|
checkbox_layout.addWidget(self.track_number_checkbox)
|
||||||
|
|
||||||
checkbox_layout.addStretch()
|
checkbox_layout.addStretch()
|
||||||
file_layout.addLayout(checkbox_layout)
|
file_layout.addLayout(checkbox_layout)
|
||||||
|
|
||||||
@@ -1016,8 +1031,6 @@ class SpotiFLACGUI(QWidget):
|
|||||||
region_label.hide()
|
region_label.hide()
|
||||||
self.qobuz_region_dropdown.hide()
|
self.qobuz_region_dropdown.hide()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
service_fallback_layout.addStretch()
|
service_fallback_layout.addStretch()
|
||||||
auth_layout.addLayout(service_fallback_layout)
|
auth_layout.addLayout(service_fallback_layout)
|
||||||
|
|
||||||
@@ -1028,8 +1041,6 @@ class SpotiFLACGUI(QWidget):
|
|||||||
self.set_combobox_value(self.service_dropdown, self.service)
|
self.set_combobox_value(self.service_dropdown, self.service)
|
||||||
self.set_combobox_value(self.qobuz_region_dropdown, self.qobuz_region)
|
self.set_combobox_value(self.qobuz_region_dropdown, self.qobuz_region)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
self.update_service_ui()
|
self.update_service_ui()
|
||||||
|
|
||||||
self.qobuz_region_dropdown.status_updated.connect(
|
self.qobuz_region_dropdown.status_updated.connect(
|
||||||
@@ -1237,7 +1248,7 @@ class SpotiFLACGUI(QWidget):
|
|||||||
|
|
||||||
about_layout.addWidget(section_widget)
|
about_layout.addWidget(section_widget)
|
||||||
|
|
||||||
footer_label = QLabel(f"v{self.current_version} | July 2025")
|
footer_label = QLabel(f"v{self.current_version} | August 2025")
|
||||||
footer_label.setStyleSheet("font-size: 12px; margin-top: 20px;")
|
footer_label.setStyleSheet("font-size: 12px; margin-top: 20px;")
|
||||||
about_layout.addWidget(footer_label, alignment=Qt.AlignmentFlag.AlignCenter)
|
about_layout.addWidget(footer_label, alignment=Qt.AlignmentFlag.AlignCenter)
|
||||||
|
|
||||||
@@ -1293,6 +1304,12 @@ class SpotiFLACGUI(QWidget):
|
|||||||
self.use_track_numbers = self.track_number_checkbox.isChecked()
|
self.use_track_numbers = self.track_number_checkbox.isChecked()
|
||||||
self.settings.setValue('use_track_numbers', self.use_track_numbers)
|
self.settings.setValue('use_track_numbers', self.use_track_numbers)
|
||||||
self.settings.sync()
|
self.settings.sync()
|
||||||
|
|
||||||
|
def save_artist_subfolder_setting(self):
|
||||||
|
self.use_artist_subfolders = self.artist_subfolder_checkbox.isChecked()
|
||||||
|
self.settings.setValue('use_artist_subfolders', self.use_artist_subfolders)
|
||||||
|
self.settings.sync()
|
||||||
|
|
||||||
def save_album_subfolder_setting(self):
|
def save_album_subfolder_setting(self):
|
||||||
self.use_album_subfolders = self.album_subfolder_checkbox.isChecked()
|
self.use_album_subfolders = self.album_subfolder_checkbox.isChecked()
|
||||||
self.settings.setValue('use_album_subfolders', self.use_album_subfolders)
|
self.settings.setValue('use_album_subfolders', self.use_album_subfolders)
|
||||||
@@ -1305,8 +1322,6 @@ class SpotiFLACGUI(QWidget):
|
|||||||
self.settings.sync()
|
self.settings.sync()
|
||||||
self.log_output.append(f"Qobuz region setting saved: {self.qobuz_region_dropdown.currentText()}")
|
self.log_output.append(f"Qobuz region setting saved: {self.qobuz_region_dropdown.currentText()}")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def save_settings(self):
|
def save_settings(self):
|
||||||
self.settings.setValue('output_path', self.output_dir.text().strip())
|
self.settings.setValue('output_path', self.output_dir.text().strip())
|
||||||
self.settings.sync()
|
self.settings.sync()
|
||||||
@@ -1429,7 +1444,7 @@ class SpotiFLACGUI(QWidget):
|
|||||||
title=track["name"],
|
title=track["name"],
|
||||||
artists=track["artists"],
|
artists=track["artists"],
|
||||||
album=track["album_name"],
|
album=track["album_name"],
|
||||||
track_number=len(self.tracks) + 1,
|
track_number=track.get("track_number", len(self.tracks) + 1),
|
||||||
duration_ms=track.get("duration_ms", 0),
|
duration_ms=track.get("duration_ms", 0),
|
||||||
id=track_id,
|
id=track_id,
|
||||||
isrc=track.get("isrc", "")
|
isrc=track.get("isrc", "")
|
||||||
@@ -1601,6 +1616,7 @@ class SpotiFLACGUI(QWidget):
|
|||||||
self.start_download_worker(tracks_to_download, outpath)
|
self.start_download_worker(tracks_to_download, outpath)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.log_output.append(f"Error: An error occurred while starting the download: {str(e)}")
|
self.log_output.append(f"Error: An error occurred while starting the download: {str(e)}")
|
||||||
|
|
||||||
def start_download_worker(self, tracks_to_download, outpath):
|
def start_download_worker(self, tracks_to_download, outpath):
|
||||||
service = self.service_dropdown.currentData()
|
service = self.service_dropdown.currentData()
|
||||||
qobuz_region = self.qobuz_region_dropdown.currentData() if service == "qobuz" else "us"
|
qobuz_region = self.qobuz_region_dropdown.currentData() if service == "qobuz" else "us"
|
||||||
@@ -1614,6 +1630,7 @@ class SpotiFLACGUI(QWidget):
|
|||||||
self.album_or_playlist_name,
|
self.album_or_playlist_name,
|
||||||
self.filename_format,
|
self.filename_format,
|
||||||
self.use_track_numbers,
|
self.use_track_numbers,
|
||||||
|
self.use_artist_subfolders,
|
||||||
self.use_album_subfolders,
|
self.use_album_subfolders,
|
||||||
service,
|
service,
|
||||||
qobuz_region
|
qobuz_region
|
||||||
@@ -1641,27 +1658,9 @@ class SpotiFLACGUI(QWidget):
|
|||||||
self.tab_widget.setCurrentWidget(self.process_tab)
|
self.tab_widget.setCurrentWidget(self.process_tab)
|
||||||
|
|
||||||
def update_progress(self, message, percentage):
|
def update_progress(self, message, percentage):
|
||||||
if "Download progress:" in message or "Processing metadata..." in message:
|
self.log_output.append(message)
|
||||||
current_text = self.log_output.toPlainText()
|
|
||||||
|
|
||||||
if current_text:
|
|
||||||
lines = current_text.split('\n')
|
|
||||||
|
|
||||||
if "Download progress:" in lines[-1] or "Processing metadata..." in lines[-1]:
|
|
||||||
lines[-1] = message
|
|
||||||
|
|
||||||
new_text = '\n'.join(lines)
|
|
||||||
|
|
||||||
self.log_output.setPlainText(new_text)
|
|
||||||
|
|
||||||
self.log_output.moveCursor(QTextCursor.MoveOperation.End)
|
self.log_output.moveCursor(QTextCursor.MoveOperation.End)
|
||||||
else:
|
if percentage > 0:
|
||||||
self.log_output.append(message)
|
|
||||||
else:
|
|
||||||
self.log_output.append(message)
|
|
||||||
else:
|
|
||||||
self.log_output.append(message)
|
|
||||||
if percentage > 0 and not "Download progress:" in message:
|
|
||||||
self.progress_bar.setValue(percentage)
|
self.progress_bar.setValue(percentage)
|
||||||
|
|
||||||
def stop_download(self):
|
def stop_download(self):
|
||||||
|
|||||||
Reference in New Issue
Block a user