fix(worker): judge download completeness by the source's edition, not MB's
The completeness + duration guards used MusicBrainz's target.track_count / total_duration_s, but MB picks an arbitrary releases[0] that is often a deluxe/expanded edition with more tracks (and runtime) than the standard album a source legitimately delivers. So complete standard-edition downloads were falsely rejected — The Script 'No Sound Without Silence' (11 vs MB 12) as 'incomplete download', Skillet 'Unleashed' (12 vs MB's 20-track deluxe) as 'too short'. Now completeness is judged against the chosen source's own track count (winner.track_count): a truncated download (fewer files than the source promised) still fails, and the duration expectation is scaled to the delivered edition's size. A separate 'implausibly small vs MB' guard (source has <= half MB's tracks) still rejects a lone-track 'full album' video. Genuine partials (e.g. John Mayer, a Qobuz track failing mid-download) still correctly fail. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -375,23 +375,39 @@ def run_pipeline(
|
||||
|
||||
# 5. verify completeness on the staging copy, then promote + tag
|
||||
_set_state(conn, job_id, "tagging", "tag")
|
||||
expected = target.track_count if target.track_count is not None else winner.track_count
|
||||
# Also count the NON-EMPTY audio actually on disk: a silently-skipped track leaves a
|
||||
# 0-byte placeholder that the adapter still counts, so trust the files when any are
|
||||
# staged. (`staged and ...` keeps fake adapters that stage nothing on the count path.)
|
||||
# Judge completeness against what the CHOSEN SOURCE offered, NOT MusicBrainz's canonical
|
||||
# release: MB picks an arbitrary releases[0] that is often a deluxe/expanded edition with
|
||||
# more tracks than the standard album a source legitimately delivers, so gating purely on
|
||||
# target.track_count falsely rejects complete standard-edition downloads (e.g. The Script
|
||||
# "No Sound Without Silence" 11 vs MB 12, Skillet "Unleashed" 12 vs MB's 20-track deluxe).
|
||||
expected = winner.track_count
|
||||
# (a) Truncated: fewer files than the source promised (a track failed mid-download).
|
||||
# Count the NON-EMPTY audio actually on disk too: a silently-skipped track leaves a 0-byte
|
||||
# placeholder the adapter still counts, so trust the files when any are staged. (`staged
|
||||
# and ...` keeps fake adapters that stage nothing on the count path.)
|
||||
staged = _count_staged_audio(staging)
|
||||
if result.track_count < expected or (staged and staged < expected):
|
||||
truncated = result.track_count < expected or bool(staged and staged < expected)
|
||||
# (b) Implausibly small vs MB's album — a lone-track "full album" video or a wrong match,
|
||||
# as distinct from a legitimately smaller edition (standard vs deluxe). A real edition
|
||||
# keeps more than half of MB's tracks; a 1-of-12 match does not.
|
||||
too_small = target.track_count is not None and expected * 2 <= target.track_count
|
||||
if truncated or too_small:
|
||||
_fail(conn, job_id, "incomplete download")
|
||||
return
|
||||
|
||||
# Duration check: even with the right track count, a truncated file or a short preview
|
||||
# substituted for a real track shows up as a total playtime well under MB's expected
|
||||
# total. Only applies when both are known (measured is None for the offline fakes).
|
||||
# substituted for a real track shows up as a total playtime well under the expected total.
|
||||
# Scale MB's total to the DELIVERED edition's size (source vs MB track count) so a smaller
|
||||
# standard edition isn't measured against a larger deluxe edition's runtime. Only applies
|
||||
# when the total is known (measured is None for the offline fakes).
|
||||
if target.total_duration_s:
|
||||
expected_total = target.total_duration_s
|
||||
if target.track_count:
|
||||
expected_total *= winner.track_count / target.track_count
|
||||
measured = measure_duration(staging)
|
||||
if measured is not None and measured < target.total_duration_s * _DURATION_MIN_RATIO:
|
||||
if measured is not None and measured < expected_total * _DURATION_MIN_RATIO:
|
||||
_fail(conn, job_id,
|
||||
f"download too short ({measured / 60:.0f} of ~{target.total_duration_s / 60:.0f} min)")
|
||||
f"download too short ({measured / 60:.0f} of ~{expected_total / 60:.0f} min)")
|
||||
return
|
||||
|
||||
final = album_dir(dest_root, target)
|
||||
|
||||
Reference in New Issue
Block a user