better
This commit is contained in:
parent
6dd6fefa5c
commit
a429aa4dbd
1 changed files with 151 additions and 6 deletions
157
ui/pages/sync.py
157
ui/pages/sync.py
|
|
@ -2702,6 +2702,11 @@ class DownloadMissingTracksModal(QDialog):
|
||||||
|
|
||||||
def start_next_track_search(self):
|
def start_next_track_search(self):
|
||||||
"""Start searching for the next track in sequence"""
|
"""Start searching for the next track in sequence"""
|
||||||
|
# Check for cancellation
|
||||||
|
if hasattr(self, 'cancel_requested') and self.cancel_requested:
|
||||||
|
print("🛑 Search cancelled by user")
|
||||||
|
return
|
||||||
|
|
||||||
if self.current_search_index >= len(self.missing_tracks):
|
if self.current_search_index >= len(self.missing_tracks):
|
||||||
# All searches complete - check if we should finish
|
# All searches complete - check if we should finish
|
||||||
if self.completed_downloads >= len(self.missing_tracks):
|
if self.completed_downloads >= len(self.missing_tracks):
|
||||||
|
|
@ -2832,8 +2837,85 @@ class DownloadMissingTracksModal(QDialog):
|
||||||
|
|
||||||
return shortened.strip()
|
return shortened.strip()
|
||||||
|
|
||||||
|
def generate_word_removal_fallbacks(self, original_query, spotify_track):
|
||||||
|
"""Generate fallback queries by removing words when original query returns 0 results"""
|
||||||
|
fallback_queries = []
|
||||||
|
|
||||||
|
# Parse the original query to understand its components
|
||||||
|
track_name = spotify_track.name.strip()
|
||||||
|
artist_name = spotify_track.artists[0] if spotify_track.artists else ""
|
||||||
|
|
||||||
|
print(f"🔄 Generating fallbacks for: '{original_query}' (track: '{track_name}', artist: '{artist_name}')")
|
||||||
|
|
||||||
|
# If the query contains the artist name, try removing words from artist
|
||||||
|
if artist_name and artist_name.lower() in original_query.lower():
|
||||||
|
# Remove common words from artist name
|
||||||
|
artist_words = artist_name.split()
|
||||||
|
if len(artist_words) > 1:
|
||||||
|
# Try removing first word if it's a common article/prefix
|
||||||
|
if artist_words[0].lower() in ['the', 'a', 'an', 'dj', 'mc', 'lil', 'big', 'young', 'old', 'saint', 'st.', 'dr.', 'mr.', 'ms.']:
|
||||||
|
reduced_artist = ' '.join(artist_words[1:])
|
||||||
|
fallback_query = f"{track_name} {reduced_artist}".strip()
|
||||||
|
if fallback_query != original_query and fallback_query not in fallback_queries:
|
||||||
|
fallback_queries.append(fallback_query)
|
||||||
|
print(f" 💡 Fallback 1: '{fallback_query}' (removed article/prefix)")
|
||||||
|
|
||||||
|
# Try removing last word (often suffixes like Jr., Sr., etc.)
|
||||||
|
if artist_words[-1].lower() in ['jr.', 'sr.', 'jr', 'sr', 'iii', 'ii', 'iv', 'v']:
|
||||||
|
reduced_artist = ' '.join(artist_words[:-1])
|
||||||
|
fallback_query = f"{track_name} {reduced_artist}".strip()
|
||||||
|
if fallback_query != original_query and fallback_query not in fallback_queries:
|
||||||
|
fallback_queries.append(fallback_query)
|
||||||
|
print(f" 💡 Fallback 2: '{fallback_query}' (removed suffix)")
|
||||||
|
|
||||||
|
# Try just first word of artist if multi-word
|
||||||
|
if len(artist_words) >= 2:
|
||||||
|
first_word = artist_words[0]
|
||||||
|
if len(first_word) > 2 and first_word.lower() not in ['the', 'a', 'an']:
|
||||||
|
fallback_query = f"{track_name} {first_word}".strip()
|
||||||
|
if fallback_query != original_query and fallback_query not in fallback_queries:
|
||||||
|
fallback_queries.append(fallback_query)
|
||||||
|
print(f" 💡 Fallback 3: '{fallback_query}' (first word only)")
|
||||||
|
|
||||||
|
# Try just last word of artist if it's likely the main name
|
||||||
|
if len(artist_words) >= 2:
|
||||||
|
last_word = artist_words[-1]
|
||||||
|
if len(last_word) > 2 and last_word.lower() not in ['jr.', 'sr.', 'jr', 'sr', 'iii', 'ii']:
|
||||||
|
fallback_query = f"{track_name} {last_word}".strip()
|
||||||
|
if fallback_query != original_query and fallback_query not in fallback_queries:
|
||||||
|
fallback_queries.append(fallback_query)
|
||||||
|
print(f" 💡 Fallback 4: '{fallback_query}' (last word only)")
|
||||||
|
|
||||||
|
# Try just track name if not already tried
|
||||||
|
if track_name.strip() != original_query and track_name.strip() not in fallback_queries:
|
||||||
|
fallback_queries.append(track_name.strip())
|
||||||
|
print(f" 💡 Fallback 5: '{track_name.strip()}' (track only)")
|
||||||
|
|
||||||
|
# Try removing special characters and punctuation from track name
|
||||||
|
import re
|
||||||
|
clean_track = re.sub(r'[^\w\s]', '', track_name).strip()
|
||||||
|
if clean_track != track_name and clean_track not in fallback_queries:
|
||||||
|
fallback_queries.append(clean_track)
|
||||||
|
print(f" 💡 Fallback 6: '{clean_track}' (cleaned track)")
|
||||||
|
|
||||||
|
# If track has multiple words, try just the first word
|
||||||
|
track_words = track_name.split()
|
||||||
|
if len(track_words) > 1:
|
||||||
|
first_track_word = track_words[0]
|
||||||
|
if len(first_track_word) > 2 and first_track_word not in fallback_queries:
|
||||||
|
fallback_queries.append(first_track_word)
|
||||||
|
print(f" 💡 Fallback 7: '{first_track_word}' (first track word)")
|
||||||
|
|
||||||
|
print(f"🔄 Generated {len(fallback_queries)} fallback queries")
|
||||||
|
return fallback_queries
|
||||||
|
|
||||||
def try_search_queries(self, queries, spotify_track, track_index, table_index, query_index):
|
def try_search_queries(self, queries, spotify_track, track_index, table_index, query_index):
|
||||||
"""Try search queries sequentially until we find good results"""
|
"""Try search queries sequentially until we find good results"""
|
||||||
|
# Check for cancellation
|
||||||
|
if hasattr(self, 'cancel_requested') and self.cancel_requested:
|
||||||
|
print("🛑 Search queries cancelled by user")
|
||||||
|
return
|
||||||
|
|
||||||
if query_index >= len(queries):
|
if query_index >= len(queries):
|
||||||
# All queries failed
|
# All queries failed
|
||||||
self.on_search_failed(spotify_track, track_index, table_index)
|
self.on_search_failed(spotify_track, track_index, table_index)
|
||||||
|
|
@ -2983,6 +3065,23 @@ class DownloadMissingTracksModal(QDialog):
|
||||||
self.start_download_with_match(best_match, spotify_track, track_index, table_index)
|
self.start_download_with_match(best_match, spotify_track, track_index, table_index)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# Check if this query returned zero results and try word removal fallback
|
||||||
|
if len(results) == 0:
|
||||||
|
print(f"⚠️ Query '{query}' returned 0 results, trying word removal fallback...")
|
||||||
|
if hasattr(self.parent_page, 'log_area'):
|
||||||
|
self.parent_page.log_area.append(f" ⚠️ 0 results for '{query}', trying word removal...")
|
||||||
|
|
||||||
|
# Generate fallback queries with word removal
|
||||||
|
fallback_queries = self.generate_word_removal_fallbacks(query, spotify_track)
|
||||||
|
if fallback_queries:
|
||||||
|
print(f"🔄 Generated {len(fallback_queries)} fallback queries")
|
||||||
|
# Insert fallback queries into the remaining query list
|
||||||
|
remaining_queries = queries[query_index + 1:]
|
||||||
|
new_queries = queries[:query_index + 1] + fallback_queries + remaining_queries
|
||||||
|
# Try the first fallback
|
||||||
|
self.try_search_queries(new_queries, spotify_track, track_index, table_index, query_index + 1)
|
||||||
|
return
|
||||||
|
|
||||||
# No good results, try next query
|
# No good results, try next query
|
||||||
print(f"⚠️ Query '{query}' had no suitable matches, trying next...")
|
print(f"⚠️ Query '{query}' had no suitable matches, trying next...")
|
||||||
if hasattr(self.parent_page, 'log_area'):
|
if hasattr(self.parent_page, 'log_area'):
|
||||||
|
|
@ -3590,6 +3689,11 @@ class DownloadMissingTracksModal(QDialog):
|
||||||
|
|
||||||
def advance_to_next_track(self):
|
def advance_to_next_track(self):
|
||||||
"""Move to searching the next track"""
|
"""Move to searching the next track"""
|
||||||
|
# Check for cancellation
|
||||||
|
if hasattr(self, 'cancel_requested') and self.cancel_requested:
|
||||||
|
print("🛑 Track advancement cancelled by user")
|
||||||
|
return
|
||||||
|
|
||||||
self.current_search_index += 1
|
self.current_search_index += 1
|
||||||
self.start_next_track_search()
|
self.start_next_track_search()
|
||||||
|
|
||||||
|
|
@ -4384,17 +4488,49 @@ class DownloadMissingTracksModal(QDialog):
|
||||||
|
|
||||||
def cancel_operations(self):
|
def cancel_operations(self):
|
||||||
"""Cancel any ongoing operations"""
|
"""Cancel any ongoing operations"""
|
||||||
# Cancel workers
|
print("🛑 Cancelling all operations...")
|
||||||
for worker in self.active_workers:
|
|
||||||
if hasattr(worker, 'cancel'):
|
# Set cancellation flag to stop ongoing processes
|
||||||
worker.cancel()
|
self.cancel_requested = True
|
||||||
|
|
||||||
|
# Cancel all active workers
|
||||||
|
if hasattr(self, 'active_workers'):
|
||||||
|
for worker in self.active_workers:
|
||||||
|
if hasattr(worker, 'cancel'):
|
||||||
|
worker.cancel()
|
||||||
|
# Also try to set stop flag for our custom workers
|
||||||
|
if hasattr(worker, '_stop_requested'):
|
||||||
|
worker._stop_requested = True
|
||||||
|
|
||||||
# Stop timers
|
# Stop all download monitoring timers
|
||||||
|
if hasattr(self, 'download_timers'):
|
||||||
|
for timer in self.download_timers:
|
||||||
|
if timer.isActive():
|
||||||
|
timer.stop()
|
||||||
|
self.download_timers.clear()
|
||||||
|
|
||||||
|
# Stop analysis/download timer
|
||||||
if hasattr(self, 'download_timer'):
|
if hasattr(self, 'download_timer'):
|
||||||
self.download_timer.stop()
|
self.download_timer.stop()
|
||||||
|
|
||||||
|
# Stop status update timer
|
||||||
if hasattr(self, 'status_update_timer'):
|
if hasattr(self, 'status_update_timer'):
|
||||||
self.status_update_timer.stop()
|
self.status_update_timer.stop()
|
||||||
|
|
||||||
|
# Cancel any pending downloads via downloads.py infrastructure
|
||||||
|
if hasattr(self, 'track_download_items'):
|
||||||
|
for download_item, (track_index, table_index) in self.track_download_items.items():
|
||||||
|
try:
|
||||||
|
if hasattr(download_item, 'download_id') and download_item.download_id:
|
||||||
|
# Try to cancel download
|
||||||
|
print(f"🛑 Attempting to cancel download: {download_item.download_id}")
|
||||||
|
# Note: Actual cancellation would need to be implemented in downloads.py
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Error cancelling download: {e}")
|
||||||
|
|
||||||
|
# Update main console
|
||||||
|
if hasattr(self.parent_page, 'log_area'):
|
||||||
|
self.parent_page.log_area.append("🛑 Download operations cancelled by user")
|
||||||
|
|
||||||
# Reset button states - hide Cancel, show Begin Search
|
# Reset button states - hide Cancel, show Begin Search
|
||||||
self.cancel_btn.hide()
|
self.cancel_btn.hide()
|
||||||
|
|
@ -4409,6 +4545,15 @@ class DownloadMissingTracksModal(QDialog):
|
||||||
# Reset state flags
|
# Reset state flags
|
||||||
self.analysis_complete = False
|
self.analysis_complete = False
|
||||||
self.download_in_progress = False
|
self.download_in_progress = False
|
||||||
|
self.cancel_requested = False # Reset for next time
|
||||||
|
|
||||||
|
# Reset search state
|
||||||
|
if hasattr(self, 'current_search_index'):
|
||||||
|
self.current_search_index = 0
|
||||||
|
if hasattr(self, 'track_search_results'):
|
||||||
|
self.track_search_results.clear()
|
||||||
|
if hasattr(self, 'track_candidate_index'):
|
||||||
|
self.track_candidate_index.clear()
|
||||||
|
|
||||||
# Reset playlist status indicator
|
# Reset playlist status indicator
|
||||||
playlist_item = self.find_playlist_item()
|
playlist_item = self.find_playlist_item()
|
||||||
|
|
@ -4419,7 +4564,7 @@ class DownloadMissingTracksModal(QDialog):
|
||||||
if hasattr(self.parent_page, 'enable_refresh_button'):
|
if hasattr(self.parent_page, 'enable_refresh_button'):
|
||||||
self.parent_page.enable_refresh_button()
|
self.parent_page.enable_refresh_button()
|
||||||
|
|
||||||
print("🛑 Operations cancelled")
|
print("🛑 All operations cancelled successfully")
|
||||||
|
|
||||||
def closeEvent(self, event):
|
def closeEvent(self, event):
|
||||||
"""Handle modal close event"""
|
"""Handle modal close event"""
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue