Support MusicBrainz release track ID

I still don't totally understand when MusicBrainz uses a track ID and
when it uses a release track ID - they're both displayed as the
"MusicBrainz Track ID" tag in Picard, despite being treated as different
tags by everything else - but supporting both is easy enough.
This commit is contained in:
Danielle McLean 2024-05-14 10:06:39 +10:00
parent 5afeb32f9a
commit 9fca1d566e
Signed by: 00dani
GPG key ID: 6854781A0488421C
3 changed files with 15 additions and 0 deletions

View file

@ -8,6 +8,7 @@ from ..song import Song
# The maximum size for a BLAKE2b "person" value is sixteen bytes, so we need to be concise. # The maximum size for a BLAKE2b "person" value is sixteen bytes, so we need to be concise.
HASH_PERSON_PREFIX: Final = b"mnp.mac." HASH_PERSON_PREFIX: Final = b"mnp.mac."
TRACKID_HASH_PERSON: Final = HASH_PERSON_PREFIX + b"mb_tid" TRACKID_HASH_PERSON: Final = HASH_PERSON_PREFIX + b"mb_tid"
RELEASETRACKID_HASH_PERSON: Final = HASH_PERSON_PREFIX + b"mb_rtid"
FILE_HASH_PERSON: Final = HASH_PERSON_PREFIX + b"f" FILE_HASH_PERSON: Final = HASH_PERSON_PREFIX + b"f"
PERSISTENT_ID_BITS: Final = 64 PERSISTENT_ID_BITS: Final = 64
@ -20,6 +21,14 @@ def digest_trackid(trackid: UUID) -> bytes:
).digest() ).digest()
def digest_releasetrackid(trackid: UUID) -> bytes:
return blake2b(
trackid.bytes,
digest_size=PERSISTENT_ID_BYTES,
person=RELEASETRACKID_HASH_PERSON,
).digest()
def digest_file_uri(file: Path) -> bytes: def digest_file_uri(file: Path) -> bytes:
return blake2b( return blake2b(
bytes(file), digest_size=PERSISTENT_ID_BYTES, person=FILE_HASH_PERSON bytes(file), digest_size=PERSISTENT_ID_BYTES, person=FILE_HASH_PERSON
@ -34,6 +43,8 @@ def digest_file_uri(file: Path) -> bytes:
def song_to_persistent_id(song: Song) -> int: def song_to_persistent_id(song: Song) -> int:
if song.musicbrainz_trackid: if song.musicbrainz_trackid:
hashed_id = digest_trackid(song.musicbrainz_trackid) hashed_id = digest_trackid(song.musicbrainz_trackid)
elif song.musicbrainz_releasetrackid:
hashed_id = digest_releasetrackid(song.musicbrainz_releasetrackid)
else: else:
hashed_id = digest_file_uri(song.file) hashed_id = digest_file_uri(song.file)
return int.from_bytes(hashed_id) return int.from_bytes(hashed_id)

View file

@ -21,6 +21,9 @@ def mpd_current_to_song(
queue_length=int(status["playlistlength"]), queue_length=int(status["playlistlength"]),
file=Path(current["file"]), file=Path(current["file"]),
musicbrainz_trackid=convert_if_exists(current.get("musicbrainz_trackid"), UUID), musicbrainz_trackid=convert_if_exists(current.get("musicbrainz_trackid"), UUID),
musicbrainz_releasetrackid=convert_if_exists(
current.get("musicbrainz_releasetrackid"), UUID
),
title=current.get("title"), title=current.get("title"),
artist=current.get("artist"), artist=current.get("artist"),
album=current.get("album"), album=current.get("album"),

View file

@ -19,6 +19,7 @@ class Song:
queue_length: int queue_length: int
file: Path file: Path
musicbrainz_trackid: UUID | None musicbrainz_trackid: UUID | None
musicbrainz_releasetrackid: UUID | None
title: str | None title: str | None
artist: str | None artist: str | None
composer: str | None composer: str | None