Merge 6b7e6bff61 into 60e7193539
This commit is contained in:
commit
0de1641b90
2 changed files with 96 additions and 5 deletions
|
|
@ -8513,6 +8513,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)
|
||||||
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
|
# STEP 1: Normalize bracket/dash styles for consistent matching
|
||||||
# Convert all bracket styles to spaces for better matching
|
# Convert all bracket styles to spaces for better matching
|
||||||
cleaned = re.sub(r'\s*[\[\(]\s*', ' ', cleaned) # Convert opening brackets/parens to space
|
cleaned = re.sub(r'\s*[\[\(]\s*', ' ', cleaned) # Convert opening brackets/parens to space
|
||||||
|
|
@ -8528,11 +8544,6 @@ class MusicDatabase:
|
||||||
r'\s*explicit\s*', # Remove explicit markers
|
r'\s*explicit\s*', # Remove explicit markers
|
||||||
r'\s*clean\s*', # Remove clean 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)
|
# Remasters (same recording, different mastering)
|
||||||
r'\s*\d{4}\s*remaster.*', # Remove "2015 remaster"
|
r'\s*\d{4}\s*remaster.*', # Remove "2015 remaster"
|
||||||
r'\s*remaster.*', # Remove "remaster/remastered"
|
r'\s*remaster.*', # Remove "remaster/remastered"
|
||||||
|
|
@ -8569,6 +8580,19 @@ class MusicDatabase:
|
||||||
for pattern in patterns_to_remove:
|
for pattern in patterns_to_remove:
|
||||||
cleaned = re.sub(pattern, '', cleaned, flags=re.IGNORECASE).strip()
|
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
|
# STEP 3: Clean up extra spaces
|
||||||
cleaned = re.sub(r'\s+', ' ', cleaned).strip()
|
cleaned = re.sub(r'\s+', ' ', cleaned).strip()
|
||||||
|
|
||||||
|
|
|
||||||
67
tests/test_track_title_version_distinction.py
Normal file
67
tests/test_track_title_version_distinction.py
Normal 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
|
||||||
Loading…
Reference in a new issue