From 027549be59c1b84655d2ad2bb4ad30a74f943ffc Mon Sep 17 00:00:00 2001 From: Broque Thomas <26755000+Nezreka@users.noreply.github.com> Date: Sun, 12 Apr 2026 10:48:24 -0700 Subject: [PATCH] Fix album matching using full similarity instead of word subset check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The old subset check treated "Paradise" as matching "Club Paradise" because {'paradise'} is a subset of {'club', 'paradise'}. Both got the same +0.10 bonus, so the wrong album could be selected. Now uses SequenceMatcher for full-string similarity between the wanted album name and each path segment. Exact matches (>= 0.85) get +0.10, partial matches (>= 0.60) get +0.03, no match gets +0.00. No penalty applied — purely adjusts bonus sizing so the correct album ranks higher. --- core/matching_engine.py | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/core/matching_engine.py b/core/matching_engine.py index 83ed1c09..586914c5 100644 --- a/core/matching_engine.py +++ b/core/matching_engine.py @@ -657,22 +657,30 @@ class MusicMatchingEngine: # --- Source Type --- is_youtube = slskd_track.username == 'youtube' - # 4b. Album Bonus: Prefer results from the correct album folder - # This ensures "Dark Side of the Moon" sources rank above "Greatest Hits" - # when both have the same song. Binary check — album words in path or not. + # 4b. Album Bonus/Penalty: Prefer results from the correct album folder. + # Uses full-string similarity to prevent "Paradise" matching "Club Paradise". + # The old subset check said "paradise" ⊂ {"club", "paradise"} = True, which was wrong. album_bonus = 0.0 album_name = getattr(spotify_track, 'album', None) if album_name and not is_youtube: - album_words = set(self.clean_album_name(album_name).split()) - if album_words: + album_cleaned = self.clean_album_name(album_name) + if album_cleaned: + best_album_sim = 0.0 path_segments = re.split(r'[/\\]', slskd_track.filename) for segment in path_segments: if not segment: continue - seg_words = set(self.normalize_string(segment).split()) - if album_words.issubset(seg_words): - album_bonus = 0.10 - break + seg_cleaned = self.normalize_string(segment) + if not seg_cleaned: + continue + sim = SequenceMatcher(None, album_cleaned, seg_cleaned).ratio() + best_album_sim = max(best_album_sim, sim) + + if best_album_sim >= 0.85: + album_bonus = 0.10 # Strong album match (e.g. "Paradise" vs "Paradise") + elif best_album_sim >= 0.60: + album_bonus = 0.03 # Partial match — small bonus + # No penalty for low similarity — the file might just not have album folders # 5. Special handling for short titles (high false positive risk) # Titles like "Run", "Love", "Girls", "Stay" need stricter artist matching