Skip to content

Commit

Permalink
Expose queue worker toggle, reuse icons to avoid high mem usage
Browse files Browse the repository at this point in the history
  • Loading branch information
justin025 committed Dec 4, 2024
1 parent 918ec0f commit 23b63c7
Show file tree
Hide file tree
Showing 10 changed files with 222 additions and 95 deletions.
1 change: 1 addition & 0 deletions docs/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ Customize **OnTheSpot** to fit your preferences by adjusting the settings in the
| **Raw Media Download** | Downloads an unmodified file from whatever service is selected. With this enabled file conversion and the embedding of any metadata is skipped. |
| **Download Delay** | Time (in seconds) to wait before initiating the next download. Helps prevent Spotify's rate limits. |
| **Download Chunk Size** | The chunk size in which to download files. |
| **Maximum Queue Workers** | Set the maximum number of queue workers. Setting a higher number will queue songs faster, only change this setting if you know what you're doing. |
| **Maximum Download Workers** | Set the maximum number of download workers. Only change this setting if you know what you're doing. |
| **Translate File Path** | Translate file paths into the application language. |
| **Metadata Separator** | Set the separator for metadata fields with multiple values (default: `; `). |
Expand Down
13 changes: 6 additions & 7 deletions src/onthespot/api/spotify.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,11 +131,11 @@ def spotify_new_session():
with open(session_json_path, 'r') as file:
zeroconf_login = json.load(file)
except FileNotFoundError:
print(f"Error: The file {session_json_path} was not found.")
logger.error(f"Error: The file {session_json_path} was not found.")
except json.JSONDecodeError:
print("Error: Failed to decode JSON from the file.")
logger.error("Error: Failed to decode JSON from the file.")
except Exception as e:
print(f"An error occurred: {e}")
logger.error(f"An error occurred: {e}")
cfg_copy = config.get('accounts').copy()
new_user = {
"uuid": uuid_uniq,
Expand All @@ -158,20 +158,19 @@ def spotify_new_session():
def spotify_login_user(account):
try:
# I'd prefer to use 'Session.Builder().stored(credentials).create but
# it seems to be broken, loading from credentials file instead
# I can't get it to work, loading from credentials file instead.
uuid = account['uuid']
username = account['login']['username']

session_dir = os.path.join(cache_dir(), "onthespot", "sessions")
os.makedirs(session_dir, exist_ok=True)
session_json_path = os.path.join(session_dir, f"ots_login_{uuid}.json")
print(session_json_path)
try:
with open(session_json_path, 'w') as file:
json.dump(account['login'], file)
print(f"Login information for '{username[:4]}*******' written to {session_json_path}")
logger.info(f"Login information for '{username[:4]}*******' written to {session_json_path}")
except IOError as e:
print(f"Error writing to file {session_json_path}: {e}")
logger.error(f"Error writing to file {session_json_path}: {e}")


config = Session.Configuration.Builder().set_stored_credential_file(session_json_path).build()
Expand Down
6 changes: 4 additions & 2 deletions src/onthespot/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ def run(self):
else:
time.sleep(0.2)


def main():
print('\033[32mLogging In...\033[0m\n', end='', flush=True)

Expand All @@ -65,8 +66,9 @@ def main():
thread.daemon = True
thread.start()

queue_worker = QueueWorker()
queue_worker.start()
for i in range(config.get('maximum_queue_workers')):
queue_worker = QueueWorker()
queue_worker.start()

for i in range(config.get('maximum_download_workers')):
downloadworker = DownloadWorker(gui=True)
Expand Down
146 changes: 104 additions & 42 deletions src/onthespot/gui/mainui.py

Large diffs are not rendered by default.

79 changes: 76 additions & 3 deletions src/onthespot/gui/qtui/main.ui
Original file line number Diff line number Diff line change
Expand Up @@ -656,9 +656,9 @@
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>660</width>
<height>3154</height>
<y>-1557</y>
<width>627</width>
<height>3234</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_16">
Expand Down Expand Up @@ -2297,6 +2297,54 @@
<bool>true</bool>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_231">
<item>
<widget class="QGroupBox" name="groupBox_130">
<property name="title">
<string/>
</property>
<property name="flat">
<bool>false</bool>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_238">
<item>
<widget class="QLabel" name="lb_chunk_size_8">
<property name="text">
<string>Maximum Queue Workers</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_48">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QSpinBox" name="inp_maximum_queue_workers">
<property name="minimumSize">
<size>
<width>80</width>
<height>0</height>
</size>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>999999</number>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_129">
<property name="title">
Expand Down Expand Up @@ -2345,6 +2393,18 @@
</layout>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="gb1_12">
<property name="title">
<string/>
</property>
<property name="flat">
<bool>true</bool>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_232">
<item>
<widget class="QGroupBox" name="inp_translate_file_path_2">
<property name="title">
Expand Down Expand Up @@ -2380,6 +2440,19 @@
</layout>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
Expand Down
55 changes: 19 additions & 36 deletions src/onthespot/gui/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,43 +18,26 @@ def load_config(self):
# Hide Popups
self.group_search_items.hide()
self.group_download_items.hide()
# Icons
en_US_icon = QIcon(os.path.join(config.app_root, 'resources', 'icons', 'en_US.png'))
self.inp_language.insertItem(0, en_US_icon, "English")
de_DE_icon = QIcon(os.path.join(config.app_root, 'resources', 'icons', 'de_DE.png'))
self.inp_language.insertItem(1, de_DE_icon, "Deutsch")
pt_PT_icon = QIcon(os.path.join(config.app_root, 'resources', 'icons', 'pt_PT.png'))
self.inp_language.insertItem(2, pt_PT_icon, "Português")

pirate_icon = QIcon(os.path.join(config.app_root, 'resources', 'icons', 'pirate_flag.png'))
self.inp_language.insertItem(999, pirate_icon, "Contribute")
# Icons
self.inp_language.insertItem(0, self.get_icon('en_US'), "English")
self.inp_language.insertItem(1, self.get_icon('de_DE'), "Deutsch")
self.inp_language.insertItem(2, self.get_icon('pt_PT'), "Português")
self.inp_language.insertItem(999, self.get_icon('pirate_flag'), "Contribute")
self.inp_language.currentIndexChanged.connect(self.contribute)

deezer_icon = QIcon(os.path.join(config.app_root, 'resources', 'icons', 'deezer.png'))
self.inp_login_service.insertItem(0, deezer_icon, "")

soundcloud_icon = QIcon(os.path.join(config.app_root, 'resources', 'icons', 'soundcloud.png'))
self.inp_login_service.insertItem(1, soundcloud_icon, "")

spotify_icon = QIcon(os.path.join(config.app_root, 'resources', 'icons', 'spotify.png'))
self.inp_login_service.insertItem(2, spotify_icon, "")

youtube_icon = QIcon(os.path.join(config.app_root, 'resources', 'icons', 'youtube.png'))
self.inp_login_service.insertItem(3, youtube_icon, "")

self.inp_login_service.insertItem(0, self.get_icon('deezer'), "")
self.inp_login_service.insertItem(1, self.get_icon('soundcloud'), "")
self.inp_login_service.insertItem(2, self.get_icon('spotify'), "")
self.inp_login_service.insertItem(3, self.get_icon('youtube'), "")
self.inp_login_service.setCurrentIndex(2)

save_icon = QIcon(os.path.join(config.app_root, 'resources', 'icons', 'save.png'))
self.btn_save_config.setIcon(save_icon)
folder_icon = QIcon(os.path.join(config.app_root, 'resources', 'icons', 'folder.png'))
self.btn_download_root_browse.setIcon(folder_icon)
self.btn_download_tmp_browse.setIcon(folder_icon)
search_icon = QIcon(os.path.join(config.app_root, 'resources', 'icons', 'search.png'))
self.btn_search.setIcon(search_icon)
collapse_down_icon = QIcon(os.path.join(config.app_root, 'resources', 'icons', 'collapse_down.png'))
collapse_up_icon = QIcon(os.path.join(config.app_root, 'resources', 'icons', 'collapse_up.png'))
self.btn_search_filter_toggle.setIcon(collapse_down_icon)
self.btn_download_filter_toggle.setIcon(collapse_up_icon)
self.btn_save_config.setIcon(self.get_icon('save'))
self.btn_download_root_browse.setIcon(self.get_icon('folder'))
self.btn_download_tmp_browse.setIcon(self.get_icon('folder'))
self.btn_search.setIcon(self.get_icon('search'))
self.btn_search_filter_toggle.setIcon(self.get_icon('collapse_down'))
self.btn_download_filter_toggle.setIcon(self.get_icon('collapse_up'))

# Text
self.inp_language.setCurrentIndex(config.get("language_index"))
Expand All @@ -77,6 +60,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_queue_workers.setValue(config.get("maximum_queue_workers"))
self.inp_maximum_download_workers.setValue(config.get("maximum_download_workers"))

# Checkboxes
Expand Down Expand Up @@ -156,6 +140,7 @@ def load_config(self):
"inp_file_hertz",
"inp_download_delay",
"inp_chunk_size",
"inp_maximum_queue_workers",
"inp_maximum_download_workers"
]

