Backfill MusicBrainz recording ID from Navidrome during database scan

Navidrome provides musicBrainzId on tracks — now captured during
database updates so the MusicBrainz enrichment worker can skip
tracks that already have an MBID.

Uses COALESCE on UPDATE to never overwrite existing enrichment data
with NULL (safe for Plex/Jellyfin which don't provide this field).

Inspired by PR #279 — fixed data loss bug in the original where
unconditional UPDATE would erase existing MBIDs.
This commit is contained in:
Broque Thomas 2026-04-11 18:47:54 -07:00
parent 7fb4cf6b0e
commit a3ab5adcba
2 changed files with 10 additions and 5 deletions

View file

@ -120,6 +120,7 @@ class NavidromeTrack:
self._album_id = navidrome_data.get('albumId', '')
self._artist_id = navidrome_data.get('artistId', '')
self.musicBrainzId = navidrome_data.get('musicBrainzId')
def _parse_date(self, date_str: Optional[str]) -> Optional[datetime]:
if not date_str:

View file

@ -4638,6 +4638,9 @@ class MusicDatabase:
except Exception:
pass
# Extract MusicBrainz recording ID from server if available (Navidrome provides this)
mbid = getattr(track_obj, 'musicBrainzId', None) or None
# Check if track already exists — UPDATE to preserve enrichment columns,
# INSERT only for genuinely new tracks
cursor.execute("SELECT 1 FROM tracks WHERE id = ? LIMIT 1", (track_id,))
@ -4646,20 +4649,21 @@ class MusicDatabase:
if is_new_track:
cursor.execute("""
INSERT INTO tracks
(id, album_id, artist_id, title, track_number, duration, file_path, bitrate, server_source, track_artist, updated_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP)
""", (track_id, album_id, artist_id, title, track_number, duration, file_path, bitrate, server_source, track_artist))
(id, album_id, artist_id, title, track_number, duration, file_path, bitrate, server_source, track_artist, musicbrainz_recording_id, updated_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP)
""", (track_id, album_id, artist_id, title, track_number, duration, file_path, bitrate, server_source, track_artist, mbid))
else:
# Update server-provided fields only — preserves spotify_track_id, deezer_id,
# isrc, bpm, musicbrainz IDs, and all other enrichment data
# isrc, bpm, and all other enrichment data
cursor.execute("""
UPDATE tracks
SET album_id = ?, artist_id = ?, title = ?, track_number = ?,
duration = ?, file_path = ?, bitrate = ?, server_source = ?,
track_artist = COALESCE(?, track_artist),
musicbrainz_recording_id = COALESCE(?, musicbrainz_recording_id),
updated_at = CURRENT_TIMESTAMP
WHERE id = ?
""", (album_id, artist_id, title, track_number, duration, file_path, bitrate, server_source, track_artist, track_id))
""", (album_id, artist_id, title, track_number, duration, file_path, bitrate, server_source, track_artist, mbid, track_id))
conn.commit()