soulsync/tests/matching/test_script_compat.py
BoulderBadgeDad 2604704a27 #797: stop AcoustID quarantining correct non-English-artist downloads
AcoustID returns a recording's title/artist in their ORIGINAL script
(e.g. "久石譲" for Joe Hisaishi) while SoulSync's expected metadata is
romanized/English. A correct download then fails verification on two
walls: the title can never clear the 0.70 similarity bar cross-script,
and the only skip path that ignores the title required a near-perfect
0.95 fingerprint plus a resolved alias. Result: every non-English
artist trips it. Two complementary fixes, per the reporter's two ideas.

Graceful fix (automatic):
- New pure core/matching/script_compat.py detects when two strings are
  in genuinely different writing systems (CJK/Hangul/Cyrillic/Greek/
  Arabic/Hebrew/Thai vs Latin). Accented Latin (Beyoncé, Sigur Rós)
  stays Latin — no false trigger.
- acoustid_verification.py: when the EXPECTED artist and the matched
  artist span scripts AND the artist is confirmed via the existing
  MusicBrainz alias bridge, SKIP instead of quarantine, without the
  0.95 floor (the 0.80 trust floor already gates the fingerprint).
- Deliberately narrow: keyed on the ARTIST spanning scripts + being
  confirmed. A same-script artist with only a cross-script title keeps
  the stricter 0.95 floor, so the #607 wrong-file protection (Kendrick
  R.O.T.C, low-fingerprint Japanese-title) is untouched.

Per-request toggle (manual escape hatch):
- New "Skip AcoustID verification" checkbox in the download-missing
  modal beside "Force Download All".
- skip_acoustid threads request -> batch -> per-track track_info ->
  download context (same path as _playlist_folder_mode), landing on
  the existing _skip_quarantine_check='acoustid' bypass. No new
  mechanism; only the AcoustID gate is bypassed (integrity/bit-depth
  still run).

Tests:
- tests/matching/test_script_compat.py — script-boundary cases.
- test_acoustid_skip_logic.py — Joe Hisaishi SKIPs at 0.85; unconfirmed
  cross-script artist still FAILs; same-script low-fingerprint still
  FAILs.
- test_downloads_candidates.py — toggle injects the bypass; absent
  toggle keeps verification.

Full suite: 5169 passed; only pre-existing soundcloud /app env failures
remain. Zero regressions.
2026-06-05 16:02:01 -07:00

79 lines
3.1 KiB
Python

"""Tests for core/matching/script_compat.py — writing-system detection.
Issue #797 — these pin the exact boundary that the AcoustID verifier
relies on: accented Latin is still Latin (no false cross-script
trigger), but genuinely different writing systems (CJK / Hangul /
Cyrillic / Greek / Arabic / Hebrew / Thai) ARE flagged so a
romanized-vs-native artist comparison isn't treated as a real mismatch.
"""
from __future__ import annotations
import pytest
from core.matching.script_compat import (
has_strong_nonlatin,
is_cross_script_mismatch,
)
# ---------------------------------------------------------------------------
# has_strong_nonlatin — accented Latin must NOT count
# ---------------------------------------------------------------------------
@pytest.mark.parametrize('text', [
'Beyoncé', 'Sigur Rós', 'Mötley Crüe', 'Joe Hisaishi',
'Kendrick Lamar', 'Dmitry Yablonsky', 'AC/DC', 'P!nk',
'', ' ', '12345', 'Café del Mar',
])
def test_latin_and_accented_latin_is_not_nonlatin(text):
assert has_strong_nonlatin(text) is False
@pytest.mark.parametrize('text', [
'久石譲', # kanji (Joe Hisaishi)
'残酷な天使のテーゼ', # kana + kanji
'Дмитрий Яблонский', # Cyrillic
'방탄소년단', # Hangul (BTS)
'Σωκράτης', # Greek
'عمرو دياب', # Arabic
'שלום', # Hebrew
'ก้อง สหรัถ', # Thai
])
def test_real_nonlatin_scripts_detected(text):
assert has_strong_nonlatin(text) is True
# ---------------------------------------------------------------------------
# is_cross_script_mismatch — the verifier's gate
# ---------------------------------------------------------------------------
def test_romanized_vs_native_is_cross_script():
# The reported case (#797): expected romanized, AcoustID native.
assert is_cross_script_mismatch('Joe Hisaishi', '久石譲') is True
assert is_cross_script_mismatch('Dmitry Yablonsky', 'Дмитрий Яблонский') is True
def test_is_symmetric():
assert is_cross_script_mismatch('久石譲', 'Joe Hisaishi') is True
def test_same_latin_both_sides_is_not_mismatch():
# English-vs-English — comparison is meaningful, no bridge. This is
# the Kendrick R.O.T.C protection surface: must stay False so the
# verifier keeps its strict FAIL path.
assert is_cross_script_mismatch('Kendrick Lamar', 'Kendrick Lamar feat. BJ') is False
assert is_cross_script_mismatch('Crown', 'Crown of Thorns') is False
def test_same_nonlatin_both_sides_is_not_mismatch():
# Both native — same-script similarity still works, don't relax.
assert is_cross_script_mismatch('久石譲', '久石譲') is False
assert is_cross_script_mismatch('久石譲', '坂本龍一') is False
def test_empty_or_letterless_other_side_is_not_mismatch():
# One side non-Latin but the other has no Latin LETTER to bridge to.
assert is_cross_script_mismatch('', '久石譲') is False
assert is_cross_script_mismatch('12345', '久石譲') is False
assert is_cross_script_mismatch('久石譲', ' ') is False