This commit is contained in:
Broque Thomas 2025-07-25 15:33:59 -07:00
parent 6dd0be2bc2
commit c94f5f2b53
4 changed files with 4625 additions and 13 deletions

View file

@ -1 +1 @@
{"access_token": "BQAOkCHX28CL-pVeujeJLh4eHgtpT8ZbyFQmRT5OODgBQKUmsM0omIWpGKosEkBpptGbqXW1Bv0GhV_hfnDQOXBsPR9tS2aFz-NmbMHVu-SvlweJvCC_5UxhVmOfsVje6RFmrQ6gsiP0V5kyV-8NT8eXs4yFLEx2zcz6mCh7Ei1xSwK-vF8ajeAq2O6IgPxbo6AnNEXSrm1cyt1z-raCCFU-qoF6grTZEn1CdzWkwInNqCxLzyViePpiERvznf9o", "token_type": "Bearer", "expires_in": 3600, "scope": "user-library-read user-read-private playlist-read-private playlist-read-collaborative user-read-email", "expires_at": 1753482547, "refresh_token": "AQDmfQkPCGObfJeTUIbW1hAAwhSqkuHRA3Qh2dqVYMRh0eCkFMQgPNJDDzF8y-BiaVbj80zePkK_XSfYH1aJutMtNbnsqRKWuxP31BTrMc7pdUdbE7Fma4oH8wpDUKdG3MM"}
{"access_token": "BQD9oDwW8TwgzLCnFVOcmV5Fla9uvVQBiF6Mepygzv9cDix5Qv1zyNGGQ8vQMHb--psBdJ8yPd9mu4OO-L4ZStl_JLvi9c50JcvuZBFX7AA25qRL6FuCkcUxYxkLct5hezvsz3NF8qtwcTv8TlJZ42a1E0sWmA7EhnDGx42EoQppz6JmKWX0F32W4PHOaeugZaDg3BM4V0Lzy9SIJfALuPgXMob1bxGU2le49AwlKOsMOqjH03IcqaSQVOjp4YDe", "token_type": "Bearer", "expires_in": 3600, "scope": "user-library-read user-read-private playlist-read-private playlist-read-collaborative user-read-email", "expires_at": 1753486281, "refresh_token": "AQDmfQkPCGObfJeTUIbW1hAAwhSqkuHRA3Qh2dqVYMRh0eCkFMQgPNJDDzF8y-BiaVbj80zePkK_XSfYH1aJutMtNbnsqRKWuxP31BTrMc7pdUdbE7Fma4oH8wpDUKdG3MM"}

File diff suppressed because it is too large Load diff

View file

@ -4441,25 +4441,54 @@ class DownloadMissingTracksModal(QDialog):
def get_valid_candidates(self, results, spotify_track, query):
"""
Scores and filters search results using the MusicMatchingEngine to find the best candidates.
This replaces the simple size-based sorting with intelligent, confidence-based scoring.
Scores and filters search results, then performs a strict artist verification
by checking the file path. This prevents downloading tracks from the wrong artist.
"""
if not results:
return []
# Use the new matching engine function to score, filter, and sort the results.
# This returns a list of SlskdTrack objects with a 'confidence' attribute,
# already sorted from best to worst and filtered by our confidence threshold.
confident_matches = self.matching_engine.find_best_slskd_matches(spotify_track, results)
# Step 1: Get initial confident matches based on title, bitrate, etc.
# This gives us a sorted list of potential candidates.
initial_candidates = self.matching_engine.find_best_slskd_matches(spotify_track, results)
if confident_matches:
best_confidence = confident_matches[0].confidence
print(f"✅ Found {len(confident_matches)} confident matches for '{spotify_track.name}'. Best score: {best_confidence:.2f} from query '{query}'")
if not initial_candidates:
print(f"⚠️ No initial candidates found for '{spotify_track.name}' from query '{query}'.")
return []
print(f"✅ Found {len(initial_candidates)} initial candidates for '{spotify_track.name}'. Now verifying artist...")
# Step 2: Perform strict artist verification on the initial candidates.
verified_candidates = []
spotify_artist_name = spotify_track.artists[0] if spotify_track.artists else ""
# **IMPROVEMENT**: More robust normalization for both artist name and file path.
# This removes all non-alphanumeric characters and converts to lowercase.
# e.g., "Virtual Mage" -> "virtualmage", "virtual-mage" -> "virtualmage"
normalized_spotify_artist = re.sub(r'[^a-zA-Z0-9]', '', spotify_artist_name).lower()
for candidate in initial_candidates:
# The 'filename' from Soulseek includes the full folder path.
slskd_full_path = candidate.filename
# Apply the same robust normalization to the Soulseek path.
normalized_slskd_path = re.sub(r'[^a-zA-Z0-9]', '', slskd_full_path).lower()
# **THE CRITICAL CHECK**: See if the cleaned artist's name is in the cleaned folder path.
if normalized_spotify_artist in normalized_slskd_path:
# Artist name was found in the path, this is a valid candidate.
print(f"✔️ Artist '{spotify_artist_name}' VERIFIED in path: '{slskd_full_path}'")
verified_candidates.append(candidate)
else:
# Artist name was NOT found. Discard this candidate.
print(f"❌ Artist '{spotify_artist_name}' NOT found in path: '{slskd_full_path}'. Discarding candidate.")
if verified_candidates:
best_confidence = verified_candidates[0].confidence
print(f"✅ Found {len(verified_candidates)} VERIFIED matches for '{spotify_track.name}'. Best score: {best_confidence:.2f}")
else:
print(f"⚠️ No confident matches found for '{spotify_track.name}' from query '{query}'.")
return confident_matches
print(f"⚠️ No verified matches found for '{spotify_track.name}' after checking file paths.")
return verified_candidates
def create_spotify_based_search_result_from_validation(self, slskd_result, spotify_metadata):
"""Create SpotifyBasedSearchResult from validation results"""
class SpotifyBasedSearchResult: