From aac75d6a3b119b3cc54370e5c9d67011905437e8 Mon Sep 17 00:00:00 2001 From: Broque Thomas <26755000+Nezreka@users.noreply.github.com> Date: Wed, 15 Apr 2026 12:09:41 -0700 Subject: [PATCH] Fix Explore tab checkmark badge not persisting after refresh Explored status was stored only in frontend memory; on reload the badge disappeared because the API never returned it. Added explored_at column to mirrored_playlists (auto-migrated), written when build-tree completes, and read back via SELECT * so the badge survives page refreshes. --- database/music_database.py | 29 +++++++++++++++++++++++++++++ web_server.py | 1 + webui/static/script.js | 6 +++--- 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/database/music_database.py b/database/music_database.py index 4c016846..3cb72c2e 100644 --- a/database/music_database.py +++ b/database/music_database.py @@ -517,6 +517,9 @@ class MusicDatabase: """) cursor.execute("CREATE INDEX IF NOT EXISTS idx_arh_automation_id ON automation_run_history(automation_id)") + # Add explored_at to mirrored_playlists (migration) + self._add_mirrored_playlist_explored_column(cursor) + # Add notification columns to automations (migration) self._add_automation_notify_columns(cursor) self._add_automation_system_column(cursor) @@ -684,6 +687,17 @@ class MusicDatabase: logger.error(f"Error initializing database: {e}") raise + def _add_mirrored_playlist_explored_column(self, cursor): + """Add explored_at column to mirrored_playlists to persist explore badge.""" + try: + cursor.execute("PRAGMA table_info(mirrored_playlists)") + cols = [c[1] for c in cursor.fetchall()] + if 'explored_at' not in cols: + cursor.execute("ALTER TABLE mirrored_playlists ADD COLUMN explored_at TIMESTAMP DEFAULT NULL") + logger.info("Added explored_at column to mirrored_playlists table") + except Exception as e: + logger.error(f"Error adding explored_at column to mirrored_playlists: {e}") + def _add_automation_notify_columns(self, cursor): """Add notification and result columns to automations table.""" try: @@ -10490,6 +10504,21 @@ class MusicDatabase: logger.error(f"Error getting mirrored playlists: {e}") return [] + def mark_mirrored_playlist_explored(self, playlist_id: int) -> bool: + """Set explored_at to now for a mirrored playlist.""" + try: + with self._get_connection() as conn: + cursor = conn.cursor() + cursor.execute( + "UPDATE mirrored_playlists SET explored_at = CURRENT_TIMESTAMP WHERE id = ?", + (playlist_id,) + ) + conn.commit() + return cursor.rowcount > 0 + except Exception as e: + logger.error(f"Error marking playlist {playlist_id} as explored: {e}") + return False + def get_mirrored_playlist(self, playlist_id: int) -> Optional[Dict]: """Return a single mirrored playlist by id.""" try: diff --git a/web_server.py b/web_server.py index 94e5c8c6..e4532e0d 100644 --- a/web_server.py +++ b/web_server.py @@ -49288,6 +49288,7 @@ def playlist_explorer_build_tree(): if idx < len(artist_groups) - 1: time.sleep(0.2) + get_database().mark_mirrored_playlist_explored(playlist_id) yield json.dumps({"type": "complete", "total_artists": len(artist_groups), "total_albums": total_albums}) + '\n' return Response(generate(), mimetype='application/x-ndjson', headers={ diff --git a/webui/static/script.js b/webui/static/script.js index 34a033d9..0f820fe0 100644 --- a/webui/static/script.js +++ b/webui/static/script.js @@ -71743,7 +71743,7 @@ function explorerRenderPickerCards(source) { const isReady = pct >= 50; const isActive = _explorer.playlistId === p.id; const isFullyDiscovered = pct === 100; - const wasExplored = p.explored || false; + const wasExplored = !!(p.explored_at || p.explored); const wishlisted = p.wishlisted_count || 0; const inLibrary = p.in_library_count || 0; @@ -71967,10 +71967,10 @@ async function explorerBuildTree() { if (progress) progress.style.display = 'none'; _explorerUpdateCount(); - // Mark playlist as explored (persists in session for badge display) + // Mark playlist as explored (server persists via explored_at; update local copy too) const exploredPl = _explorer._playlists.find(p => p.id === playlistId); if (exploredPl) { - exploredPl.explored = true; + exploredPl.explored_at = new Date().toISOString(); // Update card badge without full re-render const card = document.querySelector(`.explorer-picker-card[data-id="${playlistId}"]`); if (card) {