Commit graph

2 commits

Author SHA1 Message Date
BoulderBadgeDad
ba6c39bae3 AcoustID: report errors honestly instead of masking them as 'Skipped'
An invalid API key (and rate limits / missing chromaprint / fingerprint
failures) all collapsed into the same None as a genuine no-match, so:
  - every download showed a benign 'AcoustID: Skipped', and
  - the 'Test API key' button reported a dead key as VALID
because test_api_key trusted 'no exception = valid' but fingerprint_and_lookup
swallows the error and returns None. A broken AcoustID setup looked completely
normal — which cost a real debugging session to untangle.

- New AcoustIDClient.lookup_with_status() returns a structured result that
  distinguishes ok / no_match / error / no_backend / fingerprint_error /
  unavailable. fingerprint_and_lookup() stays dict-or-None (library scanner /
  auto-import / their tests unchanged) as a thin wrapper over it.
- verify_audio_file() uses it: a real error -> new VerificationResult.ERROR
  (-> _acoustid_result='error' -> the existing red 'Error' history badge),
  a genuine no-match -> SKIP 'No match in AcoustID database'. ERROR never
  quarantines (an outage/bad key must not punish good files).
- test_api_key() now validates via the authoritative direct API call (error
  code 4 = invalid key) instead of the swallowed-exception path.

Tests: structured-status distinction, legacy-wrapper contract, verify ERROR vs
SKIP, and test_api_key invalid-vs-accepted. Existing verify tests updated to
stub lookup_with_status (a stub returning just recordings is inferred as ok).
2026-05-31 20:10:31 -07:00
Broque Thomas
01c528fd5f Reject AcoustID matches whose version disagrees with the expected track
Discord report (corruption [BWC]): downloads coming through as the
instrumental cut when a vocal track was requested. The verification
step's `_normalize` function strips parentheticals and version-suffix
tags ("(Instrumental)", "- Live", etc) so legitimate name variations
don't false-fail the title-similarity check. That also means "In My
Feelings" and "In My Feelings (Instrumental)" both normalize to "in
my feelings", title similarity is 1.0, and the wrong cut passes
verification.

Detect the version label on each side BEFORE normalization runs. If
the expected and matched recordings disagree on version (one is
original, the other is instrumental / live / acoustic / remix /
etc), return FAIL — the fingerprint identified a real song, just
not the version the caller asked for.

Reuses `MusicMatchingEngine.detect_version_type` so the same regex
patterns the pre-download Soulseek matcher applies also drive
post-download verification. No duplicated tables.

Also gates the secondary fallback scan, so a wrong-version variant
sitting in the same fingerprint cluster can't win the loop after
the best match has already been version-rejected.

6 tests pin the behavior:
- instrumental returned for vocal request → FAIL
- vocal returned for instrumental request → FAIL
- live vs acoustic → FAIL
- matching versions on both sides → PASS
- original-to-original happy path → PASS (regression guard)
- secondary scan skips wrong-version recordings → not PASS

2194/2194 full suite green (was 2188 + 6 new).
2026-05-07 13:25:30 -07:00