mirror of
https://github.com/beetbox/beets.git
synced 2025-12-06 08:39:17 +01:00
musicbrainz: update patches
This commit is contained in:
parent
bef0bcbaa6
commit
0980c82959
3 changed files with 88 additions and 172 deletions
|
|
@ -49,7 +49,7 @@ from mediafile import Image, MediaFile
|
|||
|
||||
import beets
|
||||
import beets.plugins
|
||||
from beets import autotag, importer, logging, util
|
||||
from beets import importer, logging, util
|
||||
from beets.autotag.hooks import AlbumInfo, TrackInfo
|
||||
from beets.importer import ImportSession
|
||||
from beets.library import Album, Item, Library
|
||||
|
|
@ -791,40 +791,37 @@ class AutotagStub:
|
|||
length = 2
|
||||
|
||||
def install(self):
|
||||
self.mb_match_album = autotag.mb.match_album
|
||||
self.mb_match_track = autotag.mb.match_track
|
||||
self.mb_album_for_id = autotag.mb.album_for_id
|
||||
self.mb_track_for_id = autotag.mb.track_for_id
|
||||
|
||||
autotag.mb.match_album = self.match_album
|
||||
autotag.mb.match_track = self.match_track
|
||||
autotag.mb.album_for_id = self.album_for_id
|
||||
autotag.mb.track_for_id = self.track_for_id
|
||||
self.patchers = [
|
||||
patch("beets.plugins.album_for_id", lambda *_: None),
|
||||
patch("beets.plugins.track_for_id", lambda *_: None),
|
||||
patch("beets.plugins.candidates", self.candidates),
|
||||
patch("beets.plugins.item_candidates", self.item_candidates),
|
||||
]
|
||||
for p in self.patchers:
|
||||
p.start()
|
||||
|
||||
return self
|
||||
|
||||
def restore(self):
|
||||
autotag.mb.match_album = self.mb_match_album
|
||||
autotag.mb.match_track = self.mb_match_track
|
||||
autotag.mb.album_for_id = self.mb_album_for_id
|
||||
autotag.mb.track_for_id = self.mb_track_for_id
|
||||
for p in self.patchers:
|
||||
p.stop()
|
||||
|
||||
def match_album(self, albumartist, album, tracks, extra_tags):
|
||||
def candidates(self, items, artist, album, va_likely, extra_tags=None):
|
||||
if self.matching == self.IDENT:
|
||||
yield self._make_album_match(albumartist, album, tracks)
|
||||
yield self._make_album_match(artist, album, len(items))
|
||||
|
||||
elif self.matching == self.GOOD:
|
||||
for i in range(self.length):
|
||||
yield self._make_album_match(albumartist, album, tracks, i)
|
||||
yield self._make_album_match(artist, album, len(items), i)
|
||||
|
||||
elif self.matching == self.BAD:
|
||||
for i in range(self.length):
|
||||
yield self._make_album_match(albumartist, album, tracks, i + 1)
|
||||
yield self._make_album_match(artist, album, len(items), i + 1)
|
||||
|
||||
elif self.matching == self.MISSING:
|
||||
yield self._make_album_match(albumartist, album, tracks, missing=1)
|
||||
yield self._make_album_match(artist, album, len(items), missing=1)
|
||||
|
||||
def match_track(self, artist, title):
|
||||
def item_candidates(self, item, artist, title):
|
||||
yield TrackInfo(
|
||||
title=title.replace("Tag", "Applied"),
|
||||
track_id="trackid",
|
||||
|
|
@ -834,12 +831,6 @@ class AutotagStub:
|
|||
index=0,
|
||||
)
|
||||
|
||||
def album_for_id(self, mbid):
|
||||
return None
|
||||
|
||||
def track_for_id(self, mbid):
|
||||
return None
|
||||
|
||||
def _make_track_match(self, artist, album, number):
|
||||
return TrackInfo(
|
||||
title="Applied Track %d" % number,
|
||||
|
|
|
|||
|
|
@ -363,7 +363,7 @@ class ChangeRepresentation:
|
|||
self.indent_header + f"Match ({dist_string(self.match.distance)}):"
|
||||
)
|
||||
|
||||
if self.match.info.get("album"):
|
||||
if isinstance(self.match.info, autotag.hooks.AlbumInfo):
|
||||
# Matching an album - print that
|
||||
artist_album_str = (
|
||||
f"{self.match.info.artist}" + f" - {self.match.info.album}"
|
||||
|
|
|
|||
|
|
@ -1061,26 +1061,22 @@ class InferAlbumDataTest(BeetsTestCase):
|
|||
assert not self.items[0].comp
|
||||
|
||||
|
||||
def match_album_mock(*args, **kwargs):
|
||||
def album_candidates_mock(*args, **kwargs):
|
||||
"""Create an AlbumInfo object for testing."""
|
||||
track_info = TrackInfo(
|
||||
title="new title",
|
||||
track_id="trackid",
|
||||
index=0,
|
||||
)
|
||||
album_info = AlbumInfo(
|
||||
yield AlbumInfo(
|
||||
artist="artist",
|
||||
album="album",
|
||||
tracks=[track_info],
|
||||
tracks=[TrackInfo(title="new title", track_id="trackid", index=0)],
|
||||
album_id="albumid",
|
||||
artist_id="artistid",
|
||||
flex="flex",
|
||||
)
|
||||
return iter([album_info])
|
||||
|
||||
|
||||
@patch("beets.autotag.mb.match_album", Mock(side_effect=match_album_mock))
|
||||
class ImportDuplicateAlbumTest(ImportTestCase):
|
||||
@patch("beets.plugins.candidates", Mock(side_effect=album_candidates_mock))
|
||||
class ImportDuplicateAlbumTest(PluginMixin, ImportTestCase):
|
||||
plugin = "musicbrainz"
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
||||
|
|
@ -1186,20 +1182,16 @@ class ImportDuplicateAlbumTest(ImportTestCase):
|
|||
return album
|
||||
|
||||
|
||||
def match_track_mock(*args, **kwargs):
|
||||
return iter(
|
||||
[
|
||||
TrackInfo(
|
||||
artist="artist",
|
||||
title="title",
|
||||
track_id="new trackid",
|
||||
index=0,
|
||||
)
|
||||
]
|
||||
def item_candidates_mock(*args, **kwargs):
|
||||
yield TrackInfo(
|
||||
artist="artist",
|
||||
title="title",
|
||||
track_id="new trackid",
|
||||
index=0,
|
||||
)
|
||||
|
||||
|
||||
@patch("beets.autotag.mb.match_track", Mock(side_effect=match_track_mock))
|
||||
@patch("beets.plugins.item_candidates", Mock(side_effect=item_candidates_mock))
|
||||
class ImportDuplicateSingletonTest(ImportTestCase):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
|
@ -1633,7 +1625,7 @@ class ReimportTest(AutotagImportTestCase):
|
|||
|
||||
def test_reimported_album_not_preserves_flexattr(self):
|
||||
self._setup_session()
|
||||
assert self._album().data_source == "original_source"
|
||||
|
||||
self.importer.run()
|
||||
assert self._album().data_source == "match_source"
|
||||
|
||||
|
|
@ -1657,6 +1649,7 @@ class ImportPretendTest(AutotagImportTestCase):
|
|||
assert len(self.lib.albums()) == 0
|
||||
|
||||
return [line for line in logs if not line.startswith("Sending event:")]
|
||||
assert self._album().data_source == "original_source"
|
||||
|
||||
def test_import_singletons_pretend(self):
|
||||
assert self.__run(self.setup_singleton_importer(pretend=True)) == [
|
||||
|
|
@ -1681,112 +1674,64 @@ class ImportPretendTest(AutotagImportTestCase):
|
|||
assert self.__run(importer) == [f"No files imported from {empty_path}"]
|
||||
|
||||
|
||||
# Helpers for ImportMusicBrainzIdTest.
|
||||
def mocked_get_album_by_id(id_):
|
||||
"""Return album candidate for the given id.
|
||||
|
||||
|
||||
def mocked_get_release_by_id(
|
||||
id_, includes=[], release_status=[], release_type=[]
|
||||
):
|
||||
"""Mimic musicbrainzngs.get_release_by_id, accepting only a restricted list
|
||||
of MB ids (ID_RELEASE_0, ID_RELEASE_1). The returned dict differs only in
|
||||
the release title and artist name, so that ID_RELEASE_0 is a closer match
|
||||
to the items created by ImportHelper.prepare_album_for_import()."""
|
||||
The two albums differ only in the release title and artist name, so that
|
||||
ID_RELEASE_0 is a closer match to the items created by
|
||||
ImportHelper.prepare_album_for_import().
|
||||
"""
|
||||
# Map IDs to (release title, artist), so the distances are different.
|
||||
releases = {
|
||||
ImportMusicBrainzIdTest.ID_RELEASE_0: ("VALID_RELEASE_0", "TAG ARTIST"),
|
||||
ImportMusicBrainzIdTest.ID_RELEASE_1: (
|
||||
"VALID_RELEASE_1",
|
||||
"DISTANT_MATCH",
|
||||
),
|
||||
}
|
||||
album, artist = {
|
||||
ImportIdTest.ID_RELEASE_0: ("VALID_RELEASE_0", "TAG ARTIST"),
|
||||
ImportIdTest.ID_RELEASE_1: ("VALID_RELEASE_1", "DISTANT_MATCH"),
|
||||
}[id_]
|
||||
|
||||
return {
|
||||
"release": {
|
||||
"title": releases[id_][0],
|
||||
"id": id_,
|
||||
"medium-list": [
|
||||
{
|
||||
"track-list": [
|
||||
{
|
||||
"id": "baz",
|
||||
"recording": {
|
||||
"title": "foo",
|
||||
"id": "bar",
|
||||
"length": 59,
|
||||
},
|
||||
"position": 9,
|
||||
"number": "A2",
|
||||
}
|
||||
],
|
||||
"position": 5,
|
||||
}
|
||||
],
|
||||
"artist-credit": [
|
||||
{
|
||||
"artist": {
|
||||
"name": releases[id_][1],
|
||||
"id": "some-id",
|
||||
},
|
||||
}
|
||||
],
|
||||
"release-group": {
|
||||
"id": "another-id",
|
||||
},
|
||||
"status": "Official",
|
||||
}
|
||||
}
|
||||
return AlbumInfo(
|
||||
album_id=id_,
|
||||
album=album,
|
||||
artist_id="some-id",
|
||||
artist=artist,
|
||||
albumstatus="Official",
|
||||
tracks=[
|
||||
TrackInfo(
|
||||
track_id="bar",
|
||||
title="foo",
|
||||
artist_id="some-id",
|
||||
artist=artist,
|
||||
length=59,
|
||||
index=9,
|
||||
track_allt="A2",
|
||||
)
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
def mocked_get_recording_by_id(
|
||||
id_, includes=[], release_status=[], release_type=[]
|
||||
):
|
||||
"""Mimic musicbrainzngs.get_recording_by_id, accepting only a restricted
|
||||
list of MB ids (ID_RECORDING_0, ID_RECORDING_1). The returned dict differs
|
||||
only in the recording title and artist name, so that ID_RECORDING_0 is a
|
||||
closer match to the items created by ImportHelper.prepare_album_for_import().
|
||||
def mocked_get_track_by_id(id_):
|
||||
"""Return track candidate for the given id.
|
||||
|
||||
The two tracks differ only in the release title and artist name, so that
|
||||
ID_RELEASE_0 is a closer match to the items created by
|
||||
ImportHelper.prepare_album_for_import().
|
||||
"""
|
||||
# Map IDs to (recording title, artist), so the distances are different.
|
||||
releases = {
|
||||
ImportMusicBrainzIdTest.ID_RECORDING_0: (
|
||||
"VALID_RECORDING_0",
|
||||
"TAG ARTIST",
|
||||
),
|
||||
ImportMusicBrainzIdTest.ID_RECORDING_1: (
|
||||
"VALID_RECORDING_1",
|
||||
"DISTANT_MATCH",
|
||||
),
|
||||
}
|
||||
title, artist = {
|
||||
ImportIdTest.ID_RECORDING_0: ("VALID_RECORDING_0", "TAG ARTIST"),
|
||||
ImportIdTest.ID_RECORDING_1: ("VALID_RECORDING_1", "DISTANT_MATCH"),
|
||||
}[id_]
|
||||
|
||||
return {
|
||||
"recording": {
|
||||
"title": releases[id_][0],
|
||||
"id": id_,
|
||||
"length": 59,
|
||||
"artist-credit": [
|
||||
{
|
||||
"artist": {
|
||||
"name": releases[id_][1],
|
||||
"id": "some-id",
|
||||
},
|
||||
}
|
||||
],
|
||||
}
|
||||
}
|
||||
return TrackInfo(
|
||||
track_id=id_,
|
||||
title=title,
|
||||
artist_id="some-id",
|
||||
artist=artist,
|
||||
length=59,
|
||||
)
|
||||
|
||||
|
||||
@patch(
|
||||
"musicbrainzngs.get_recording_by_id",
|
||||
Mock(side_effect=mocked_get_recording_by_id),
|
||||
)
|
||||
@patch(
|
||||
"musicbrainzngs.get_release_by_id",
|
||||
Mock(side_effect=mocked_get_release_by_id),
|
||||
)
|
||||
class ImportMusicBrainzIdTest(ImportTestCase):
|
||||
"""Test the --musicbrainzid argument."""
|
||||
|
||||
MB_RELEASE_PREFIX = "https://musicbrainz.org/release/"
|
||||
MB_RECORDING_PREFIX = "https://musicbrainz.org/recording/"
|
||||
@patch("beets.plugins.track_for_id", Mock(side_effect=mocked_get_track_by_id))
|
||||
@patch("beets.plugins.album_for_id", Mock(side_effect=mocked_get_album_by_id))
|
||||
class ImportIdTest(ImportTestCase):
|
||||
ID_RELEASE_0 = "00000000-0000-0000-0000-000000000000"
|
||||
ID_RELEASE_1 = "11111111-1111-1111-1111-111111111111"
|
||||
ID_RECORDING_0 = "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
|
||||
|
|
@ -1797,21 +1742,14 @@ class ImportMusicBrainzIdTest(ImportTestCase):
|
|||
self.prepare_album_for_import(1)
|
||||
|
||||
def test_one_mbid_one_album(self):
|
||||
self.setup_importer(
|
||||
search_ids=[self.MB_RELEASE_PREFIX + self.ID_RELEASE_0]
|
||||
)
|
||||
self.setup_importer(search_ids=[self.ID_RELEASE_0])
|
||||
|
||||
self.importer.add_choice(importer.action.APPLY)
|
||||
self.importer.run()
|
||||
assert self.lib.albums().get().album == "VALID_RELEASE_0"
|
||||
|
||||
def test_several_mbid_one_album(self):
|
||||
self.setup_importer(
|
||||
search_ids=[
|
||||
self.MB_RELEASE_PREFIX + self.ID_RELEASE_0,
|
||||
self.MB_RELEASE_PREFIX + self.ID_RELEASE_1,
|
||||
]
|
||||
)
|
||||
self.setup_importer(search_ids=[self.ID_RELEASE_0, self.ID_RELEASE_1])
|
||||
|
||||
self.importer.add_choice(2) # Pick the 2nd best match (release 1).
|
||||
self.importer.add_choice(importer.action.APPLY)
|
||||
|
|
@ -1819,9 +1757,7 @@ class ImportMusicBrainzIdTest(ImportTestCase):
|
|||
assert self.lib.albums().get().album == "VALID_RELEASE_1"
|
||||
|
||||
def test_one_mbid_one_singleton(self):
|
||||
self.setup_singleton_importer(
|
||||
search_ids=[self.MB_RECORDING_PREFIX + self.ID_RECORDING_0]
|
||||
)
|
||||
self.setup_singleton_importer(search_ids=[self.ID_RECORDING_0])
|
||||
|
||||
self.importer.add_choice(importer.action.APPLY)
|
||||
self.importer.run()
|
||||
|
|
@ -1829,10 +1765,7 @@ class ImportMusicBrainzIdTest(ImportTestCase):
|
|||
|
||||
def test_several_mbid_one_singleton(self):
|
||||
self.setup_singleton_importer(
|
||||
search_ids=[
|
||||
self.MB_RECORDING_PREFIX + self.ID_RECORDING_0,
|
||||
self.MB_RECORDING_PREFIX + self.ID_RECORDING_1,
|
||||
]
|
||||
search_ids=[self.ID_RECORDING_0, self.ID_RECORDING_1]
|
||||
)
|
||||
|
||||
self.importer.add_choice(2) # Pick the 2nd best match (recording 1).
|
||||
|
|
@ -1845,11 +1778,7 @@ class ImportMusicBrainzIdTest(ImportTestCase):
|
|||
task = importer.ImportTask(
|
||||
paths=self.import_dir, toppath="top path", items=[_common.item()]
|
||||
)
|
||||
task.search_ids = [
|
||||
self.MB_RELEASE_PREFIX + self.ID_RELEASE_0,
|
||||
self.MB_RELEASE_PREFIX + self.ID_RELEASE_1,
|
||||
"an invalid and discarded id",
|
||||
]
|
||||
task.search_ids = [self.ID_RELEASE_0, self.ID_RELEASE_1]
|
||||
|
||||
task.lookup_candidates()
|
||||
assert {"VALID_RELEASE_0", "VALID_RELEASE_1"} == {
|
||||
|
|
@ -1861,11 +1790,7 @@ class ImportMusicBrainzIdTest(ImportTestCase):
|
|||
task = importer.SingletonImportTask(
|
||||
toppath="top path", item=_common.item()
|
||||
)
|
||||
task.search_ids = [
|
||||
self.MB_RECORDING_PREFIX + self.ID_RECORDING_0,
|
||||
self.MB_RECORDING_PREFIX + self.ID_RECORDING_1,
|
||||
"an invalid and discarded id",
|
||||
]
|
||||
task.search_ids = [self.ID_RECORDING_0, self.ID_RECORDING_1]
|
||||
|
||||
task.lookup_candidates()
|
||||
assert {"VALID_RECORDING_0", "VALID_RECORDING_1"} == {
|
||||
|
|
|
|||
Loading…
Reference in a new issue