From 632788d516aea0ee77cf119f9fcec054c5e8fe19 Mon Sep 17 00:00:00 2001 From: Justin Donofrio Date: Sat, 30 Nov 2024 21:29:39 -0500 Subject: [PATCH] Add additional download workers --- src/onthespot/cli.py | 6 ++- src/onthespot/downloader.py | 26 +++++++++-- src/onthespot/gui/dl_progressbtn.py | 2 + src/onthespot/gui/mainui.py | 18 +++---- src/onthespot/gui/qtui/main.ui | 67 ++++++++++++++++++++------- src/onthespot/gui/settings.py | 4 +- src/onthespot/otsconfig.py | 1 + src/onthespot/static/style.css | 2 +- src/onthespot/templates/about.html | 2 +- src/onthespot/templates/search.html | 2 +- src/onthespot/templates/settings.html | 9 +++- src/onthespot/utils.py | 2 +- src/onthespot/web.py | 6 ++- 13 files changed, 104 insertions(+), 43 deletions(-) diff --git a/src/onthespot/cli.py b/src/onthespot/cli.py index 54aefaf..029585a 100644 --- a/src/onthespot/cli.py +++ b/src/onthespot/cli.py @@ -36,6 +36,7 @@ def run(self): with download_queue_lock: download_queue[local_id] = { 'local_id': local_id, + 'available': True, "item_service": item["item_service"], "item_type": item["item_type"], 'item_id': item['item_id'], @@ -68,8 +69,9 @@ def main(): queue_worker = QueueWorker() queue_worker.start() - download_worker = DownloadWorker() - download_worker.start() + for i in range(config.get('maximum_download_workers')): + downloadworker = DownloadWorker(gui=True) + downloadworker.start() fill_account_pool.wait() diff --git a/src/onthespot/downloader.py b/src/onthespot/downloader.py index 8e3adcc..d3d71d9 100644 --- a/src/onthespot/downloader.py +++ b/src/onthespot/downloader.py @@ -36,8 +36,10 @@ def start(self): def readd_item_to_download_queue(self, item): with download_queue_lock: try: - del download_queue[item['local_id']] - download_queue[item['local_id']] = item + local_id = item['local_id'] + del download_queue[local_id] + download_queue[local_id] = item + download_queue[local_id]['available'] = True except (KeyError): # Item likely cleared from queue return @@ -47,7 +49,21 @@ def run(self): if download_queue: try: try: - item = download_queue[next(iter(download_queue))] + # Mark item as unavailable for other download workers + iterator = iter(download_queue) + while True: + try: + local_id = next(iterator) + if download_queue[local_id]['available'] is False: + continue + with download_queue_lock: + download_queue[local_id]['available'] = False + item = download_queue[local_id] + break + except StopIteration: + # Queue is empty + break + item_service = item['item_service'] item_type = item['item_type'] item_id = item['item_id'] @@ -313,7 +329,7 @@ def yt_dlp_progress_hook(self, item, d): except (RuntimeError): # Likely Ratelimit - logger.info("Download failed: {item}") + logger.info(f"Download failed: {item}") item['item_status'] = 'Failed' if self.gui: self.progress.emit(item, self.tr("Failed"), 0) @@ -345,7 +361,7 @@ def yt_dlp_progress_hook(self, item, d): if self.gui: self.progress.emit(item, self.tr("Converting"), 99) - convert_audio_format(file_path, item_metadata, default_format) + convert_audio_format(file_path, default_format) embed_metadata(item, item_metadata) diff --git a/src/onthespot/gui/dl_progressbtn.py b/src/onthespot/gui/dl_progressbtn.py index 12f496d..1a633de 100644 --- a/src/onthespot/gui/dl_progressbtn.py +++ b/src/onthespot/gui/dl_progressbtn.py @@ -73,7 +73,9 @@ def delete_file(self): file_path = download_queue[self.local_id]['file_path'] file = os.path.abspath(file_path) os.remove(file) + download_queue[self.local_id]["item_status"] = 'Deleted' download_queue[self.local_id]["gui"]["status_label"].setText(self.tr("Deleted")) self.open_btn.hide() self.locate_btn.hide() self.delete_btn.hide() + self.retry_btn.show() diff --git a/src/onthespot/gui/mainui.py b/src/onthespot/gui/mainui.py index f7b96ea..629c7ba 100644 --- a/src/onthespot/gui/mainui.py +++ b/src/onthespot/gui/mainui.py @@ -88,12 +88,13 @@ def __init__(self, _dialog, start_url=''): fillaccountpool.start() queueworker = QueueWorker() - queueworker.add_item_to_download_list.connect(self.add_item_to_download_list) # Connect signal to update_table method + queueworker.add_item_to_download_list.connect(self.add_item_to_download_list) queueworker.start() - downloadworker = DownloadWorker(gui=True) - downloadworker.progress.connect(self.update_item_in_download_list) # Connect the signal to the update method - downloadworker.start() # Start the download worker thread + for i in range(config.get('maximum_download_workers')): + downloadworker = DownloadWorker(gui=True) + downloadworker.progress.connect(self.update_item_in_download_list) + downloadworker.start() self.mirrorplayback = MirrorSpotifyPlayback() if config.get('mirror_spotify_playback'): @@ -414,6 +415,7 @@ def add_item_to_download_list(self, item, item_metadata): with download_queue_lock: download_queue[item['local_id']] = { 'local_id': item['local_id'], + 'available': True, "item_service": item["item_service"], "item_type": item["item_type"], 'item_id': item['item_id'], @@ -449,7 +451,7 @@ def update_item_in_download_list(self, item, status, progress): item['gui']['btn']['copy'].show() item['gui']["btn"]['retry'].hide() return - if progress == 0: + elif progress == 0: item['gui']["btn"]['cancel'].hide() if config.get("download_copy_btn"): item['gui']['btn']['copy'].show() @@ -460,12 +462,6 @@ def update_item_in_download_list(self, item, status, progress): item['gui']['btn']['retry'].hide() if config.get("download_copy_btn"): item['gui']['btn']['copy'].show() - if config.get("download_play_btn"): - item['gui']['btn']['play'].show() - if config.get("download_save_btn"): - item['gui']['btn']['save'].show() - if config.get("download_queue_btn"): - item['gui']['btn']['queue'].show() if config.get("download_open_btn"): item['gui']['btn']['open'].show() if config.get("download_locate_btn"): diff --git a/src/onthespot/gui/qtui/main.ui b/src/onthespot/gui/qtui/main.ui index bcc9ad3..d651c81 100644 --- a/src/onthespot/gui/qtui/main.ui +++ b/src/onthespot/gui/qtui/main.ui @@ -656,9 +656,9 @@ 0 - -732 - 627 - 3152 + -1483 + 660 + 3154 @@ -2294,6 +2294,54 @@ true + + + + + + + false + + + + + + Maximum Download Workers + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 80 + 0 + + + + 1 + + + 999999 + + + + + + @@ -2329,19 +2377,6 @@ - - - - Qt::Horizontal - - - - 40 - 20 - - - - diff --git a/src/onthespot/gui/settings.py b/src/onthespot/gui/settings.py index 2387a2f..881085d 100644 --- a/src/onthespot/gui/settings.py +++ b/src/onthespot/gui/settings.py @@ -66,7 +66,7 @@ def load_config(self): self.inp_album_cover_format.setText(config.get("album_cover_format")) self.inp_search_thumb_height.setValue(config.get("search_thumb_height")) self.inp_metadata_seperator.setText(config.get("metadata_seperator")) - + self.inp_maximum_download_workers.setValue(config.get("maximum_download_workers")) # Checkboxes self.inp_overwrite_existing_metadata.setChecked(config.get("overwrite_existing_metadata")) @@ -162,7 +162,7 @@ def save_config(self): config.set_('media_format', self.inp_media_format.text()) config.set_('podcast_media_format', self.inp_podcast_media_format.text()) config.set_('illegal_character_replacement', self.inp_illegal_character_replacement.text()) - + config.set_('maximum_download_workers', self.inp_maximum_download_workers.value()) # Checkboxes: config.set_('key', bool) config.set_('overwrite_existing_metadata', self.inp_overwrite_existing_metadata.isChecked()) diff --git a/src/onthespot/otsconfig.py b/src/onthespot/otsconfig.py index 29512d3..d65ed83 100755 --- a/src/onthespot/otsconfig.py +++ b/src/onthespot/otsconfig.py @@ -48,6 +48,7 @@ def __init__(self, cfg_path=None): "rotate_acc_sn": False, # Rotate active account for parsing and downloading tracks "download_root": os.path.join(os.path.expanduser("~"), "Music", "OnTheSpot"), # Root dir for downloads "download_delay": 3, # Seconds to wait before next download attempt + "maximum_download_workers": 1, # Maximum number of download workers "track_path_formatter": "Tracks" + os.path.sep + "{album_artist}" + os.path.sep + "[{year}] {album}" + os.path.sep + "{track_number}. {name}", # Track path format string "podcast_path_formatter": "Episodes" + os.path.sep + "{album}" + os.path.sep + "{name}", # Episode path format string "playlist_path_formatter": "Playlists" + os.path.sep + "{playlist_name} by {playlist_owner}" + os.path.sep + "{name} - {artist}", # Playlist path format string diff --git a/src/onthespot/static/style.css b/src/onthespot/static/style.css index 3c3ccff..9e3c14c 100644 --- a/src/onthespot/static/style.css +++ b/src/onthespot/static/style.css @@ -130,4 +130,4 @@ button { cursor: pointer; font-size: 12px; transition: background-color 0.3s; -} \ No newline at end of file +} diff --git a/src/onthespot/templates/about.html b/src/onthespot/templates/about.html index 5c4333f..87cae15 100644 --- a/src/onthespot/templates/about.html +++ b/src/onthespot/templates/about.html @@ -23,4 +23,4 @@

About

its a music downloader

- \ No newline at end of file + diff --git a/src/onthespot/templates/search.html b/src/onthespot/templates/search.html index 69606bf..7f048ea 100644 --- a/src/onthespot/templates/search.html +++ b/src/onthespot/templates/search.html @@ -115,4 +115,4 @@ - \ No newline at end of file + diff --git a/src/onthespot/templates/settings.html b/src/onthespot/templates/settings.html index 638ea75..5739bfe 100644 --- a/src/onthespot/templates/settings.html +++ b/src/onthespot/templates/settings.html @@ -186,6 +186,9 @@

Downloads



+ +

+

@@ -353,6 +356,8 @@

Metadata

const rotateAccSn = document.getElementById('rotate_acc_sn').checked; const forceRaw = document.getElementById('force_raw').checked; const downloadDelay = document.getElementById('download_delay').value; + const translateFilePath = document.getElementById('translate_file_path').value; + const maximumDownloadWorkers = document.getElementById('maximum_download_workers').value; const metadataSeparator = document.getElementById('metadata_seperator').value; const overwriteExistingMetadata = document.getElementById('overwrite_existing_metadata').checked; @@ -435,6 +440,8 @@

Metadata

rotate_acc_sn: rotateAccSn, force_raw: forceRaw, download_delay: downloadDelay, + translate_file_path: translateFilePath, + maximum_download_workers: maximumDownloadWorkers, metadata_separator: metadataSeparator, overwrite_existing_metadata: overwriteExistingMetadata, embed_cover: embedCover, @@ -496,4 +503,4 @@

Metadata

} - \ No newline at end of file + diff --git a/src/onthespot/utils.py b/src/onthespot/utils.py index 7642f04..69e678e 100644 --- a/src/onthespot/utils.py +++ b/src/onthespot/utils.py @@ -148,7 +148,7 @@ def format_track_path(item, item_metadata): return item_path -def convert_audio_format(filename, metadata, default_format): +def convert_audio_format(filename, default_format): if os.path.isfile(os.path.abspath(filename)): target_path = os.path.abspath(filename) file_name = os.path.basename(target_path) diff --git a/src/onthespot/web.py b/src/onthespot/web.py index c9836c7..8f168b0 100644 --- a/src/onthespot/web.py +++ b/src/onthespot/web.py @@ -34,6 +34,7 @@ def run(self): with download_queue_lock: download_queue[local_id] = { 'local_id': local_id, + 'available': True, "item_service": item["item_service"], "item_type": item["item_type"], 'item_id': item['item_id'], @@ -179,8 +180,9 @@ def main(): queue_worker = QueueWorker() queue_worker.start() - download_worker = DownloadWorker() - download_worker.start() + for i in range(config.get('maximum_download_workers')): + downloadworker = DownloadWorker(gui=True) + downloadworker.start() fill_account_pool.wait()