diff --git a/core/matching/audio_verification.py b/core/matching/audio_verification.py index 06b90949..a347ce73 100644 --- a/core/matching/audio_verification.py +++ b/core/matching/audio_verification.py @@ -67,6 +67,11 @@ def normalize(text: str) -> str: '', s, flags=re.IGNORECASE, ) s = re.sub(r'\s*-\s*from\s+.+$', '', s, flags=re.IGNORECASE) + # Path/separator punctuation -> space so a title keeps matching a source + # filename that substituted '_' for an illegal '/' or ':' (#851): the on-disk + # "You See Big Girl _ T_T" must normalize the same as "You See Big Girl / T:T". + # Done before the strip below so they become word boundaries, not joins. + s = re.sub(r'[\\/:_]+', ' ', s) # Drop remaining punctuation but keep word chars (incl. CJK) + spaces. s = re.sub(r'[^\w\s]', '', s) s = re.sub(r'\s+', ' ', s).strip() diff --git a/tests/matching/test_normalize_slash_851.py b/tests/matching/test_normalize_slash_851.py new file mode 100644 index 00000000..9b4b3c8c --- /dev/null +++ b/tests/matching/test_normalize_slash_851.py @@ -0,0 +1,24 @@ +"""#851: a '/' or ':' in a title must normalize the same as a source filename +that substituted '_' for them, so the candidate matcher stops rejecting valid +downloads (e.g. Sawano's "You See Big Girl / T:T" vs on-disk "..._ T_T").""" + +from __future__ import annotations + +from core.matching.audio_verification import normalize, similarity + + +def test_slash_colon_title_matches_underscore_source(): + assert normalize("You See Big Girl / T:T") == normalize("You See Big Girl _ T_T") + assert similarity("You See Big Girl / T:T", "You See Big Girl _ T_T") == 1.0 + + +def test_separators_become_word_boundaries(): + assert normalize("Re:Zero") == "re zero" + assert normalize("AC/DC") == "ac dc" + assert normalize("T_T") == "t t" + + +def test_joined_variant_stays_above_title_threshold(): + # Spacing a separator must not drop a joined-variant match below 0.70. + assert similarity("AC/DC", "ACDC") >= 0.70 + assert similarity("12:05", "1205") >= 0.70