Expand Down Expand Up @@ -210,13 +195,11 @@ def save_config(self):
config.set_('search_thumb_height', self.inp_search_thumb_height.value())
config.set_('disable_bulk_dl_notices', self.inp_disable_bulk_popup.isChecked())
config.set_('metadata_seperator', self.inp_metadata_seperator.text())
if 0 < self.inp_max_search_results.value() <= 50:
config.set_('max_search_results', self.inp_max_search_results.value())
else:
config.set_('max_search_results', 5)
config.set_('max_search_results', self.inp_max_search_results.value())
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_queue_workers', self.inp_maximum_queue_workers.value())
config.set_('maximum_download_workers', self.inp_maximum_download_workers.value())

# Checkboxes: config.set_('key', bool)
Expand Down
1 change: 1 addition & 0 deletions src/onthespot/otsconfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ def __init__(self, cfg_path=None):
"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
"maximum_queue_workers": 1, # Maximum number of queue 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
Expand Down
1 change: 1 addition & 0 deletions src/onthespot/parse_item.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
YOUTUBE_URL_REGEX = re.compile(r"https://(www\.|music\.)?youtube\.com/watch\?v=(?P<video_id>[a-zA-Z0-9_-]+)(&list=(?P<list_id>[a-zA-Z0-9_-]+))?")
#QOBUZ_INTERPRETER_URL_REGEX = re.compile(r"https?://www\.qobuz\.com/\w\w-\w\w/interpreter/[-\w]+/([-\w]+)")


