diff --git a/beets/autotag/__init__.py b/beets/autotag/__init__.py index 613b58d4d..959238f7f 100644 --- a/beets/autotag/__init__.py +++ b/beets/autotag/__init__.py @@ -310,6 +310,19 @@ def apply_metadata(items, info): item.mb_albumid = mb_albumid item.mb_artistid = mb_artistid +def match_by_id(items): + # Is there a consensus on the MB album ID? + albumids = [item.mb_albumid for item in items if item.mb_albumid] + if not albumids: + return None + + # If all album IDs are equal, look up the album. + if bool(reduce(lambda x,y: x if x==y else (), albumids)): + albumid = albumids[0] + return mb.album_for_id(albumid) + else: + return None + def tag_album(items, search_artist=None, search_album=None): """Bundles together the functionality used to infer tags for a set of items comprised by an album. Returns everything relevant: @@ -383,4 +396,3 @@ def tag_album(items, search_artist=None, search_album=None): rec = RECOMMEND_NONE return cur_artist, cur_album, dist_ordered_cands, rec - diff --git a/beets/autotag/mb.py b/beets/autotag/mb.py index 927b0fa1a..84a062ebe 100644 --- a/beets/autotag/mb.py +++ b/beets/autotag/mb.py @@ -170,14 +170,14 @@ def match_album(artist, album, tracks=None): tracks = release_tracks(release.id) yield release_dict(release, tracks) -def match_album_single(artist, album, tracks=None): - """Behaves like match_album but, instead of returning an iterator, - tries to get just a single result. Returns an info dictionary or - None if no suitable match. +def album_for_id(albumid): + """Fetches an album by its MusicBrainz ID and returns an + information dictionary. If no match is found, returns None. """ - it = match_album(artist, album, tracks) + query = mbws.Query() + inc = mbws.ReleaseIncludes(artist=True, tracks=True) try: - return it.next() - except StopIteration: + album = _query_wrap(query.getReleaseById, albumid, inc) + except mbws.ResourceNotFoundError: return None - + return release_dict(album, album.tracks) diff --git a/test/test_mb.py b/test/test_mb.py index 9368796d0..cf1dd9a50 100644 --- a/test/test_mb.py +++ b/test/test_mb.py @@ -127,19 +127,29 @@ class MBReleaseDictTest(unittest.TestCase): class MBWhiteBoxTest(unittest.TestCase): def test_match_album_finds_el_producto(self): - a = mb.match_album_single('the avalanches', 'el producto') + a = iter(mb.match_album('the avalanches', 'el producto')).next() self.assertEqual(a['album'], 'El Producto') self.assertEqual(a['artist'], 'The Avalanches') self.assertEqual(len(a['tracks']), 7) def test_match_album_tolerates_small_errors(self): - a = mb.match_album_single('mia', 'kala ') + a = iter(mb.match_album('mia', 'kala ')).next() self.assertEqual(a['artist'], 'M.I.A.') self.assertEqual(a['album'], 'Kala') +class ByIDTest(unittest.TestCase): + def test_match_found(self): + a = mb.album_for_id('73677f81-86e6-4087-9255-9ee81b8e3dd3') + self.assertEqual(a['artist'], 'Paul Simon') + self.assertEqual(a['album'], 'Graceland') + self.assertTrue(len(a['tracks']) > 0) + + def test_no_match_returns_none(self): + a = mb.album_for_id('bogus-id') + self.assertEqual(a, None) + def suite(): return unittest.TestLoader().loadTestsFromName(__name__) if __name__ == '__main__': unittest.main(defaultTest='suite') -