Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
e0842c4
Normalize dashes to underscores in musicbrainz data fields
snejus Jan 13, 2026
432102e
Type musicbrainz fully
snejus Jan 16, 2026
78d7a94
Simplify parsing recordings
snejus Jan 21, 2026
aa640e5
Rename track -> recording in tests for clarity
snejus Jan 17, 2026
86f8082
Fix recording parsing
snejus Jan 17, 2026
b24e450
Ensure correct data shape in recordings tests
snejus Jan 21, 2026
cae421b
Refactor track_info taking into account Recording data shape
snejus Jan 21, 2026
2754462
Simplify aliases parsing
snejus Jan 22, 2026
c39c502
Simplify multi artist credit parsing
snejus Jan 22, 2026
70df5de
Use ArtistCreditFactory for test artist_credit construction
snejus Jan 22, 2026
0dcb216
Remove _artist_ids
snejus Jan 22, 2026
1ab7223
Use ArtistFactory
snejus Jan 22, 2026
2b9bad7
Refactor _get_related_artist_names
snejus Jan 22, 2026
2d44c31
Remove album_url, track_url
snejus Jan 22, 2026
f0d712e
Refactor _preferred_release_event
snejus Jan 23, 2026
3318b53
Refactor date parsing
snejus Jan 23, 2026
4096ca6
Use ReleaseGroupFactory
snejus Jan 27, 2026
99e972e
Refactor release group parsing
snejus Jan 23, 2026
9be006a
Refactor parsing genre
snejus Jan 24, 2026
751c2c6
Refactor parsing label info
snejus Jan 25, 2026
99afdd3
Refactor parsing external ids
snejus Jan 25, 2026
7d2dddc
Refactor parsing language and script
snejus Jan 25, 2026
4a05444
Enforce asin, disambiguation, fix status
snejus Jan 25, 2026
64d1ebe
Use RecordingFactory in tests
snejus Jan 25, 2026
9a8d30b
Refactor parsing medium track
snejus Jan 27, 2026
dfceedc
Refactor medium parsing
snejus Jan 27, 2026
00a9e4a
Introduce ReleaseFactory
snejus Jan 27, 2026
8f53a2e
Make use of ReleaseFactory
snejus Jan 31, 2026
db30e6b
Fix typing issues in tests
snejus Jan 31, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
465 changes: 437 additions & 28 deletions beetsplug/_utils/musicbrainz.py

Large diffs are not rendered by default.

24 changes: 15 additions & 9 deletions beetsplug/mbpseudo.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@
from beets.library import Item
from beetsplug._typing import JSONDict

from ._utils.musicbrainz import (
Release,
ReleaseRelation,
ReleaseRelationRelease,

Check failure on line 49 in beetsplug/mbpseudo.py

View workflow job for this annotation

GitHub Actions / Check linting

Ruff (F401)

beetsplug/mbpseudo.py:49:9: F401 `._utils.musicbrainz.ReleaseRelationRelease` imported but unused
)

_STATUS_PSEUDO = "Pseudo-Release"


Expand Down Expand Up @@ -133,7 +139,7 @@
yield album_info

@override
def album_info(self, release: JSONDict) -> AlbumInfo:
def album_info(self, release: Release) -> AlbumInfo:
official_release = super().album_info(release)

if release.get("status") == _STATUS_PSEUDO:
Expand All @@ -147,7 +153,7 @@

if self.config["custom_tags_only"].get(bool):
self._replace_artist_with_alias(
raw_pseudo_release, pseudo_release

Check failure on line 156 in beetsplug/mbpseudo.py

View workflow job for this annotation

GitHub Actions / Check types with mypy

Argument 1 to "_replace_artist_with_alias" of "MusicBrainzPseudoReleasePlugin" has incompatible type "Release"; expected "dict[str, Any]"
)
self._add_custom_tags(official_release, pseudo_release)
return official_release
Expand All @@ -161,30 +167,30 @@
else:
return official_release

def _intercept_mb_release(self, data: JSONDict) -> list[str]:
def _intercept_mb_release(self, data: Release) -> list[str]:
album_id = data["id"] if "id" in data else None
if self._has_desired_script(data) or not isinstance(album_id, str):
return []

return [
pr_id
for rel in data.get("release-relations", [])
for rel in data.get("release_relations", [])
if (pr_id := self._wanted_pseudo_release_id(album_id, rel))
is not None
]

def _has_desired_script(self, release: JSONDict) -> bool:
def _has_desired_script(self, release: Release) -> bool:
if len(self._scripts) == 0:
return False
elif script := release.get("text-representation", {}).get("script"):
elif script := release.get("text_representation", {}).get("script"):
return script in self._scripts
else:
return False

def _wanted_pseudo_release_id(
self,
album_id: str,
relation: JSONDict,
relation: ReleaseRelation,
) -> str | None:
if (
len(self._scripts) == 0
Expand All @@ -195,7 +201,7 @@
return None

release = relation["release"]
if "id" in release and self._has_desired_script(release):

Check failure on line 204 in beetsplug/mbpseudo.py

View workflow job for this annotation

GitHub Actions / Check types with mypy

Argument 1 to "_has_desired_script" of "MusicBrainzPseudoReleasePlugin" has incompatible type "ReleaseRelationRelease"; expected "Release"
self._log.debug(
"Adding pseudo-release {0} for main release {1}",
release["id"],
Expand All @@ -216,9 +222,9 @@
if len(config["import"]["languages"].as_str_seq()) > 0:
return

lang = raw_pseudo_release.get("text-representation", {}).get("language")
artist_credits = raw_pseudo_release.get("release-group", {}).get(
"artist-credit", []
lang = raw_pseudo_release.get("text_representation", {}).get("language")
artist_credits = raw_pseudo_release.get("release_group", {}).get(
"artist_credit", []
)
aliases = [
artist_credit.get("artist", {}).get("aliases", [])
Expand Down
Loading
Loading