#901: one-time backfill — stable ids for EXISTING file-import mirrored tracks
The mirror_playlist fix only assigns stable ids to newly-imported playlists, so a user with an existing file-import playlist would still have empty-id rows (and dead Find & Add matches) until a manual re-import. Add an idempotent startup backfill that assigns the SAME stable id a fresh import would to any mirrored track missing one — so existing matches start sticking with no re-import. Runs once per db/process (the init is guarded), only touches empty-id rows (no-op afterward), native ids untouched. Tests: backfill fills empty ids with the exact fresh-import id, is idempotent (2nd run = 0), and leaves native ids alone.
This commit is contained in:
parent
6e622d30f1
commit
1ad80d77a6
2 changed files with 66 additions and 0 deletions
|
|
@ -992,6 +992,39 @@ class MusicDatabase:
|
|||
raise
|
||||
|
||||
self._init_manual_library_match_table()
|
||||
self._backfill_mirrored_track_source_ids()
|
||||
|
||||
def _backfill_mirrored_track_source_ids(self) -> int:
|
||||
"""One-time, idempotent: assign a stable source_track_id to mirrored tracks
|
||||
that have none (file-import / iTunes-only playlists imported before #901), so
|
||||
their existing Find & Add matches start sticking without a manual re-import.
|
||||
Only touches empty-id rows, so it's a no-op once they're filled."""
|
||||
from core.playlists.source_refs import stable_source_track_id
|
||||
updated = 0
|
||||
try:
|
||||
with self._get_connection() as conn:
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("""
|
||||
SELECT id, track_name, artist_name, album_name
|
||||
FROM mirrored_playlist_tracks
|
||||
WHERE source_track_id IS NULL OR source_track_id = ''
|
||||
""")
|
||||
rows = cursor.fetchall()
|
||||
for r in rows:
|
||||
sid = stable_source_track_id({
|
||||
'track_name': r['track_name'], 'artist_name': r['artist_name'],
|
||||
'album_name': r['album_name']})
|
||||
if sid:
|
||||
cursor.execute(
|
||||
"UPDATE mirrored_playlist_tracks SET source_track_id = ? WHERE id = ?",
|
||||
(sid, r['id']))
|
||||
updated += 1
|
||||
conn.commit()
|
||||
if updated:
|
||||
logger.info("Backfilled stable source_track_id on %d mirrored tracks (#901)", updated)
|
||||
except Exception as e:
|
||||
logger.error("mirrored track source_id backfill failed: %s", e)
|
||||
return updated
|
||||
|
||||
# Bump when the schema's generation meaningfully changes. Stamped into
|
||||
# PRAGMA user_version as a backstop indicator; nothing GATES on it yet.
|
||||
|
|
|
|||
|
|
@ -92,3 +92,36 @@ def test_native_ids_still_used_verbatim(tmp_path):
|
|||
profile_id=1)
|
||||
rows = db.get_mirrored_playlist_tracks(pid)
|
||||
assert rows[0]["source_track_id"] == "spotify123" # native id untouched
|
||||
|
||||
|
||||
def test_backfill_fills_existing_empty_ids_idempotently(tmp_path):
|
||||
# #901 backfill: a file-import playlist mirrored BEFORE the fix has empty-id rows.
|
||||
# The backfill assigns the SAME stable ids a fresh import would, so existing
|
||||
# Find & Add matches start working without a re-import.
|
||||
db = MusicDatabase(str(tmp_path / "music.db"))
|
||||
pid = db.mirror_playlist(source="file", source_playlist_id="old", name="Old",
|
||||
tracks=[{"track_name": "Slow Ride", "artist_name": "Foghat"}], profile_id=1)
|
||||
# simulate a pre-fix row: blank out the id
|
||||
with db._get_connection() as conn:
|
||||
conn.execute("UPDATE mirrored_playlist_tracks SET source_track_id = '' WHERE playlist_id = ?", (pid,))
|
||||
conn.commit()
|
||||
|
||||
n = db._backfill_mirrored_track_source_ids()
|
||||
assert n == 1
|
||||
rows = db.get_mirrored_playlist_tracks(pid)
|
||||
from core.playlists.source_refs import stable_source_track_id
|
||||
assert rows[0]["source_track_id"] == stable_source_track_id(
|
||||
{"track_name": "Slow Ride", "artist_name": "Foghat"}) # same id a fresh import gives
|
||||
|
||||
# idempotent — second run touches nothing
|
||||
assert db._backfill_mirrored_track_source_ids() == 0
|
||||
|
||||
|
||||
def test_backfill_leaves_native_ids_untouched(tmp_path):
|
||||
db = MusicDatabase(str(tmp_path / "music.db"))
|
||||
pid = db.mirror_playlist(source="spotify", source_playlist_id="sp", name="Sp",
|
||||
tracks=[{"track_name": "S", "artist_name": "A", "source_track_id": "spotify123"}],
|
||||
profile_id=1)
|
||||
db._backfill_mirrored_track_source_ids()
|
||||
rows = db.get_mirrored_playlist_tracks(pid)
|
||||
assert rows[0]["source_track_id"] == "spotify123"
|
||||
|
|
|
|||
Loading…
Reference in a new issue