From f8fbcb507c9a5348be9a0966fa099261923a2bb5 Mon Sep 17 00:00:00 2001 From: Broque Thomas <26755000+Nezreka@users.noreply.github.com> Date: Mon, 6 Apr 2026 16:18:58 -0700 Subject: [PATCH] Add source provenance and AcoustID result to download history Track original source filename, track ID, and AcoustID verification result for every download. Helps debug wrong-file downloads from streaming sources like Tidal. Each column migrated independently for crash safety. Frontend shows source detail line and color-coded AcoustID badge per entry. Button renamed to "Download History". --- database/music_database.py | 15 +++++++++++---- web_server.py | 34 +++++++++++++++++++++++++++++++++- webui/index.html | 2 +- webui/static/script.js | 23 ++++++++++++++++++++++- webui/static/style.css | 10 ++++++++++ 5 files changed, 77 insertions(+), 7 deletions(-) diff --git a/database/music_database.py b/database/music_database.py index ac622c68..930ea223 100644 --- a/database/music_database.py +++ b/database/music_database.py @@ -509,6 +509,10 @@ class MusicDatabase: if 'download_source' not in lh_cols: cursor.execute("ALTER TABLE library_history ADD COLUMN download_source TEXT") logger.info("Added download_source column to library_history") + for _col in ['source_track_id', 'source_track_title', 'source_filename', 'acoustid_result']: + if _col not in lh_cols: + cursor.execute(f"ALTER TABLE library_history ADD COLUMN {_col} TEXT") + logger.info(f"Added {_col} column to library_history") # Sync history table β tracks the last 100 sync operations with cached context for re-trigger cursor.execute(""" @@ -9617,16 +9621,19 @@ class MusicDatabase: def add_library_history_entry(self, event_type, title, artist_name=None, album_name=None, quality=None, server_source=None, file_path=None, thumb_url=None, - download_source=None): + download_source=None, source_track_id=None, source_track_title=None, + source_filename=None, acoustid_result=None): """Record a download or import event to the library history table.""" try: conn = self._get_connection() cursor = conn.cursor() cursor.execute(""" INSERT INTO library_history (event_type, title, artist_name, album_name, - quality, server_source, file_path, thumb_url, download_source) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) - """, (event_type, title, artist_name, album_name, quality, server_source, file_path, thumb_url, download_source)) + quality, server_source, file_path, thumb_url, download_source, + source_track_id, source_track_title, source_filename, acoustid_result) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + """, (event_type, title, artist_name, album_name, quality, server_source, file_path, thumb_url, + download_source, source_track_id, source_track_title, source_filename, acoustid_result)) conn.commit() return True except Exception as e: diff --git a/web_server.py b/web_server.py index 5f9e8adf..f780e6d5 100644 --- a/web_server.py +++ b/web_server.py @@ -1910,6 +1910,19 @@ def _record_library_history_download(context): if isinstance(album_info, dict): thumb_url = album_info.get('album_image_url', '') + # Source provenance β what file/track was actually downloaded + source_filename = search_result.get('filename', '') + # Track ID: try search result first, then track_info (Spotify ID used for streaming lookups) + source_track_id = (search_result.get('track_id', '') + or search_result.get('id', '') + or ti.get('id', '')) + # Source track title: only save if it differs from expected title (otherwise it's just noise) + _src_title = search_result.get('title', '') or search_result.get('name', '') + source_track_title = _src_title if _src_title and _src_title != title else '' + + # AcoustID verification result + acoustid_result = context.get('_acoustid_result', '') + db = get_database() db.add_library_history_entry( event_type='download', @@ -1919,7 +1932,11 @@ def _record_library_history_download(context): quality=quality, file_path=file_path, thumb_url=thumb_url, - download_source=download_source + download_source=download_source, + source_track_id=source_track_id, + source_track_title=source_track_title, + source_filename=source_filename, + acoustid_result=acoustid_result ) except Exception: pass # Non-critical, never block download flow @@ -19588,6 +19605,7 @@ def _post_process_matched_download(context_key, context, file_path): context ) print(f"π AcoustID verification result: {verification_result.value} - {verification_msg}") + context['_acoustid_result'] = verification_result.value if verification_result == VerificationResult.FAIL: # Move to quarantine instead of Transfer @@ -19629,11 +19647,14 @@ def _post_process_matched_download(context_key, context, file_path): return # NEVER continue processing a known-wrong file else: print(f"β οΈ AcoustID verification skipped: missing track/artist info") + context['_acoustid_result'] = 'skip' else: print(f"βΉοΈ AcoustID verification not available: {available_reason}") + context['_acoustid_result'] = 'disabled' except Exception as verify_error: # Any verification error should NOT block the download - fail open print(f"β οΈ AcoustID verification error (continuing normally): {verify_error}") + context['_acoustid_result'] = 'error' # --- END ACOUSTID VERIFICATION --- # --- SIMPLE DOWNLOAD HANDLING --- @@ -20887,6 +20908,17 @@ def get_version_info(): "title": "What's New in SoulSync", "subtitle": f"Version {SOULSYNC_VERSION} β Latest Changes", "sections": [ + { + "title": "π Download History β Source Provenance", + "description": "Download history now tracks the original source file info for every download", + "features": [ + "β’ Source filename, track ID, and original track title saved with each download", + "β’ AcoustID verification result (Verified/Failed/Skipped/Off) shown as a badge per entry", + "β’ Source details displayed in monospace under each history entry for easy debugging", + "β’ Settings Connections tab redesigned with collapsible accordion services and brand-colored dots" + ], + "usage_note": "Click 'Download History' on the Dashboard to see source provenance for new downloads." + }, { "title": "πΊοΈ Artist Map β Visualize Your Music Universe", "description": "Three interactive canvas-based visualization modes on the Discover page", diff --git a/webui/index.html b/webui/index.html index a41a5752..f7bea449 100644 --- a/webui/index.html +++ b/webui/index.html @@ -1094,7 +1094,7 @@