soulsync/tests/downloads
Broque Thomas 2aff3dc210 Filter SoundCloud previews at every entry point + fix hybrid fallback regression
The earlier validation-only filter only ran in the auto-search
scoring path. SoundCloud preview snippets still leaked through:

- The candidate-review modal cached raw search results (pre-validation),
  so previews were visible and clickable for manual retry — and the
  manual-pick download path bypassed validation entirely, downloading
  the preview anyway.
- The not-found raw-results cache stored unfiltered top-20s.

Lift the preview filter into a reusable filter_soundcloud_previews()
helper and apply it at every entry point: validation scoring (still),
modal-cache fallback when validation drops everything, and the
not-found raw-results path. Previews now never reach the cache, the
matcher, or the manual-pick UI. Drops candidates < 35s or below half
the expected duration, gated on expected > 60s so genuine short
tracks still pass. 7 new unit tests pin the helper.

Also fixed a silent regression in core/downloads/task_worker.py's
hybrid-fallback path. Cin-5 dropped the per-source attrs from the
orchestrator (orch.soulseek, orch.youtube, etc.), but the fallback
loop still resolved sources via getattr(orch, '<src>', None) — every
lookup silently returned None, so remaining_sources came back empty
and the fallback never ran. Now uses orch.client(name) like the rest
of the codebase. Updated the test fake to expose client() too — the
old test was passing because the loop was effectively dead.
2026-05-05 10:26:25 -07:00
..
__init__.py PR4a: lift sync history recording to core/downloads/history.py 2026-04-27 20:37:16 -07:00
test_background_download_worker.py Cin review: alias resolution, atomic terminal write, generic accessors 2026-05-04 22:58:46 -07:00
test_deezer_pinning.py C6: Migrate Deezer to engine.worker 2026-05-04 14:02:03 -07:00
test_download_engine.py Cin review: alias resolution, atomic terminal write, generic accessors 2026-05-04 22:58:46 -07:00
test_download_orchestrator.py Cin-5: Drop per-source attrs from orchestrator 2026-05-04 23:14:05 -07:00
test_downloads_cancel.py PR4b: lift cancel + clear download routes to core/downloads/cancel.py 2026-04-27 21:41:35 -07:00
test_downloads_candidates.py Cin-6: Rename soulseek_client global → download_orchestrator 2026-05-04 23:23:32 -07:00
test_downloads_cleanup.py PR4c: lift _automatic_wishlist_cleanup_after_db_update to core/downloads/cleanup.py 2026-04-27 22:23:41 -07:00
test_downloads_history.py PR4a: lift sync history recording to core/downloads/history.py 2026-04-27 20:37:16 -07:00
test_downloads_lifecycle.py Rename wishlist lifecycle helper 2026-04-30 08:06:02 +03:00
test_downloads_master.py Cin-6: Rename soulseek_client global → download_orchestrator 2026-05-04 23:23:32 -07:00
test_downloads_post_processing.py Cin-6: Rename soulseek_client global → download_orchestrator 2026-05-04 23:23:32 -07:00
test_downloads_staging.py Lift _try_staging_match to core/downloads/staging.py 2026-04-28 23:26:15 -07:00
test_downloads_status.py PR4e: lift status helpers + 3 routes to core/downloads/status.py 2026-04-27 23:26:26 -07:00
test_downloads_task_worker.py Filter SoundCloud previews at every entry point + fix hybrid fallback regression 2026-05-05 10:26:25 -07:00
test_downloads_validation.py Filter SoundCloud previews at every entry point + fix hybrid fallback regression 2026-05-05 10:26:25 -07:00
test_hifi_pinning.py C5: Migrate HiFi to engine.worker 2026-05-04 13:57:01 -07:00
test_lidarr_pinning.py A8: Pin LidarrDownloadClient download lifecycle behavior 2026-05-04 12:10:49 -07:00
test_qobuz_pinning.py C4: Migrate Qobuz to engine.worker 2026-05-04 13:52:55 -07:00
test_rate_limit_policy.py E1: Add RateLimitPolicy declaration mechanism 2026-05-04 14:38:20 -07:00
test_soulseek_pinning.py A1: Pin SoulseekClient download lifecycle behavior 2026-05-04 11:45:44 -07:00
test_soundcloud_pinning.py C7: Migrate SoundCloud to engine.worker 2026-05-04 14:24:50 -07:00
test_tidal_pinning.py C3: Migrate Tidal to engine.worker 2026-05-04 13:49:36 -07:00
test_youtube_pinning.py E2: Migrate YouTube to declared rate-limit policy 2026-05-04 14:45:52 -07:00