def parse_url(url):
if re.match(DEEZER_URL_REGEX, url):
match = re.search(DEEZER_URL_REGEX, url)
Expand Down
5 changes: 5 additions & 0 deletions src/onthespot/templates/settings.html
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,9 @@ <h2>Downloads</h2>
<label for="chunk_size">Chunk Size:</label>
<input type="number" id="chunk_size" value="{{ config.chunk_size }}" placeholder="Enter chunk size"><br><br>

<label for="maximum_queue_workers">Maximum Queue Workers:</label>
<input type="text" id="maximum_queue_workers" value="{{ config.maximum_queue_workers }}" placeholder="Enter maximum download workers"><br><br>

<label for="maximum_download_workers">Maximum Download Workers:</label>
<input type="text" id="maximum_download_workers" value="{{ config.maximum_download_workers }}" placeholder="Enter maximum download workers"><br><br>

Expand Down Expand Up @@ -357,6 +360,7 @@ <h2>Metadata</h2>
const forceRaw = document.getElementById('force_raw').checked;
const downloadDelay = document.getElementById('download_delay').value;
const translateFilePath = document.getElementById('translate_file_path').value;
const maximumQueueWorkers = document.getElementById('maximum_queue_workers').value;
const maximumDownloadWorkers = document.getElementById('maximum_download_workers').value;

const metadataSeparator = document.getElementById('metadata_seperator').value;
Expand Down Expand Up @@ -441,6 +445,7 @@ <h2>Metadata</h2>
force_raw: forceRaw,
download_delay: downloadDelay,
translate_file_path: translateFilePath,
maximum_queue_workers: maximumQueueWorkers,
maximum_download_workers: maximumDownloadWorkers,
metadata_separator: metadataSeparator,
overwrite_existing_metadata: overwriteExistingMetadata,
Expand Down
10 changes: 5 additions & 5 deletions src/onthespot/web.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,6 @@ def download_queue_page():
config_path = os.path.join(config_dir(), 'onthespot', 'otsconfig.json')
with open(config_path, 'r') as config_file:
config_data = json.load(config_file)
print(config_data)
return render_template('download_queue.html', config=config_data)

@app.route('/')
Expand Down Expand Up @@ -167,17 +166,18 @@ def update_settings():
def main():
fill_account_pool = FillAccountPool()

fill_account_pool.finished.connect(lambda: print("Finished filling account pool."))
fill_account_pool.progress.connect(lambda message, status: print(f"{message} {'Success' if status else 'Failed'}"))
fill_account_pool.finished.connect(lambda: logger.info("Finished filling account pool."))
fill_account_pool.progress.connect(lambda message, status: logger.info(f"{message} {'Success' if status else 'Failed'}"))

fill_account_pool.start()

thread = threading.Thread(target=parsingworker)
thread.daemon = True
thread.start()

queue_worker = QueueWorker()
queue_worker.start()
for i in range(config.get('maximum_queue_workers')):
queue_worker = QueueWorker()
queue_worker.start()

for i in range(config.get('maximum_download_workers')):
downloadworker = DownloadWorker(gui=True)
Expand Down

0 comments on commit 23b63c7

Please sign in to comment.