From 3b510a2ac84348fce1a066dfa5bf619e754d28ea Mon Sep 17 00:00:00 2001 From: chuenchen309 <48723787+chuenchen309@users.noreply.github.com> Date: Thu, 16 Jul 2026 08:13:00 +0800 Subject: [PATCH 1/3] fix(autotag): "featuring" pattern in string_dist matches mid-word "ft" SD_PATTERNS' featuring/feat/ft regex has no word boundary before the alternation, so it matches "ft" embedded in ordinary words like "draft", "left", "gift", "craft" and treats everything after it as a low-weight suffix. "Draft Beer" vs. "Draft Whiskey" scores 0.05 (near-identical) instead of correctly registering as very different. --- beets/autotag/distance.py | 2 +- docs/changelog.rst | 4 ++++ test/autotag/test_distance.py | 17 +++++++++++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/beets/autotag/distance.py b/beets/autotag/distance.py index d5821f4733..6d57cfd60d 100644 --- a/beets/autotag/distance.py +++ b/beets/autotag/distance.py @@ -35,7 +35,7 @@ SD_PATTERNS = [ (r"^the ", 0.1), (r"[\[\(]?(ep|single)[\]\)]?", 0.0), - (r"[\[\(]?(featuring|feat|ft)[\. :].+", 0.1), + (r"[\[\(]?\b(featuring|feat|ft)[\. :].+", 0.1), (r"\(.*?\)", 0.3), (r"\[.*?\]", 0.3), (r"(, )?(pt\.|part) .+", 0.2), diff --git a/docs/changelog.rst b/docs/changelog.rst index 096a35a6db..4a549dbd12 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -95,6 +95,10 @@ Bug fixes valid date/time string" error instead of crashing with an uncaught ``KeyError``. A ``|`` was being accepted as a relative-date unit due to a regular expression character-class typo. +- Autotagging distance calculations no longer treat ordinary words containing + "ft" (such as "draft", "left", "gift", "craft") as a "featuring artist" + suffix, which was silently making genuinely different titles/artists score + as near-identical matches. .. For plugin developers diff --git a/test/autotag/test_distance.py b/test/autotag/test_distance.py index 15c4a7208f..03c2513c77 100644 --- a/test/autotag/test_distance.py +++ b/test/autotag/test_distance.py @@ -282,6 +282,23 @@ def test_matching_distance(self, string1, string2): def test_different_distance(self): assert string_dist("Some String", "Totally Different") != 0.0 + @pytest.mark.parametrize( + "string1, string2", + [ + ("Draft Beer", "Draft Whiskey"), + ("Left Field", "Left Symphony"), + ("Gift Ideas", "Gift Cards"), + ("Craft Beer", "Craft Wine"), + ], + ) + def test_featuring_pattern_does_not_match_mid_word(self, string1, string2): + # The "featuring"/"feat"/"ft" pattern must not match "ft" embedded + # inside an ordinary word (draft, left, gift, craft, ...) -- doing so + # would treat everything after "ft" as a low-weight suffix and make + # genuinely different strings look almost identical instead of + # correctly registering as a large distance. + assert string_dist(string1, string2) > 0.3 + @pytest.mark.parametrize( "string1, string2, reference", [ From 9d7f9429b9d1ee588877342c8ae0ee48ba58b887 Mon Sep 17 00:00:00 2001 From: chuenchen309 <48723787+chuenchen309@users.noreply.github.com> Date: Thu, 16 Jul 2026 18:11:30 +0800 Subject: [PATCH 2/3] docs: reflow changelog entry to satisfy docstrfmt Co-Authored-By: Claude Opus 4.8 (1M context) --- docs/changelog.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 4a549dbd12..f4fadcdb78 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -97,8 +97,8 @@ Bug fixes regular expression character-class typo. - Autotagging distance calculations no longer treat ordinary words containing "ft" (such as "draft", "left", "gift", "craft") as a "featuring artist" - suffix, which was silently making genuinely different titles/artists score - as near-identical matches. + suffix, which was silently making genuinely different titles/artists score as + near-identical matches. .. For plugin developers From f0bb4971f78a0010344932098ccfd34f2ba5cb0d Mon Sep 17 00:00:00 2001 From: chuenchen309 <48723787+chuenchen309@users.noreply.github.com> Date: Thu, 16 Jul 2026 18:42:15 +0800 Subject: [PATCH 3/3] fix(autotag): make featuring word boundary symmetric Apply reviewer suggestion (@snejus): add a trailing \b after the (featuring|feat|ft) alternation so the boundary is explicit on both sides, matching the leading \b. Co-Authored-By: Claude Opus 4.8 (1M context) --- beets/autotag/distance.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/beets/autotag/distance.py b/beets/autotag/distance.py index 6d57cfd60d..ba6d7939bf 100644 --- a/beets/autotag/distance.py +++ b/beets/autotag/distance.py @@ -35,7 +35,7 @@ SD_PATTERNS = [ (r"^the ", 0.1), (r"[\[\(]?(ep|single)[\]\)]?", 0.0), - (r"[\[\(]?\b(featuring|feat|ft)[\. :].+", 0.1), + (r"[\[\(]?\b(featuring|feat|ft)\b[\. :].+", 0.1), (r"\(.*?\)", 0.3), (r"\[.*?\]", 0.3), (r"(, )?(pt\.|part) .+", 0.2),