Track server push status, expand push to all playlist types, rename to _push_playlist_to_server
This commit is contained in:
parent
5415d0fe3c
commit
ed013d79b9
2 changed files with 74 additions and 23 deletions
|
|
@ -636,7 +636,8 @@ class MusicDatabase:
|
||||||
playlist_folder_mode INTEGER DEFAULT 0,
|
playlist_folder_mode INTEGER DEFAULT 0,
|
||||||
started_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
started_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
completed_at TIMESTAMP,
|
completed_at TIMESTAMP,
|
||||||
track_results TEXT
|
track_results TEXT,
|
||||||
|
server_push_status 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_started_at ON sync_history (started_at DESC)")
|
||||||
|
|
@ -662,6 +663,16 @@ class MusicDatabase:
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# Migration: add server_push_status column to sync_history
|
||||||
|
try:
|
||||||
|
cursor.execute("SELECT server_push_status FROM sync_history LIMIT 1")
|
||||||
|
except Exception:
|
||||||
|
try:
|
||||||
|
cursor.execute("ALTER TABLE sync_history ADD COLUMN server_push_status TEXT")
|
||||||
|
logger.info("Added server_push_status column to sync_history table")
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
# Migration: add track_artist column for per-track artist on compilations/DJ mixes
|
# Migration: add track_artist column for per-track artist on compilations/DJ mixes
|
||||||
try:
|
try:
|
||||||
cursor.execute("SELECT track_artist FROM tracks LIMIT 1")
|
cursor.execute("SELECT track_artist FROM tracks LIMIT 1")
|
||||||
|
|
@ -10497,6 +10508,20 @@ class MusicDatabase:
|
||||||
logger.debug(f"Error updating sync history track results: {e}")
|
logger.debug(f"Error updating sync history track results: {e}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def update_sync_history_push_status(self, batch_id, status):
|
||||||
|
"""Update the server push status for a sync_history entry."""
|
||||||
|
try:
|
||||||
|
conn = self._get_connection()
|
||||||
|
cursor = conn.cursor()
|
||||||
|
cursor.execute("""
|
||||||
|
UPDATE sync_history SET server_push_status = ? WHERE batch_id = ?
|
||||||
|
""", (status, batch_id))
|
||||||
|
conn.commit()
|
||||||
|
return cursor.rowcount > 0
|
||||||
|
except Exception as e:
|
||||||
|
logger.debug(f"Error updating sync history push status: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
def refresh_sync_history_entry(self, entry_id, tracks_found=0, tracks_downloaded=0, tracks_failed=0):
|
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."""
|
"""Update an existing sync_history entry with new stats and reset timestamps to move it to the top."""
|
||||||
try:
|
try:
|
||||||
|
|
@ -10611,7 +10636,8 @@ class MusicDatabase:
|
||||||
cursor.execute("""
|
cursor.execute("""
|
||||||
SELECT id, batch_id, playlist_name, source, sync_type, source_page,
|
SELECT id, batch_id, playlist_name, source, sync_type, source_page,
|
||||||
total_tracks, tracks_found, tracks_downloaded, tracks_failed,
|
total_tracks, tracks_found, tracks_downloaded, tracks_failed,
|
||||||
thumb_url, is_album_download, started_at, completed_at
|
thumb_url, is_album_download, started_at, completed_at,
|
||||||
|
server_push_status
|
||||||
FROM sync_history
|
FROM sync_history
|
||||||
WHERE completed_at IS NOT NULL
|
WHERE completed_at IS NOT NULL
|
||||||
AND started_at >= datetime('now', ? || ' days')
|
AND started_at >= datetime('now', ? || ' days')
|
||||||
|
|
|
||||||
|
|
@ -28652,11 +28652,17 @@ def _on_download_completed(batch_id, task_id, success=True):
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Push discover playlists to media server after downloads complete
|
# Push playlists to media server after downloads complete
|
||||||
playlist_id = batch.get('playlist_id')
|
playlist_id = batch.get('playlist_id')
|
||||||
if playlist_id and playlist_id.startswith('discover_'):
|
_push_prefixes = (
|
||||||
|
'discover_', 'auto_mirror_', 'youtube_mirrored_',
|
||||||
|
'youtube_', 'tidal_', 'deezer_', 'spotify_public_',
|
||||||
|
'listenbrainz_', 'beatport_',
|
||||||
|
)
|
||||||
|
if playlist_id and playlist_id.startswith(_push_prefixes):
|
||||||
|
database.update_sync_history_push_status(batch_id, 'pending')
|
||||||
threading.Thread(
|
threading.Thread(
|
||||||
target=_push_discover_playlist_to_server,
|
target=_push_playlist_to_server,
|
||||||
args=(batch_id, batch),
|
args=(batch_id, batch),
|
||||||
daemon=True
|
daemon=True
|
||||||
).start()
|
).start()
|
||||||
|
|
@ -31912,11 +31918,17 @@ def _check_batch_completion_v2(batch_id):
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Push discover playlists to media server after downloads complete
|
# Push playlists to media server after downloads complete
|
||||||
playlist_id = batch.get('playlist_id')
|
playlist_id = batch.get('playlist_id')
|
||||||
if playlist_id and playlist_id.startswith('discover_'):
|
_push_prefixes = (
|
||||||
|
'discover_', 'auto_mirror_', 'youtube_mirrored_',
|
||||||
|
'youtube_', 'tidal_', 'deezer_', 'spotify_public_',
|
||||||
|
'listenbrainz_', 'beatport_',
|
||||||
|
)
|
||||||
|
if playlist_id and playlist_id.startswith(_push_prefixes):
|
||||||
|
database.update_sync_history_push_status(batch_id, 'pending')
|
||||||
threading.Thread(
|
threading.Thread(
|
||||||
target=_push_discover_playlist_to_server,
|
target=_push_playlist_to_server,
|
||||||
args=(batch_id, batch),
|
args=(batch_id, batch),
|
||||||
daemon=True
|
daemon=True
|
||||||
).start()
|
).start()
|
||||||
|
|
@ -32464,18 +32476,23 @@ def _record_sync_history_completion(batch_id, batch):
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|
||||||
|
|
||||||
def _push_discover_playlist_to_server(batch_id, batch):
|
def _push_playlist_to_server(batch_id, batch):
|
||||||
"""After a discover batch completes, push the playlist to the media server.
|
"""After a batch completes, push the playlist to the media server.
|
||||||
Runs in a background thread. Triggers a scan, waits, then searches for tracks and creates/updates the playlist."""
|
Runs in a background thread. Triggers a scan, waits, then searches for tracks and creates/updates the playlist.
|
||||||
|
Supports discover, mirrored, and auto-mirror playlists."""
|
||||||
|
database = get_database()
|
||||||
try:
|
try:
|
||||||
playlist_id = batch.get('playlist_id', '')
|
playlist_id = batch.get('playlist_id', '')
|
||||||
playlist_name = batch.get('playlist_name', '')
|
playlist_name = batch.get('playlist_name', '')
|
||||||
if not playlist_name:
|
if not playlist_name:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
database.update_sync_history_push_status(batch_id, 'pushing')
|
||||||
|
|
||||||
analysis_results = batch.get('analysis_results', [])
|
analysis_results = batch.get('analysis_results', [])
|
||||||
if not analysis_results:
|
if not analysis_results:
|
||||||
logger.info(f"[DiscoverPush] No analysis results for {playlist_name} - skipping server push")
|
logger.info(f"[PlaylistPush] No analysis results for {playlist_name} - skipping server push")
|
||||||
|
database.update_sync_history_push_status(batch_id, 'skipped')
|
||||||
return
|
return
|
||||||
|
|
||||||
# Build list of tracks that should be in the playlist (found in library OR successfully downloaded)
|
# Build list of tracks that should be in the playlist (found in library OR successfully downloaded)
|
||||||
|
|
@ -32508,16 +32525,17 @@ def _push_discover_playlist_to_server(batch_id, batch):
|
||||||
})
|
})
|
||||||
|
|
||||||
if not tracks_to_find:
|
if not tracks_to_find:
|
||||||
logger.info(f"[DiscoverPush] No tracks to push for {playlist_name}")
|
logger.info(f"[PlaylistPush] No tracks to push for {playlist_name}")
|
||||||
|
database.update_sync_history_push_status(batch_id, 'skipped')
|
||||||
return
|
return
|
||||||
|
|
||||||
logger.info(f"[DiscoverPush] {playlist_name}: {len(tracks_to_find)} tracks to push to server, triggering scan first")
|
logger.info(f"[PlaylistPush] {playlist_name}: {len(tracks_to_find)} tracks to push to server, triggering scan first")
|
||||||
|
|
||||||
# Trigger a library scan so newly downloaded tracks are indexed
|
# Trigger a library scan so newly downloaded tracks are indexed
|
||||||
if navidrome_client and navidrome_client.is_connected():
|
if navidrome_client and navidrome_client.is_connected():
|
||||||
navidrome_client.trigger_library_scan()
|
navidrome_client.trigger_library_scan()
|
||||||
elif hasattr(web_scan_manager, 'request_scan'):
|
elif hasattr(web_scan_manager, 'request_scan'):
|
||||||
web_scan_manager.request_scan(f"Discover playlist push: {playlist_name}")
|
web_scan_manager.request_scan(f"Playlist push: {playlist_name}")
|
||||||
|
|
||||||
# Wait for scan to finish (poll every 5s, up to 90s)
|
# Wait for scan to finish (poll every 5s, up to 90s)
|
||||||
if navidrome_client and navidrome_client.is_connected():
|
if navidrome_client and navidrome_client.is_connected():
|
||||||
|
|
@ -32525,7 +32543,7 @@ def _push_discover_playlist_to_server(batch_id, batch):
|
||||||
time.sleep(5)
|
time.sleep(5)
|
||||||
if not navidrome_client.is_library_scanning():
|
if not navidrome_client.is_library_scanning():
|
||||||
break
|
break
|
||||||
logger.info(f"[DiscoverPush] Scan complete, searching for tracks")
|
logger.info(f"[PlaylistPush] Scan complete, searching for tracks")
|
||||||
else:
|
else:
|
||||||
time.sleep(30)
|
time.sleep(30)
|
||||||
|
|
||||||
|
|
@ -32540,27 +32558,34 @@ def _push_discover_playlist_to_server(batch_id, batch):
|
||||||
nav_track = getattr(best, '_original_navidrome_track', None)
|
nav_track = getattr(best, '_original_navidrome_track', None)
|
||||||
if nav_track:
|
if nav_track:
|
||||||
matched_server_tracks.append(nav_track)
|
matched_server_tracks.append(nav_track)
|
||||||
logger.debug(f"[DiscoverPush] Matched: '{t['title']}' by '{t['artist']}' → {best.id}")
|
logger.debug(f"[PlaylistPush] Matched: '{t['title']}' by '{t['artist']}' → {best.id}")
|
||||||
else:
|
else:
|
||||||
matched_server_tracks.append(best)
|
matched_server_tracks.append(best)
|
||||||
else:
|
else:
|
||||||
logger.info(f"[DiscoverPush] No match for: '{t['title']}' by '{t['artist']}'")
|
logger.info(f"[PlaylistPush] No match for: '{t['title']}' by '{t['artist']}'")
|
||||||
|
|
||||||
if not matched_server_tracks:
|
if not matched_server_tracks:
|
||||||
logger.warning(f"[DiscoverPush] No tracks matched on server for {playlist_name}")
|
logger.warning(f"[PlaylistPush] No tracks matched on server for {playlist_name}")
|
||||||
|
database.update_sync_history_push_status(batch_id, 'failed')
|
||||||
return
|
return
|
||||||
|
|
||||||
logger.info(f"[DiscoverPush] Pushing {len(matched_server_tracks)}/{len(tracks_to_find)} tracks to '{playlist_name}' on server")
|
logger.info(f"[PlaylistPush] Pushing {len(matched_server_tracks)}/{len(tracks_to_find)} tracks to '{playlist_name}' on server")
|
||||||
success = navidrome_client.update_playlist(playlist_name, matched_server_tracks)
|
success = navidrome_client.update_playlist(playlist_name, matched_server_tracks)
|
||||||
if success:
|
if success:
|
||||||
logger.info(f"[DiscoverPush] Successfully pushed '{playlist_name}' to server with {len(matched_server_tracks)} tracks")
|
logger.info(f"[PlaylistPush] Successfully pushed '{playlist_name}' to server with {len(matched_server_tracks)} tracks")
|
||||||
|
database.update_sync_history_push_status(batch_id, 'success')
|
||||||
else:
|
else:
|
||||||
logger.warning(f"[DiscoverPush] Failed to push '{playlist_name}' to server")
|
logger.warning(f"[PlaylistPush] Failed to push '{playlist_name}' to server")
|
||||||
|
database.update_sync_history_push_status(batch_id, 'failed')
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"[DiscoverPush] Error pushing playlist to server: {e}")
|
logger.error(f"[PlaylistPush] Error pushing playlist to server: {e}")
|
||||||
import traceback
|
import traceback
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
try:
|
||||||
|
database.update_sync_history_push_status(batch_id, 'failed')
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
# ===============================
|
# ===============================
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue