Enforce strict version matching for track confidence

Adds strict checks to ensure Soulseek track versions (live, remix, acoustic, instrumental) are only matched if the Spotify track title contains corresponding version indicators. This prevents mismatched versions from being accepted and applies a reduced penalty for matching non-original versions.
pull/49/head
Broque Thomas 7 months ago
parent dead8da5ee
commit 09b4638279

@ -613,16 +613,89 @@ class MusicMatchingEngine:
"""
Enhanced version of calculate_slskd_match_confidence with version-aware scoring.
Returns (confidence, version_type) tuple.
STRICT VERSION MATCHING:
- Live versions are ONLY accepted if Spotify track title contains "live" or "live version"
- Remixes are ONLY accepted if Spotify track title contains "remix" or "mix"
- Acoustic versions are ONLY accepted if Spotify track title contains "acoustic"
- etc.
"""
# Get base confidence using existing logic
base_confidence = self.calculate_slskd_match_confidence(spotify_track, slskd_track)
# Detect version type and get penalty
# Detect version type in Soulseek result
version_type, penalty = self.detect_version_type(slskd_track.filename)
# Apply version penalty
# Check if Spotify track title contains version indicators
spotify_title_lower = spotify_track.name.lower()
# STRICT VERSION MATCHING: Reject mismatched versions
if version_type == 'live':
# Only accept live versions if Spotify title has live as a VERSION INDICATOR
# Patterns: (Live), - Live, [Live], Live at, Live from, Live in, Live Version
# NOT: words ending with 'live' like "Let Me Live" or starting like "Lively"
live_patterns = [
r'\(live\)', # (Live) or (Live at Wembley)
r'\[live\]', # [Live]
r'[-–—]\s*live\b', # - Live or Live
r'\blive\s+at\b', # Live at
r'\blive\s+from\b', # Live from
r'\blive\s+in\b', # Live in
r'\blive\s+version\b', # Live Version
r'\blive\s+recording\b' # Live Recording
]
has_live_indicator = any(re.search(pattern, spotify_title_lower) for pattern in live_patterns)
if not has_live_indicator:
# Reject: Soulseek has live version but Spotify doesn't want it
return 0.0, 'rejected_version_mismatch'
elif version_type == 'remix':
# Only accept remixes if Spotify title has remix as a VERSION INDICATOR
# Patterns: (Remix), - Remix, [Remix], Remix, Mix
remix_patterns = [
r'\(.*?(remix|mix|rmx).*?\)', # (Remix) or (DJ Remix)
r'\[.*?(remix|mix|rmx).*?\]', # [Remix]
r'[-–—]\s*(remix|mix|rmx)\b', # - Remix
r'\b(remix|mix|rmx)\s*$', # Remix at end
]
has_remix_indicator = any(re.search(pattern, spotify_title_lower) for pattern in remix_patterns)
if not has_remix_indicator:
# Reject: Soulseek has remix but Spotify wants original
return 0.0, 'rejected_version_mismatch'
elif version_type == 'acoustic':
# Only accept acoustic if Spotify title has acoustic as a VERSION INDICATOR
acoustic_patterns = [
r'\(.*?acoustic.*?\)', # (Acoustic)
r'\[.*?acoustic.*?\]', # [Acoustic]
r'[-–—]\s*acoustic\b', # - Acoustic
r'\bacoustic\s+version\b', # Acoustic Version
]
has_acoustic_indicator = any(re.search(pattern, spotify_title_lower) for pattern in acoustic_patterns)
if not has_acoustic_indicator:
# Reject: Soulseek has acoustic but Spotify wants original
return 0.0, 'rejected_version_mismatch'
elif version_type == 'instrumental':
# Only accept instrumental if Spotify title has instrumental as a VERSION INDICATOR
instrumental_patterns = [
r'\(.*?instrumental.*?\)', # (Instrumental)
r'\[.*?instrumental.*?\]', # [Instrumental]
r'[-–—]\s*instrumental\b', # - Instrumental
r'\binstrumental\s+version\b', # Instrumental Version
]
has_instrumental_indicator = any(re.search(pattern, spotify_title_lower) for pattern in instrumental_patterns)
if not has_instrumental_indicator:
# Reject: Soulseek has instrumental but Spotify wants original
return 0.0, 'rejected_version_mismatch'
# Apply version penalty (for matching versions, slight penalty for quality differences)
if version_type != 'original':
adjusted_confidence = max(0.0, base_confidence - penalty)
adjusted_confidence = max(0.0, base_confidence - (penalty * 0.5)) # Reduced penalty since it's a match
# Store version info on the track object for UI display
slskd_track.version_type = version_type
slskd_track.version_penalty = penalty
@ -630,7 +703,7 @@ class MusicMatchingEngine:
adjusted_confidence = base_confidence
slskd_track.version_type = 'original'
slskd_track.version_penalty = 0.0
return adjusted_confidence, version_type
def find_best_slskd_matches_enhanced(self, spotify_track: SpotifyTrack, slskd_results: List[TrackResult]) -> List[TrackResult]:

Loading…
Cancel
Save