Broque Thomas
|
f0955420c3
|
PR4f: lift _download_track_worker to core/downloads/task_worker.py
Sixth sub-PR in the download orchestrator series. Strict 1:1 lift —
zero behavior change. ~333 lines moved out of web_server.py.
What moved:
- _download_track_worker → download_track_worker
Dependencies bundled in `TaskWorkerDeps` (10 callbacks):
- soulseek_client (with .mode + .hybrid_order + subclient attrs for hybrid
fallback: .soulseek/.youtube/.tidal/.qobuz/.hifi/.deezer_dl)
- matching_engine (.generate_download_queries)
- run_async
- try_source_reuse, store_batch_source, try_staging_match,
get_valid_candidates, attempt_download_with_candidates,
recover_worker_slot (web_server.py helpers — large, will lift in
follow-up PRs)
- on_download_completed (deferred to PR4g batch lifecycle)
Direct imports for already-lifted: download_tasks, tasks_lock from
core.runtime_state. SpotifyTrack from core.spotify_client.
Behavior parity:
- Same control flow: missing-task short-circuit → cancellation
checkpoint with V2/legacy split → SpotifyTrack reconstruction with
artist/album normalization → source-reuse shortcut → staging-match
shortcut → searching-state init → query generation (matching
engine + legacy fallbacks: track+first-artist-word with The-prefix
handling, track-only, paren/bracket-cleaned) → case-insensitive
dedup → sequential query loop with cancellation checks before/
during/after each search → hybrid fallback across remaining sources
using first 2 queries → not_found marking with diagnostics → 2-tier
exception recovery (failed marking + emergency worker_slot recovery)
- Same logger messages text-for-text (so log filters keep working)
- Same locking pattern (tasks_lock around every download_tasks read/
write, with the 2.0s timeout fallback in the exception path)
- Same `cached_candidates` storage for retry fallback + raw-results
storage for candidate review modal (top 20 per query without valid
candidates)
- Same V2 detection via `playlist_id` field — V2 tasks don't trigger
on_download_completed for cancellation (V2 atomic cancel handles
the worker slot itself)
Tests: 19 new under tests/downloads/test_downloads_task_worker.py
covering early-return guards (missing/cancelled-V2/cancelled-legacy/
cancelled-no-batch), source reuse + staging shortcuts, search loop
happy path, no-results not_found, raw-results-stored-when-no-valid-
candidates, attempt-download-failure-falls-through, cancellation mid-
flight returns without completion, hybrid fallback (with + without
hybrid mode), critical exception with + without recovery callback,
query generation edge cases (The-prefix, paren cleanup, dedup).
Full suite: 1001 passing (was 982). Ruff clean.
|
2026-04-28 07:50:01 -07:00 |
|