diff --git a/NEWS b/NEWS index 445e6cf61..5fd26b08e 100644 --- a/NEWS +++ b/NEWS @@ -20,6 +20,9 @@ is forthcoming as well. * Fixed bug that completely broke non-autotagged imports ("import -A"). * Fixed bug that logged the wrong paths when using "import -l". +* Fixed autotagging for the creatively-named band !!!. +* Efficiency tweak should reduce the number of MusicBrainz queries per + autotagged album. * A new "-v" command line switch enables debugging output. 1.0b4 diff --git a/beets/autotag/__init__.py b/beets/autotag/__init__.py index 6705ee9b4..6b1c20994 100644 --- a/beets/autotag/__init__.py +++ b/beets/autotag/__init__.py @@ -448,8 +448,9 @@ def tag_album(items, search_artist=None, search_album=None): # Get candidate metadata from search. if not search_artist or not search_album: raise InsufficientMetadataError() - candidates = mb.match_album(search_artist, search_album, len(items)) - candidates = list(candidates)[:MAX_CANDIDATES] + candidates = mb.match_album(search_artist, search_album, + len(items), MAX_CANDIDATES) + candidates = list(candidates) # Get candidates from plugins. candidates.extend(plugins.candidates(items)) diff --git a/beets/autotag/mb.py b/beets/autotag/mb.py index c8fd61992..8f055099e 100644 --- a/beets/autotag/mb.py +++ b/beets/autotag/mb.py @@ -31,6 +31,11 @@ SEARCH_LIMIT = 10 class ServerBusyError(Exception): pass +# We hard-code IDs for artists that can't easily be searched for. +SPECIAL_CASE_ARTISTS = { + '!!!': 'f26c72d3-e52c-467b-b651-679c73d8e1a7', +} + # MusicBrainz requires that a client does not query the server more # than once a second. This function enforces that limit using a # module-global variable to keep track of the last time a query was @@ -72,9 +77,18 @@ def get_releases(**params): """Given a list of parameters to ReleaseFilter, executes the query and yields release dicts (complete with tracks). """ + # Replace special cases. + if 'artistName' in params: + artist = params['artistName'] + if artist in SPECIAL_CASE_ARTISTS: + del params['artistName'] + params['artistId'] = SPECIAL_CASE_ARTISTS[artist] + + # Issue query. filt = mbws.ReleaseFilter(**params) results = _query_wrap(mbws.Query().getReleases, filter=filt) + # Construct results. for result in results: release = result.release tracks, _ = release_info(release.id) @@ -109,6 +123,13 @@ def find_releases(criteria, limit=SEARCH_LIMIT): is detailed here: http://wiki.musicbrainz.org/Text_Search_Syntax """ + # Replace special cases. + if 'artist' in criteria: + artist = criteria['artist'] + if artist in SPECIAL_CASE_ARTISTS: + del criteria['artist'] + criteria['arid'] = SPECIAL_CASE_ARTISTS[artist] + # Build Lucene query (the MusicBrainz 'query' filter). query_parts = [] for name, value in criteria.items(): @@ -162,7 +183,7 @@ def release_dict(release, tracks=None): return out -def match_album(artist, album, tracks=None): +def match_album(artist, album, tracks=None, limit=SEARCH_LIMIT): """Searches for a single album ("release" in MusicBrainz parlance) and returns an iterator over dictionaries of information (as returned by `release_dict`). diff --git a/beetsplug/lastid.py b/beetsplug/lastid.py index 40fe45544..f77340953 100644 --- a/beetsplug/lastid.py +++ b/beetsplug/lastid.py @@ -131,8 +131,8 @@ class LastIdPlugin(BeetsPlugin): criteria['artistName'] = last_artist # Perform the search. - cands = mb.get_releases(**criteria) - cands = list(cands)[:autotag.MAX_CANDIDATES] + criteria['limit'] = autotag.MAX_CANDIDATES + cands = list(mb.get_releases(**criteria)) log.debug('Matched last candidates: %s' % ', '.join([cand['album'] for cand in cands])) diff --git a/test/test_mb.py b/test/test_mb.py index abec39b01..79744d868 100644 --- a/test/test_mb.py +++ b/test/test_mb.py @@ -148,6 +148,25 @@ class ByIDTest(unittest.TestCase): a = mb.album_for_id('bogus-id') self.assertEqual(a, None) +class SpecialCaseTest(unittest.TestCase): + def test_chkchkchk_by_query(self): + a = iter(mb.find_releases({ + 'artist': '!!!', + 'album': '!!!', + 'tracks': '7', + })).next() + self.assertEqual(a['artist'], '!!!') + self.assertEqual(a['album'], '!!!') + + def test_chkchkchk_by_keys(self): + a = iter(mb.get_releases( + artistName='!!!', + title='!!!', + trackCount=7, + )).next() + self.assertEqual(a['artist'], '!!!') + self.assertEqual(a['album'], '!!!') + def suite(): return unittest.TestLoader().loadTestsFromName(__name__)