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.
This commit is contained in:
parent
211c7b451a
commit
aac75d6a3b
3 changed files with 33 additions and 3 deletions
|
|
@ -517,6 +517,9 @@ class MusicDatabase:
|
||||||
""")
|
""")
|
||||||
cursor.execute("CREATE INDEX IF NOT EXISTS idx_arh_automation_id ON automation_run_history(automation_id)")
|
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)
|
# Add notification columns to automations (migration)
|
||||||
self._add_automation_notify_columns(cursor)
|
self._add_automation_notify_columns(cursor)
|
||||||
self._add_automation_system_column(cursor)
|
self._add_automation_system_column(cursor)
|
||||||
|
|
@ -684,6 +687,17 @@ class MusicDatabase:
|
||||||
logger.error(f"Error initializing database: {e}")
|
logger.error(f"Error initializing database: {e}")
|
||||||
raise
|
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):
|
def _add_automation_notify_columns(self, cursor):
|
||||||
"""Add notification and result columns to automations table."""
|
"""Add notification and result columns to automations table."""
|
||||||
try:
|
try:
|
||||||
|
|
@ -10490,6 +10504,21 @@ class MusicDatabase:
|
||||||
logger.error(f"Error getting mirrored playlists: {e}")
|
logger.error(f"Error getting mirrored playlists: {e}")
|
||||||
return []
|
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]:
|
def get_mirrored_playlist(self, playlist_id: int) -> Optional[Dict]:
|
||||||
"""Return a single mirrored playlist by id."""
|
"""Return a single mirrored playlist by id."""
|
||||||
try:
|
try:
|
||||||
|
|
|
||||||
|
|
@ -49288,6 +49288,7 @@ def playlist_explorer_build_tree():
|
||||||
if idx < len(artist_groups) - 1:
|
if idx < len(artist_groups) - 1:
|
||||||
time.sleep(0.2)
|
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'
|
yield json.dumps({"type": "complete", "total_artists": len(artist_groups), "total_albums": total_albums}) + '\n'
|
||||||
|
|
||||||
return Response(generate(), mimetype='application/x-ndjson', headers={
|
return Response(generate(), mimetype='application/x-ndjson', headers={
|
||||||
|
|
|
||||||
|
|
@ -71743,7 +71743,7 @@ function explorerRenderPickerCards(source) {
|
||||||
const isReady = pct >= 50;
|
const isReady = pct >= 50;
|
||||||
const isActive = _explorer.playlistId === p.id;
|
const isActive = _explorer.playlistId === p.id;
|
||||||
const isFullyDiscovered = pct === 100;
|
const isFullyDiscovered = pct === 100;
|
||||||
const wasExplored = p.explored || false;
|
const wasExplored = !!(p.explored_at || p.explored);
|
||||||
const wishlisted = p.wishlisted_count || 0;
|
const wishlisted = p.wishlisted_count || 0;
|
||||||
const inLibrary = p.in_library_count || 0;
|
const inLibrary = p.in_library_count || 0;
|
||||||
|
|
||||||
|
|
@ -71967,10 +71967,10 @@ async function explorerBuildTree() {
|
||||||
if (progress) progress.style.display = 'none';
|
if (progress) progress.style.display = 'none';
|
||||||
_explorerUpdateCount();
|
_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);
|
const exploredPl = _explorer._playlists.find(p => p.id === playlistId);
|
||||||
if (exploredPl) {
|
if (exploredPl) {
|
||||||
exploredPl.explored = true;
|
exploredPl.explored_at = new Date().toISOString();
|
||||||
// Update card badge without full re-render
|
// Update card badge without full re-render
|
||||||
const card = document.querySelector(`.explorer-picker-card[data-id="${playlistId}"]`);
|
const card = document.querySelector(`.explorer-picker-card[data-id="${playlistId}"]`);
|
||||||
if (card) {
|
if (card) {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue