better
This commit is contained in:
parent
b42b1aeef5
commit
d8c16ba87a
5 changed files with 7223 additions and 2 deletions
|
|
@ -1 +1 @@
|
|||
{"access_token": "BQBV3J80UTFPrCM5cWbrN00DAauBeT6OykJaRhh3UYkDQHuaThaxxzNvxFPw2nxNWgEd4qk37NpIvWxBUdFl3_tZjZP6Gp2ZJr6U06QjYa5__x2VIQ5Av6pUiA6Iu0IgSfC49AhXjjmBG5wPiw7Q6l24MmB9yHfs7zgVlfqREAs5_qkD0GFAPlpTEYQamOgfOp9BtGawOQZje5m9ddrKOdSLOCQ77Hc5XGZIMmJpKvwSIJdFIs5YXm7Uy7vBhSFy", "token_type": "Bearer", "expires_in": 3600, "scope": "user-library-read user-read-private playlist-read-private playlist-read-collaborative user-read-email", "expires_at": 1752544984, "refresh_token": "AQDmfQkPCGObfJeTUIbW1hAAwhSqkuHRA3Qh2dqVYMRh0eCkFMQgPNJDDzF8y-BiaVbj80zePkK_XSfYH1aJutMtNbnsqRKWuxP31BTrMc7pdUdbE7Fma4oH8wpDUKdG3MM"}
|
||||
{"access_token": "BQBL7Raj7Urrt1zo-GMFVGrLMtq-ytp9u8wvZ0vie6JJWk77ileGQLgHizS_Hdvrb4xA3PJYYZd2r08RWAZwkFMhFwfhQH9YKS8W_BCHrVo_RVcVmZrOhhgdlhba28WXvL8rQCl50kM7oU1RuFqyprw2oy3wPbv1bkwHPM638nzV8u1tHAd8aNeYojYWvaWvd3i8iKYcnit3zccprYDXW8b-In-G75vxhP7cj4Dg-oRU-58CGRxGBocKKDh0R5Vk", "token_type": "Bearer", "expires_in": 3600, "scope": "user-library-read user-read-private playlist-read-private playlist-read-collaborative user-read-email", "expires_at": 1752548677, "refresh_token": "AQDmfQkPCGObfJeTUIbW1hAAwhSqkuHRA3Qh2dqVYMRh0eCkFMQgPNJDDzF8y-BiaVbj80zePkK_XSfYH1aJutMtNbnsqRKWuxP31BTrMc7pdUdbE7Fma4oH8wpDUKdG3MM"}
|
||||
7122
logs/app.log
7122
logs/app.log
File diff suppressed because it is too large
Load diff
Binary file not shown.
Binary file not shown.
|
|
@ -6546,6 +6546,10 @@ class DownloadsPage(QWidget):
|
|||
print(f" Selected album: '{selected_album.name}'")
|
||||
print(f" 🔒 ALL tracks will be forced into: '{selected_album.name}'")
|
||||
|
||||
# Fetch official track titles from Spotify album
|
||||
print(f"🎵 Fetching official track titles from Spotify album...")
|
||||
spotify_tracks = self._get_spotify_album_tracks(selected_album)
|
||||
|
||||
download_items = []
|
||||
|
||||
# Process all tracks and FORCE them into the selected album
|
||||
|
|
@ -6566,7 +6570,16 @@ class DownloadsPage(QWidget):
|
|||
else:
|
||||
track.track_number = track_index
|
||||
|
||||
print(f" 🎵 Track {track_index}: {track.title} -> FORCED into Album: {selected_album.name}")
|
||||
# Match to Spotify track title if available
|
||||
spotify_title = self._match_track_to_spotify_title(track, spotify_tracks)
|
||||
if spotify_title:
|
||||
print(f" 🎵 Track {track_index}: '{track.title}' -> Spotify title: '{spotify_title}'")
|
||||
track._spotify_title = spotify_title # Store the official Spotify title
|
||||
track._spotify_clean_title = spotify_title # This will be used for file naming
|
||||
else:
|
||||
print(f" 🎵 Track {track_index}: '{track.title}' -> No Spotify match found, using original")
|
||||
|
||||
print(f" 🔒 FORCED into Album: {selected_album.name}")
|
||||
|
||||
# Start individual track download with enhanced metadata
|
||||
download_item = self._start_download_with_artist(track, artist)
|
||||
|
|
@ -6574,6 +6587,12 @@ class DownloadsPage(QWidget):
|
|||
# Also apply the forced album to the download item
|
||||
download_item._force_album_name = selected_album.name
|
||||
download_item._force_album_mode = True
|
||||
|
||||
# Apply Spotify title to download item if available
|
||||
if hasattr(track, '_spotify_clean_title'):
|
||||
download_item._spotify_clean_title = track._spotify_clean_title
|
||||
print(f"✅ Applied Spotify title to download item: '{track._spotify_clean_title}'")
|
||||
|
||||
download_items.append(download_item)
|
||||
print(f"✓ Successfully queued track: {track.title}")
|
||||
else:
|
||||
|
|
@ -9103,6 +9122,86 @@ class DownloadsPage(QWidget):
|
|||
print(f"❌ Error extracting track number from filename: {e}")
|
||||
return None
|
||||
|
||||
def _get_spotify_album_tracks(self, selected_album: Album) -> List[dict]:
|
||||
"""Fetch all tracks from the selected Spotify album"""
|
||||
try:
|
||||
print(f"🎵 Fetching tracks from Spotify album: {selected_album.name}")
|
||||
tracks_data = self.spotify_client.get_album_tracks(selected_album.id)
|
||||
|
||||
if tracks_data and 'items' in tracks_data:
|
||||
tracks = []
|
||||
for track_data in tracks_data['items']:
|
||||
tracks.append({
|
||||
'name': track_data['name'],
|
||||
'track_number': track_data['track_number'],
|
||||
'duration_ms': track_data['duration_ms'],
|
||||
'id': track_data['id']
|
||||
})
|
||||
print(f"✅ Found {len(tracks)} tracks in Spotify album")
|
||||
return tracks
|
||||
else:
|
||||
print(f"❌ No tracks found in Spotify album")
|
||||
return []
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Error fetching Spotify album tracks: {e}")
|
||||
return []
|
||||
|
||||
def _match_track_to_spotify_title(self, track, spotify_tracks: List[dict]) -> Optional[str]:
|
||||
"""Match a downloaded track to a Spotify track title using similarity scoring"""
|
||||
try:
|
||||
if not spotify_tracks:
|
||||
return None
|
||||
|
||||
original_title = track.title
|
||||
print(f"🔍 Matching track: '{original_title}'")
|
||||
|
||||
# Clean the original title by removing track number prefixes
|
||||
import re
|
||||
cleaned_original = original_title
|
||||
track_num_match = re.match(r'^(\d+)\s*[\.\-_]\s*(.+)', cleaned_original.strip())
|
||||
if track_num_match:
|
||||
cleaned_original = track_num_match.group(2).strip()
|
||||
print(f" 🧹 Cleaned title (removed track number): '{cleaned_original}'")
|
||||
|
||||
best_match = None
|
||||
best_score = 0.0
|
||||
|
||||
# Try matching by track number first (most reliable)
|
||||
if hasattr(track, 'track_number') and track.track_number:
|
||||
for spotify_track in spotify_tracks:
|
||||
if spotify_track['track_number'] == track.track_number:
|
||||
print(f"✅ Matched by track number {track.track_number}: '{spotify_track['name']}'")
|
||||
return spotify_track['name']
|
||||
|
||||
# Fallback to title similarity matching using cleaned titles
|
||||
for spotify_track in spotify_tracks:
|
||||
# Normalize both titles for comparison (use cleaned original)
|
||||
normalized_original = self.matching_engine.normalize_string(cleaned_original)
|
||||
normalized_spotify = self.matching_engine.normalize_string(spotify_track['name'])
|
||||
|
||||
print(f" 📊 Comparing: '{normalized_original}' vs '{normalized_spotify}'")
|
||||
|
||||
# Calculate similarity score
|
||||
score = self.matching_engine.similarity_score(normalized_original, normalized_spotify)
|
||||
|
||||
if score > best_score:
|
||||
best_score = score
|
||||
best_match = spotify_track
|
||||
print(f" ⬆️ New best match ({score:.2f}): '{spotify_track['name']}'")
|
||||
|
||||
# Only return match if confidence is high enough
|
||||
if best_match and best_score >= 0.6: # 60% similarity threshold
|
||||
print(f"✅ Matched by title similarity ({best_score:.2f}): '{best_match['name']}'")
|
||||
return best_match['name']
|
||||
else:
|
||||
print(f"❌ No good title match found (best score: {best_score:.2f})")
|
||||
return None
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Error matching track to Spotify title: {e}")
|
||||
return None
|
||||
|
||||
def cleanup_resources(self):
|
||||
"""Clean up resources when page is destroyed"""
|
||||
try:
|
||||
|
|
|
|||
Loading…
Reference in a new issue