Fix false library match between normal and Extended Mix titles

Featuring cleanup after bracket flattening stripped version suffixes, so
Download Missing treated distinct tracks (e.g. Latinamerica vs Extended Mix)
as already in library. Remove feat blocks before flattening and bound
unparenthesized feat removal; add regression tests.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Francesco Durighetto 2026-06-03 00:28:18 +02:00
parent cd9e4abc7c
commit 6b7e6bff61
2 changed files with 96 additions and 5 deletions

View file

@ -7296,6 +7296,22 @@ class MusicDatabase:
cleaned = re.sub(r'\s*\(with\s+[^)]*\)', '', cleaned, flags=re.IGNORECASE)
cleaned = re.sub(r'\s*\[with\s+[^\]]*\]', '', cleaned, flags=re.IGNORECASE)
# Featuring in parentheses/brackets — must run BEFORE bracket flattening.
# Otherwise ``feat.`` removal after flattening is greedy and strips
# version suffixes ("Extended Mix", "Radio Edit", …) from the same title.
cleaned = re.sub(
r'\s*\([^)]*(?:feat\.?|ft\.?|featuring)[^)]*\)',
'',
cleaned,
flags=re.IGNORECASE,
)
cleaned = re.sub(
r'\s*\[[^\]]*(?:feat\.?|ft\.?|featuring)[^\]]*\]',
'',
cleaned,
flags=re.IGNORECASE,
)
# STEP 1: Normalize bracket/dash styles for consistent matching
# Convert all bracket styles to spaces for better matching
cleaned = re.sub(r'\s*[\[\(]\s*', ' ', cleaned) # Convert opening brackets/parens to space
@ -7311,11 +7327,6 @@ class MusicDatabase:
r'\s*explicit\s*', # Remove explicit markers
r'\s*clean\s*', # Remove clean markers
# Featuring/collaboration (metadata, not different version)
r'\s*feat\..*', # Remove featuring
r'\s*featuring.*', # Remove featuring
r'\s*ft\..*', # Remove ft.
# Remasters (same recording, different mastering)
r'\s*\d{4}\s*remaster.*', # Remove "2015 remaster"
r'\s*remaster.*', # Remove "remaster/remastered"
@ -7352,6 +7363,19 @@ class MusicDatabase:
for pattern in patterns_to_remove:
cleaned = re.sub(pattern, '', cleaned, flags=re.IGNORECASE).strip()
# Unparenthesized featuring (e.g. after bracket flatten) — bounded so
# "feat. Vika - Extended Mix" keeps the version tail.
_version_boundary = (
r'(?:extended|radio|club|dub|instrumental|acoustic|live|remix|'
r'original|edit|mix|version)\b'
)
cleaned = re.sub(
rf'\s+(?:feat\.?|ft\.?|featuring)\s+.+?(?=\s+-\s+{_version_boundary}|\s+{_version_boundary}|$)',
'',
cleaned,
flags=re.IGNORECASE,
).strip()
# STEP 3: Clean up extra spaces
cleaned = re.sub(r'\s+', ' ', cleaned).strip()

View file

@ -0,0 +1,67 @@
"""Regression: normal vs Extended Mix must not collapse to the same cleaned title."""
import tempfile
from pathlib import Path
import pytest
from database.music_database import DatabaseTrack, MusicDatabase
@pytest.fixture
def db(tmp_path: Path):
return MusicDatabase(database_path=str(tmp_path / "test.db"))
def test_clean_title_preserves_extended_mix_after_feat(db):
normal = db._clean_track_title_for_comparison("Latinamerica (feat. Vika)")
extended = db._clean_track_title_for_comparison(
"Latinamerica (feat. Vika) - Extended Mix"
)
assert normal == "latinamerica"
assert extended == "latinamerica extended mix"
assert normal != extended
def test_normal_does_not_match_extended_in_library(db):
extended_track = DatabaseTrack(
id="t1",
album_id="a1",
artist_id="ar1",
title="Latinamerica (feat. Vika) - Extended Mix",
track_number=1,
duration=300000,
file_path="/music/ext.flac",
bitrate=320,
)
extended_track.artist_name = "Raffa FL"
extended_track.album_title = "Latinamerica (feat. Vika)"
confidence = db._calculate_track_confidence(
"Latinamerica (feat. Vika)",
"Raffa FL",
extended_track,
)
assert confidence < 0.7
def test_extended_matches_extended_in_library(db):
extended_track = DatabaseTrack(
id="t1",
album_id="a1",
artist_id="ar1",
title="Latinamerica (feat. Vika) - Extended Mix",
track_number=1,
duration=300000,
file_path="/music/ext.flac",
bitrate=320,
)
extended_track.artist_name = "Raffa FL"
extended_track.album_title = "Latinamerica (feat. Vika)"
confidence = db._calculate_track_confidence(
"Latinamerica (feat. Vika) - Extended Mix",
"Raffa FL",
extended_track,
)
assert confidence >= 0.7