From c9dbf421dca2c8c271d91d99bdfbf47e804ed38e Mon Sep 17 00:00:00 2001 From: Broque Thomas <26755000+Nezreka@users.noreply.github.com> Date: Sun, 3 May 2026 13:22:35 -0700 Subject: [PATCH] SoundCloud progress UI fix: include SoundCloud in cached transfer lookup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit User: SoundCloud downloads finish correctly but the modal stays at "Downloading... 0%" until "Processing..." flips on. Live percentage never updates. Root cause: my live-progress fix in 8de4a18 made the SoundCloud client compute progress correctly via fragment_index/fragment_count — but the percent never reached the modal because `get_cached_transfer_data` in web_server.py iterates `[youtube, tidal, qobuz, hifi, deezer_dl, lidarr]` to build the lookup that drives `task.progress`. SoundCloud was missing from that loop, so `live_transfers_lookup` had no entry for SoundCloud downloads, so `live_info` lookup at `core/downloads/status.py:135` always missed, so `task_status['progress']` defaulted to 0 the entire time. Frontend was reading `task.progress` (rendered as "Downloading... ${task.progress}%" in `webui/static/downloads.js:3142`), which stayed at 0. The percentComplete field that the `/api/downloads/status` endpoint includes for SoundCloud was correct; this only affected the cached lookup used by the V2 task tracker. Fix: include SoundCloud in the iteration. Used `getattr` fallback to match the same pattern I used in `core/downloads/monitor.py` so older soulseek_client snapshots without the attribute don't AttributeError. Bonus: also wired the SoundCloud client's `set_shutdown_check` callback in the startup block right after HiFi's. Previously the cooperative- cancellation hook in `_progress_hook` would never fire on shutdown because `self.shutdown_check` was None. Verified: full suite 1732 passed, ruff clean. yt-dlp probe confirms fragment_index / fragment_count are populated correctly during HLS download (164 hook calls for a 19-fragment track), so the now- exposed progress will increment smoothly from 0 to 99.9 and then flip to Completed. --- web_server.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/web_server.py b/web_server.py index ccee40ad..4275e39a 100644 --- a/web_server.py +++ b/web_server.py @@ -641,6 +641,9 @@ if soulseek_client: if hasattr(soulseek_client, 'hifi'): soulseek_client.hifi.set_shutdown_check(lambda: IS_SHUTTING_DOWN) logger.info(" Configured HiFi client shutdown callback") + if hasattr(soulseek_client, 'soundcloud') and soulseek_client.soundcloud: + soulseek_client.soundcloud.set_shutdown_check(lambda: IS_SHUTTING_DOWN) + logger.info(" Configured SoundCloud client shutdown callback") # Initialize web scan manager for automatic post-download scanning try: @@ -2472,11 +2475,15 @@ def get_cached_transfer_data(): key = _make_context_key(transfer.get('username'), transfer.get('filename', '')) live_transfers_lookup[key] = transfer - # Also add non-Soulseek downloads (avoid redundant slskd call through orchestrator) + # Also add non-Soulseek downloads (avoid redundant slskd call through orchestrator). + # Every streaming source must appear here — task progress for in-flight + # downloads comes from this lookup. Missing a source = task.progress + # stays at 0 even when the underlying client knows the real percent. try: all_downloads = [] for _dl_client in [soulseek_client.youtube, soulseek_client.tidal, soulseek_client.qobuz, - soulseek_client.hifi, soulseek_client.deezer_dl, soulseek_client.lidarr]: + soulseek_client.hifi, soulseek_client.deezer_dl, soulseek_client.lidarr, + getattr(soulseek_client, 'soundcloud', None)]: if _dl_client: try: all_downloads.extend(run_async(_dl_client.get_all_downloads()))