fix: Add locks, logging refactor, and bugfixes

Improve thread-safety, logging, and various bug fixes across the app.

Key changes:
- Add and use state.downloads_lock around accesses to state.active_downloads in multiple modules (UI, libtorrent, misc, direct downloads) to prevent race conditions.
- Prevent concurrent dl_status_loop runs using a non-blocking _loop_lock and ensure proper iteration over a snapshot of downloads.
- Add metadata timeout when waiting for torrent metadata and fix free-space check logic to remove or reject downloads appropriately.
- Refactor download log persistence: add _load_downloads and _save_downloads helpers and centralize JSON read/write logic in utils/logging/logs.py.
- Optimize DirectDownloadStatus speed window by switching to deque and using popleft to trim older samples.
- Trim console log widget to 500 lines to avoid unbounded growth.
- Add small state fields for custom image positioning (x/y and enabled flag).
- Fix Steamrip scraper caching behavior and make Uztracker return an empty list on fetch failures.
- Add defensive checks in run_download to handle missing links.

These changes focus on stability and correctness for concurrent download handling and durable logging.
This commit is contained in:
Vxrtrauter
2026-04-08 01:41:32 +02:00
parent dde4288a2d
commit cc51f57e18
12 changed files with 149 additions and 155 deletions
+17 -8
View File
@@ -9,19 +9,23 @@ import os
def cleanup_session():
if state.dl_session is not None:
for magnetdl in state.active_downloads.values():
if hasattr(magnetdl, 'pause'): # Check it's a handle
magnetdl.pause()
with state.downloads_lock:
for magnetdl in state.active_downloads.values():
if hasattr(magnetdl, 'pause'): # check it's a handle
magnetdl.pause()
del state.dl_session
state.dl_session = None
state.active_downloads.clear()
with state.downloads_lock:
state.active_downloads.clear()
def send_notification(shutdown_event):
notified = set()
while not shutdown_event.is_set():
try:
for magnet_uri, magnetdl in list(state.active_downloads.items()):
with state.downloads_lock:
items = list(state.active_downloads.items())
for magnet_uri, magnetdl in items:
if isinstance(magnetdl, dict):
continue
@@ -42,7 +46,9 @@ def update_log(shutdown_event):
updated = set()
while not shutdown_event.is_set():
try:
for magnet_uri, magnetdl in list(state.active_downloads.items()):
with state.downloads_lock:
items = list(state.active_downloads.items())
for magnet_uri, magnetdl in items:
if isinstance(magnetdl, dict):
continue
@@ -63,7 +69,9 @@ def update_log(shutdown_event):
def check_deleted_files(shutdown_event):
while not shutdown_event.is_set():
try:
for magnet_uri, magnetdl in list(state.active_downloads.items()):
with state.downloads_lock:
items = list(state.active_downloads.items())
for magnet_uri, magnetdl in items:
if isinstance(magnetdl, dict):
continue
@@ -75,7 +83,8 @@ def check_deleted_files(shutdown_event):
if not os.path.exists(file_path):
consoleLog(f"Registered File Deletion: {status.name}")
state.dl_session.remove_torrent(magnetdl)
del state.active_downloads[magnet_uri]
with state.downloads_lock:
del state.active_downloads[magnet_uri]
except Exception as e:
consoleLog(f"Exception while checking for file deletions: {e}")
time.sleep(5)