chore(downloads): add config defaults + clarify validation fallback scope
Wraps up the code-review refactor pass. - config/settings.py: ``download_source`` defaults gain ``album_bundle_poll_interval_seconds`` (default 2s) and ``album_bundle_timeout_seconds`` (default 6h, was a hard-coded ``6 * 60 * 60`` magic constant in torrent.py). The plugin reads these via ``album_bundle.get_poll_interval`` / ``get_poll_timeout`` with safe fallback to the defaults when the config value is missing / non-numeric. ``mode`` doc-comment extended to list ``torrent`` and ``usenet``. - core/downloads/validation.py: comment block above the album-name fallback rewritten to document when the fallback actually runs now — single-track hybrid downloads only, because the album- bundle gate handles single-source mode and the hybrid chain filter strips torrent / usenet from album batches. Code path unchanged; just clarifies the contract for the next reader. - webui/static/helper.js: WHATS_NEW entry summarising the refactor pass (helper extraction, dispatch lift, staging deps injection, atomic copy, configurable timeout, test additions). The /loop of: extract → inject → test was sweep enough to drop the gate code's coupling to 2-3 modules and put 49 unit tests behind the new boundaries. Code-review feedback addressed: 1. album_bundle.py extracted ✓ 2. Dispatch lifted out of master.py ✓ 3. staging.py decoupled from runtime_state ✓ 4. Validation fallback scope documented ✓ 5. Poll timeout config-driven ✓ 6. ``amazon`` provenance owned in a prior commit ✓ 7. End-to-end-shaped tests added (test_album_bundle_dispatch.py) 8. Auto-Import race closed via atomic copy ✓
This commit is contained in:
parent
440c3624f3
commit
1c120a7fb7
3 changed files with 30 additions and 9 deletions
|
|
@ -480,11 +480,19 @@ class ConfigManager:
|
|||
"search_min_delay_seconds": 0,
|
||||
},
|
||||
"download_source": {
|
||||
"mode": "soulseek", # Options: "soulseek", "youtube", "tidal", "qobuz", "hifi", "hybrid"
|
||||
"mode": "soulseek", # Options: "soulseek", "youtube", "tidal", "qobuz", "hifi", "hybrid", "torrent", "usenet"
|
||||
"hybrid_primary": "soulseek", # Legacy: primary source for hybrid mode
|
||||
"hybrid_secondary": "youtube", # Legacy: fallback source for hybrid mode
|
||||
"hybrid_order": [], # Ordered list of sources for hybrid mode (overrides primary/secondary)
|
||||
"stream_source": "youtube", # Options: "youtube" (instant, default), "active" (use download source; falls back to youtube if soulseek)
|
||||
# Album-bundle (torrent / usenet single-source) poll tuning.
|
||||
# Downloader is polled every N seconds until the release
|
||||
# lands; whole job aborts at the timeout. Defaults match
|
||||
# the previous hard-coded constants. Users on slow private
|
||||
# trackers / large box sets can extend the timeout without
|
||||
# editing source.
|
||||
"album_bundle_poll_interval_seconds": 2.0,
|
||||
"album_bundle_timeout_seconds": 6 * 60 * 60, # 6 hours
|
||||
},
|
||||
"tidal_download": {
|
||||
"quality": "lossless", # Options: "low", "high", "lossless", "hires"
|
||||
|
|
|
|||
|
|
@ -146,14 +146,26 @@ def get_valid_candidates(results, spotify_track, query):
|
|||
candidate_duration_ms=r.duration or 0,
|
||||
)
|
||||
|
||||
# Torrent / usenet results are typically release-level (album torrents).
|
||||
# Looking for "Luther (with SZA)" against a candidate titled
|
||||
# "GNX (2024) [FLAC]" scores ~0 on track-title alone, even though
|
||||
# the album torrent does in fact contain the wanted track. Score
|
||||
# the candidate title against the wanted track's ALBUM name too
|
||||
# and take the max, so album-level releases match every track on
|
||||
# them. The album_track_count bonus only kicks in when we have
|
||||
# a non-empty album string to compare against.
|
||||
# Album-name fallback for torrent / usenet per-track results.
|
||||
#
|
||||
# When this fallback runs: hybrid mode + non-album batch (single
|
||||
# track wishlist / playlist of singles). Album-context batches
|
||||
# never reach here — the album-bundle gate in
|
||||
# core/downloads/album_bundle_dispatch.py engages the bulk-
|
||||
# download flow in single-source mode, and the hybrid chain
|
||||
# filter in core/downloads/task_worker.py strips torrent /
|
||||
# usenet from album batches in hybrid mode. What's left is the
|
||||
# single-track-in-hybrid case where a user is searching for one
|
||||
# track and the only torrent / usenet result is the album that
|
||||
# contains it.
|
||||
#
|
||||
# Without this fallback, "Luther (with SZA)" against a
|
||||
# candidate titled "GNX (2024) [FLAC]" scores ~0 on track-title
|
||||
# alone — even though the album torrent does in fact contain
|
||||
# the wanted track. Scoring the candidate title against the
|
||||
# wanted track's ALBUM name and taking the max gives album-
|
||||
# level releases a fair shot. The Auto-Import sweep then picks
|
||||
# the right file out of the downloaded album folder.
|
||||
if r.username in ('torrent', 'usenet') and spotify_track and spotify_track.album:
|
||||
album_conf, _ = matching_engine.score_track_match(
|
||||
source_title=spotify_track.album,
|
||||
|
|
|
|||
|
|
@ -3415,6 +3415,7 @@ function closeHelperSearch() {
|
|||
const WHATS_NEW = {
|
||||
'2.6.0': [
|
||||
{ unreleased: true },
|
||||
{ title: 'Code review refactor pass on the torrent / usenet flow', desc: 'cleanup commits before review. Lifted the shared album-pick + staging-collision helpers out of torrent.py into a new core/download_plugins/album_bundle.py module so usenet.py no longer reaches into a sibling plugin\'s private surface. Lifted the ~90-line inline album-bundle gate out of run_full_missing_tracks_process into core/downloads/album_bundle_dispatch.py with a clean pure-predicate / inject-deps design so the gate is unit-testable in isolation. Replaced the staging matcher\'s direct download_batches import with an injected get_batch_field accessor on StagingDeps. Made the 6h poll timeout configurable via download_source.album_bundle_timeout_seconds. Added atomic .tmp + rename copy so the Auto-Import worker can never observe a partial audio file during the album-bundle copy loop. 49 new tests across album_bundle, album_bundle_dispatch, and staging-provenance modules pin the contracts.' },
|
||||
{ title: 'Hybrid mode skips torrent / usenet on album batches', desc: 'follow-up to the album-bundle flow. When download mode is set to Hybrid AND the batch is an album, the per-track search loop now silently strips torrent and usenet from the source chain — they\'re release-level sources that can\'t match per-track meaningfully, and the album-bundle handling only fires in single-source mode. Without the skip, hybrid + torrent-first would fire N redundant Prowlarr searches per album and rely on Auto-Import sweeping Staging to recover. Cleaner now: hybrid falls straight through to per-track-compatible sources (Soulseek / streaming) for albums, and torrent / usenet still get a shot for single-track / wishlist / basic-search use cases where per-track makes sense.' },
|
||||
{ title: 'Album-bundle flow for torrent / usenet downloads', desc: 'fixes the core architectural problem with indexer-based sources. Prowlarr returns release-level torrents — searching per-track for "Luther (with SZA)" against the GNX album torrent scores near-zero and the orchestrator rejects every candidate. New gated flow: when downloading an album AND torrent or usenet is the single active source (not hybrid), SoulSync now does ONE Prowlarr search for the whole release, picks the best torrent (prefers FLAC, high seeders, reasonable size — drops single-track torrents that snuck in), hands it to your torrent / usenet client, walks the resulting audio files (extracting .zip/.rar/.tar if needed), and drops them all into the staging folder. The existing per-track staging matcher then imports each one to the library by fuzzy title match — same path as the Auto-Import flow. Gate is strictly opt-in: per-track flow is completely untouched for hybrid mode, non-album downloads, and every other source. 5 new tests cover the album picker (seeded-FLAC preference, size floor for single-track torrents, fallback when all candidates are small) and the staging path collision handler.' },
|
||||
{ title: 'Filesystem-access heads-up for torrent / usenet sources', desc: 'new advisory card on the Indexers & Downloaders tab explaining the cleanest setup: point ALL your downloaders (Soulseek, qBittorrent, SABnzbd / NZBGet) at the same download folder. One folder, one mount, everything just works. Bare-metal needs no change; Docker users can reuse the existing ./downloads mount and just configure each client to write there. docker-compose.yml updated to call this out as the easiest path, with optional commented placeholders for users who prefer separate folders per protocol.' },
|
||||
|
|
|
|||
Loading…
Reference in a new issue