diff --git a/tidal_dl_ng/dialog.py b/tidal_dl_ng/dialog.py index 073e016..4e36d8a 100644 --- a/tidal_dl_ng/dialog.py +++ b/tidal_dl_ng/dialog.py @@ -162,7 +162,7 @@ class DialogPreferences(QtWidgets.QDialog): ] def _init_spin_box(self): - self.parameters_spin_box = ["album_track_num_pad_min"] + self.parameters_spin_box = ["album_track_num_pad_min", "downloads_concurrent_max"] def _init_comboboxes(self): self.parameters_combo = [ diff --git a/tidal_dl_ng/download.py b/tidal_dl_ng/download.py index 83d8743..af00497 100644 --- a/tidal_dl_ng/download.py +++ b/tidal_dl_ng/download.py @@ -621,22 +621,30 @@ class Download: # Iterate through list items while not self.progress.finished: - for item_media in items: - # Download the item. - status, result_path_file = self.item( - media=item_media, - file_template=file_name_relative, - quality_audio=quality_audio, - quality_video=quality_video, - download_delay=download_delay, - is_parent_album=is_album, - ) + with futures.ThreadPoolExecutor(max_workers=self.settings.data.downloads_concurrent_max) as executor: + # Dispatch all download tasks to worker threads + l_futures: [any] = [ + executor.submit( + self.item, + media=item_media, + file_template=file_name_relative, + quality_audio=quality_audio, + quality_video=quality_video, + download_delay=download_delay, + is_parent_album=is_album, + ) + for item_media in items + ] + # Report results as they become available + for future in futures.as_completed(l_futures): + # Retrieve result + status, result_path_file = future.result() - # Advance progress bar. - self.progress.advance(p_task1) + # Advance progress bar. + self.progress.advance(p_task1) - if not progress_stdout: - self.progress_gui.list_item.emit(self.progress.tasks[p_task1].percentage) + if not progress_stdout: + self.progress_gui.list_item.emit(self.progress.tasks[p_task1].percentage) self.fn_logger.info(f"Finished list '{list_media_name}'.") diff --git a/tidal_dl_ng/model/cfg.py b/tidal_dl_ng/model/cfg.py index bf01814..88636f1 100644 --- a/tidal_dl_ng/model/cfg.py +++ b/tidal_dl_ng/model/cfg.py @@ -40,7 +40,8 @@ class Settings: downloads_simultaneous_per_track_max: int = 20 download_delay_sec_min: float = 3.0 download_delay_sec_max: float = 5.0 - album_track_num_pad_min: int = 0 + album_track_num_pad_min: int = 1 + downloads_concurrent_max: int = 3 @dataclass_json @@ -86,8 +87,9 @@ class HelpSettings: download_delay_sec_min: str = "Lower boundary for the calculation of the download delay in seconds." download_delay_sec_max: str = "Upper boundary for the calculation of the download delay in seconds." album_track_num_pad_min: str = ( - "Minimum length of the album track count, will be padded with zeroes (0). To disable " "padding set this to 0." + "Minimum length of the album track count, will be padded with zeroes (0). To disable padding set this to 1." ) + downloads_concurrent_max: str = "Maximum concurrent number of downloads (threads)." @dataclass_json diff --git a/tidal_dl_ng/ui/dialog_settings.py b/tidal_dl_ng/ui/dialog_settings.py index d3d2401..945af92 100644 --- a/tidal_dl_ng/ui/dialog_settings.py +++ b/tidal_dl_ng/ui/dialog_settings.py @@ -27,7 +27,7 @@ class Ui_DialogSettings: def setupUi(self, DialogSettings): if not DialogSettings.objectName(): DialogSettings.setObjectName("DialogSettings") - DialogSettings.resize(640, 705) + DialogSettings.resize(640, 767) sizePolicy = QSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) sizePolicy.setHorizontalStretch(100) sizePolicy.setVerticalStretch(100) @@ -293,6 +293,27 @@ class Ui_DialogSettings: self.verticalLayout_8.addLayout(self.horizontalLayout_9) + self.horizontalLayout_11 = QHBoxLayout() + self.horizontalLayout_11.setObjectName("horizontalLayout_11") + self.l_downloads_concurrent_max = QLabel(self.gb_numbers) + self.l_downloads_concurrent_max.setObjectName("l_downloads_concurrent_max") + + self.horizontalLayout_11.addWidget(self.l_downloads_concurrent_max) + + self.l_icon_downloads_concurrent_max = QLabel(self.gb_numbers) + self.l_icon_downloads_concurrent_max.setObjectName("l_icon_downloads_concurrent_max") + + self.horizontalLayout_11.addWidget(self.l_icon_downloads_concurrent_max) + + self.sb_downloads_concurrent_max = QSpinBox(self.gb_numbers) + self.sb_downloads_concurrent_max.setObjectName("sb_downloads_concurrent_max") + self.sb_downloads_concurrent_max.setMinimum(1) + self.sb_downloads_concurrent_max.setMaximum(5) + + self.horizontalLayout_11.addWidget(self.sb_downloads_concurrent_max) + + self.verticalLayout_8.addLayout(self.horizontalLayout_11) + self.lv_main.addWidget(self.gb_numbers) self.gb_path = QGroupBox(DialogSettings) @@ -563,6 +584,8 @@ class Ui_DialogSettings: self.gb_numbers.setTitle(QCoreApplication.translate("DialogSettings", "Numbers", None)) self.l_album_track_num_pad_min.setText(QCoreApplication.translate("DialogSettings", "TextLabel", None)) self.l_icon_album_track_num_pad_min.setText(QCoreApplication.translate("DialogSettings", "TextLabel", None)) + self.l_downloads_concurrent_max.setText(QCoreApplication.translate("DialogSettings", "TextLabel", None)) + self.l_icon_downloads_concurrent_max.setText(QCoreApplication.translate("DialogSettings", "TextLabel", None)) self.gb_path.setTitle(QCoreApplication.translate("DialogSettings", "Path", None)) self.l_icon_download_base_path.setText(QCoreApplication.translate("DialogSettings", "TextLabel", None)) self.l_download_base_path.setText(QCoreApplication.translate("DialogSettings", "TextLabel", None)) diff --git a/tidal_dl_ng/ui/dialog_settings.ui b/tidal_dl_ng/ui/dialog_settings.ui index bff04c7..d81701a 100644 --- a/tidal_dl_ng/ui/dialog_settings.ui +++ b/tidal_dl_ng/ui/dialog_settings.ui @@ -7,7 +7,7 @@ 0 0 640 - 705 + 767 @@ -386,6 +386,34 @@ + + + + + + TextLabel + + + + + + + TextLabel + + + + + + + 1 + + + 5 + + + + +