Cache per-track results in sync history + fix config_manager import
Sync operations now store per-track data (name, artist, match status, confidence, download status) in a new track_results column on sync_history. Also fixed missing config_manager import in add_to_wishlist that crashed the duplicate tracks toggle.
This commit is contained in:
parent
cfe2ab7dec
commit
ad262822a4
2 changed files with 92 additions and 4 deletions
|
|
@ -518,12 +518,23 @@ class MusicDatabase:
|
|||
is_album_download INTEGER DEFAULT 0,
|
||||
playlist_folder_mode INTEGER DEFAULT 0,
|
||||
started_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
completed_at TIMESTAMP
|
||||
completed_at TIMESTAMP,
|
||||
track_results TEXT
|
||||
)
|
||||
""")
|
||||
cursor.execute("CREATE INDEX IF NOT EXISTS idx_sh_started_at ON sync_history (started_at DESC)")
|
||||
cursor.execute("CREATE INDEX IF NOT EXISTS idx_sh_source ON sync_history (source)")
|
||||
|
||||
# Migration: add track_results column to existing sync_history tables
|
||||
try:
|
||||
cursor.execute("SELECT track_results FROM sync_history LIMIT 1")
|
||||
except Exception:
|
||||
try:
|
||||
cursor.execute("ALTER TABLE sync_history ADD COLUMN track_results TEXT")
|
||||
logger.info("Added track_results column to sync_history table")
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
conn.commit()
|
||||
logger.info("Database initialized successfully")
|
||||
|
||||
|
|
@ -6059,6 +6070,7 @@ class MusicDatabase:
|
|||
|
||||
# Check for duplicates by track name + artist (not just Spotify ID)
|
||||
# When allow_duplicates is True (default), same song from different albums can coexist
|
||||
from config.settings import config_manager
|
||||
allow_duplicates = config_manager.get('wishlist.allow_duplicate_tracks', True)
|
||||
|
||||
if not allow_duplicates:
|
||||
|
|
@ -9012,6 +9024,20 @@ class MusicDatabase:
|
|||
logger.debug(f"Error updating sync history completion: {e}")
|
||||
return False
|
||||
|
||||
def update_sync_history_track_results(self, batch_id, track_results_json):
|
||||
"""Store per-track match/download results on a sync_history entry."""
|
||||
try:
|
||||
conn = self._get_connection()
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("""
|
||||
UPDATE sync_history SET track_results = ? WHERE batch_id = ?
|
||||
""", (track_results_json, batch_id))
|
||||
conn.commit()
|
||||
return cursor.rowcount > 0
|
||||
except Exception as e:
|
||||
logger.debug(f"Error updating sync history track results: {e}")
|
||||
return False
|
||||
|
||||
def refresh_sync_history_entry(self, entry_id, tracks_found=0, tracks_downloaded=0, tracks_failed=0):
|
||||
"""Update an existing sync_history entry with new stats and reset timestamps to move it to the top."""
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -24320,6 +24320,27 @@ def _run_full_missing_tracks_process(batch_id, playlist_id, tracks_json):
|
|||
try:
|
||||
db_sh = MusicDatabase()
|
||||
db_sh.update_sync_history_completion(batch_id, tracks_found=tracks_found, tracks_downloaded=0, tracks_failed=0)
|
||||
# Save per-track results (all found, no downloads)
|
||||
track_results = []
|
||||
for res in analysis_results:
|
||||
td = res.get('track', {})
|
||||
artists = td.get('artists', [])
|
||||
first_artist = (artists[0].get('name', artists[0]) if isinstance(artists[0], dict) else str(artists[0])) if artists else ''
|
||||
alb = td.get('album', '')
|
||||
track_results.append({
|
||||
'index': res.get('track_index', 0),
|
||||
'name': td.get('name', ''),
|
||||
'artist': first_artist,
|
||||
'album': alb.get('name', '') if isinstance(alb, dict) else str(alb or ''),
|
||||
'duration_ms': td.get('duration_ms', 0),
|
||||
'source_track_id': td.get('id', ''),
|
||||
'status': 'found' if res.get('found') else 'not_found',
|
||||
'confidence': round(res.get('confidence', 0.0), 3),
|
||||
'matched_track': None,
|
||||
'download_status': None,
|
||||
})
|
||||
if track_results:
|
||||
db_sh.update_sync_history_track_results(batch_id, json.dumps(track_results))
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
|
@ -27198,6 +27219,7 @@ def get_sync_history_entry(entry_id):
|
|||
entry['tracks'] = json.loads(entry['tracks_json']) if entry.get('tracks_json') else []
|
||||
entry['artist_context'] = json.loads(entry['artist_context']) if entry.get('artist_context') else None
|
||||
entry['album_context'] = json.loads(entry['album_context']) if entry.get('album_context') else None
|
||||
entry['track_results'] = json.loads(entry['track_results']) if entry.get('track_results') else None
|
||||
entry.pop('tracks_json', None)
|
||||
|
||||
return jsonify({"success": True, "entry": entry})
|
||||
|
|
@ -27317,7 +27339,7 @@ def _record_sync_history_start(batch_id, playlist_id, playlist_name, tracks,
|
|||
logger.warning(f"Failed to record sync history start: {e}")
|
||||
|
||||
def _record_sync_history_completion(batch_id, batch):
|
||||
"""Update sync history with completion stats.
|
||||
"""Update sync history with completion stats and per-track results.
|
||||
NOTE: Called from within tasks_lock context — do NOT acquire tasks_lock here."""
|
||||
try:
|
||||
analysis_results = batch.get('analysis_results', [])
|
||||
|
|
@ -27325,13 +27347,53 @@ def _record_sync_history_completion(batch_id, batch):
|
|||
queue = batch.get('queue', [])
|
||||
completed_count = 0
|
||||
failed_count = len(batch.get('permanently_failed_tracks', []))
|
||||
# Already inside tasks_lock — safe to read download_tasks directly
|
||||
|
||||
# Build download status map: track_index → status
|
||||
download_status_map = {}
|
||||
for task_id in queue:
|
||||
if task_id in download_tasks and download_tasks[task_id].get('status') == 'completed':
|
||||
task = download_tasks.get(task_id, {})
|
||||
ti = task.get('track_index')
|
||||
if ti is not None:
|
||||
download_status_map[ti] = task.get('status', 'unknown')
|
||||
if task.get('status') == 'completed':
|
||||
completed_count += 1
|
||||
|
||||
# Build per-track results from analysis
|
||||
track_results = []
|
||||
for res in analysis_results:
|
||||
track_data = res.get('track', {})
|
||||
artists = track_data.get('artists', [])
|
||||
if artists:
|
||||
first = artists[0]
|
||||
artist_name = first.get('name', first) if isinstance(first, dict) else str(first)
|
||||
else:
|
||||
artist_name = ''
|
||||
|
||||
album = track_data.get('album', '')
|
||||
album_name = album.get('name', '') if isinstance(album, dict) else str(album or '')
|
||||
|
||||
idx = res.get('track_index', 0)
|
||||
entry = {
|
||||
'index': idx,
|
||||
'name': track_data.get('name', ''),
|
||||
'artist': artist_name,
|
||||
'album': album_name,
|
||||
'duration_ms': track_data.get('duration_ms', 0),
|
||||
'source_track_id': track_data.get('id', ''),
|
||||
'status': 'found' if res.get('found') else 'not_found',
|
||||
'confidence': round(res.get('confidence', 0.0), 3),
|
||||
'matched_track': None,
|
||||
'download_status': download_status_map.get(idx),
|
||||
}
|
||||
track_results.append(entry)
|
||||
|
||||
db = MusicDatabase()
|
||||
db.update_sync_history_completion(batch_id, tracks_found, completed_count, failed_count)
|
||||
|
||||
# Save per-track results
|
||||
if track_results:
|
||||
db.update_sync_history_track_results(batch_id, json.dumps(track_results))
|
||||
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to record sync history completion: {e}")
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue