Fix watchlist migration dropping profile_id & fix profile delete dialog hidden behind overlay
- Watchlist nullable migration now preserves profile_id column and composite UNIQUE constraints when rebuilding the table - Profile support migration always repairs missing profile_id columns on all tables, even if the migration metadata key already exists (handles tables rebuilt by other migrations) - Confirm dialog z-index raised to 100000 to appear above profile picker overlay (99999), fixing invisible delete confirmation
This commit is contained in:
parent
219f453b74
commit
078b1130f8
2 changed files with 79 additions and 44 deletions
|
|
@ -1128,30 +1128,59 @@ class MusicDatabase:
|
||||||
if has_not_null:
|
if has_not_null:
|
||||||
logger.info("Migrating watchlist_artists table to make spotify_artist_id nullable...")
|
logger.info("Migrating watchlist_artists table to make spotify_artist_id nullable...")
|
||||||
|
|
||||||
|
# Check if old table already has profile_id (from profile migration)
|
||||||
|
old_has_profile = 'profile_id' in columns
|
||||||
|
|
||||||
# Drop leftover temp table from any previous failed migration
|
# Drop leftover temp table from any previous failed migration
|
||||||
cursor.execute("DROP TABLE IF EXISTS watchlist_artists_new")
|
cursor.execute("DROP TABLE IF EXISTS watchlist_artists_new")
|
||||||
|
|
||||||
# Create new table with nullable spotify_artist_id
|
# Create new table with nullable spotify_artist_id
|
||||||
cursor.execute("""
|
# Include profile_id + composite UNIQUE if old table had profile support
|
||||||
CREATE TABLE watchlist_artists_new (
|
if old_has_profile:
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
cursor.execute("""
|
||||||
spotify_artist_id TEXT UNIQUE,
|
CREATE TABLE watchlist_artists_new (
|
||||||
artist_name TEXT NOT NULL,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
date_added TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
spotify_artist_id TEXT,
|
||||||
last_scan_timestamp TIMESTAMP,
|
artist_name TEXT NOT NULL,
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
date_added TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
last_scan_timestamp TIMESTAMP,
|
||||||
image_url TEXT,
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
include_albums INTEGER DEFAULT 1,
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
include_eps INTEGER DEFAULT 1,
|
image_url TEXT,
|
||||||
include_singles INTEGER DEFAULT 1,
|
include_albums INTEGER DEFAULT 1,
|
||||||
include_live INTEGER DEFAULT 0,
|
include_eps INTEGER DEFAULT 1,
|
||||||
include_remixes INTEGER DEFAULT 0,
|
include_singles INTEGER DEFAULT 1,
|
||||||
include_acoustic INTEGER DEFAULT 0,
|
include_live INTEGER DEFAULT 0,
|
||||||
include_compilations INTEGER DEFAULT 0,
|
include_remixes INTEGER DEFAULT 0,
|
||||||
itunes_artist_id TEXT
|
include_acoustic INTEGER DEFAULT 0,
|
||||||
)
|
include_compilations INTEGER DEFAULT 0,
|
||||||
""")
|
itunes_artist_id TEXT,
|
||||||
|
profile_id INTEGER DEFAULT 1,
|
||||||
|
UNIQUE(profile_id, spotify_artist_id),
|
||||||
|
UNIQUE(profile_id, itunes_artist_id)
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
else:
|
||||||
|
cursor.execute("""
|
||||||
|
CREATE TABLE watchlist_artists_new (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
spotify_artist_id TEXT UNIQUE,
|
||||||
|
artist_name TEXT NOT NULL,
|
||||||
|
date_added TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
last_scan_timestamp TIMESTAMP,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
image_url TEXT,
|
||||||
|
include_albums INTEGER DEFAULT 1,
|
||||||
|
include_eps INTEGER DEFAULT 1,
|
||||||
|
include_singles INTEGER DEFAULT 1,
|
||||||
|
include_live INTEGER DEFAULT 0,
|
||||||
|
include_remixes INTEGER DEFAULT 0,
|
||||||
|
include_acoustic INTEGER DEFAULT 0,
|
||||||
|
include_compilations INTEGER DEFAULT 0,
|
||||||
|
itunes_artist_id TEXT
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
# Copy data from old table (only columns that exist in both)
|
# Copy data from old table (only columns that exist in both)
|
||||||
cursor.execute("PRAGMA table_info(watchlist_artists)")
|
cursor.execute("PRAGMA table_info(watchlist_artists)")
|
||||||
|
|
@ -1160,7 +1189,7 @@ class MusicDatabase:
|
||||||
'last_scan_timestamp', 'created_at', 'updated_at', 'image_url',
|
'last_scan_timestamp', 'created_at', 'updated_at', 'image_url',
|
||||||
'include_albums', 'include_eps', 'include_singles', 'include_live',
|
'include_albums', 'include_eps', 'include_singles', 'include_live',
|
||||||
'include_remixes', 'include_acoustic', 'include_compilations',
|
'include_remixes', 'include_acoustic', 'include_compilations',
|
||||||
'itunes_artist_id']
|
'itunes_artist_id', 'profile_id']
|
||||||
shared_cols = [c for c in new_cols if c in old_cols]
|
shared_cols = [c for c in new_cols if c in old_cols]
|
||||||
cols_str = ', '.join(shared_cols)
|
cols_str = ', '.join(shared_cols)
|
||||||
cursor.execute(f"INSERT INTO watchlist_artists_new ({cols_str}) SELECT {cols_str} FROM watchlist_artists")
|
cursor.execute(f"INSERT INTO watchlist_artists_new ({cols_str}) SELECT {cols_str} FROM watchlist_artists")
|
||||||
|
|
@ -1173,6 +1202,8 @@ class MusicDatabase:
|
||||||
|
|
||||||
# Recreate indexes
|
# Recreate indexes
|
||||||
cursor.execute("CREATE INDEX IF NOT EXISTS idx_watchlist_spotify_id ON watchlist_artists (spotify_artist_id)")
|
cursor.execute("CREATE INDEX IF NOT EXISTS idx_watchlist_spotify_id ON watchlist_artists (spotify_artist_id)")
|
||||||
|
if old_has_profile:
|
||||||
|
cursor.execute("CREATE INDEX IF NOT EXISTS idx_watchlist_profile ON watchlist_artists (profile_id)")
|
||||||
|
|
||||||
logger.info("Successfully migrated watchlist_artists table - spotify_artist_id is now nullable")
|
logger.info("Successfully migrated watchlist_artists table - spotify_artist_id is now nullable")
|
||||||
else:
|
else:
|
||||||
|
|
@ -1767,8 +1798,27 @@ class MusicDatabase:
|
||||||
try:
|
try:
|
||||||
# Check if migration already applied
|
# Check if migration already applied
|
||||||
cursor.execute("SELECT value FROM metadata WHERE key = 'profiles_migration_v1' LIMIT 1")
|
cursor.execute("SELECT value FROM metadata WHERE key = 'profiles_migration_v1' LIMIT 1")
|
||||||
if cursor.fetchone():
|
already_migrated = cursor.fetchone() is not None
|
||||||
return # Already migrated
|
|
||||||
|
# Even if already migrated, ensure profile_id columns exist on all tables
|
||||||
|
# (another migration may have rebuilt a table without profile_id)
|
||||||
|
tables_needing_profile_id = [
|
||||||
|
'watchlist_artists', 'wishlist_tracks', 'similar_artists',
|
||||||
|
'discovery_pool', 'discovery_recent_albums', 'discovery_curated_playlists',
|
||||||
|
'bubble_snapshots', 'recent_releases'
|
||||||
|
]
|
||||||
|
for table in tables_needing_profile_id:
|
||||||
|
try:
|
||||||
|
cursor.execute(f"PRAGMA table_info({table})")
|
||||||
|
columns = [col[1] for col in cursor.fetchall()]
|
||||||
|
if 'profile_id' not in columns:
|
||||||
|
cursor.execute(f"ALTER TABLE {table} ADD COLUMN profile_id INTEGER DEFAULT 1")
|
||||||
|
logger.info(f"Repaired missing profile_id column on {table}")
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if already_migrated:
|
||||||
|
return # Rest of migration already done
|
||||||
|
|
||||||
logger.info("Adding multi-profile support...")
|
logger.info("Adding multi-profile support...")
|
||||||
|
|
||||||
|
|
@ -1791,22 +1841,7 @@ class MusicDatabase:
|
||||||
VALUES (1, 'Admin', 1)
|
VALUES (1, 'Admin', 1)
|
||||||
""")
|
""")
|
||||||
|
|
||||||
# 3. Add profile_id column to per-profile tables
|
# 3. profile_id columns already ensured above (before early-return guard)
|
||||||
tables_needing_profile_id = [
|
|
||||||
'watchlist_artists', 'wishlist_tracks', 'similar_artists',
|
|
||||||
'discovery_pool', 'discovery_recent_albums', 'discovery_curated_playlists',
|
|
||||||
'bubble_snapshots', 'recent_releases'
|
|
||||||
]
|
|
||||||
|
|
||||||
for table in tables_needing_profile_id:
|
|
||||||
try:
|
|
||||||
cursor.execute(f"PRAGMA table_info({table})")
|
|
||||||
columns = [col[1] for col in cursor.fetchall()]
|
|
||||||
if 'profile_id' not in columns:
|
|
||||||
cursor.execute(f"ALTER TABLE {table} ADD COLUMN profile_id INTEGER DEFAULT 1")
|
|
||||||
logger.info(f"Added profile_id column to {table}")
|
|
||||||
except Exception as e:
|
|
||||||
logger.warning(f"Could not add profile_id to {table}: {e}")
|
|
||||||
|
|
||||||
# 4. Rebuild watchlist_artists to change UNIQUE constraint
|
# 4. Rebuild watchlist_artists to change UNIQUE constraint
|
||||||
# Old: UNIQUE(spotify_artist_id)
|
# Old: UNIQUE(spotify_artist_id)
|
||||||
|
|
|
||||||
|
|
@ -4337,7 +4337,7 @@ body {
|
||||||
/* Confirm Dialog Modal */
|
/* Confirm Dialog Modal */
|
||||||
/* Confirm dialog must sit above all other modals (playlist, download, etc.) */
|
/* Confirm dialog must sit above all other modals (playlist, download, etc.) */
|
||||||
#confirm-modal-overlay {
|
#confirm-modal-overlay {
|
||||||
z-index: 11000;
|
z-index: 100000;
|
||||||
}
|
}
|
||||||
|
|
||||||
.confirm-modal {
|
.confirm-modal {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue