fix interface to ID matching

As outlined in #299, we broke many places in the code that were expecting
_album_for_id and _track_for_id to return a single item rather than a list. I
took this opportunity to divide up the interface: there's now one function for
MBIDs (returning a single object or None) and one for generic IDs (returning a
list).
This commit is contained in:
Adrian Sampson 2013-06-01 17:22:39 -07:00
parent 18bbe9f645
commit 4624f65ce3
5 changed files with 36 additions and 41 deletions

View file

@ -166,37 +166,37 @@ TrackMatch = namedtuple('TrackMatch', ['distance', 'info'])
# Aggregation of sources.
def _album_for_id(album_id):
"""Get a list of albums corresponding to a release ID."""
candidates = []
# Candidates from MusicBrainz.
def album_for_mbid(release_id):
"""Get an AlbumInfo object for a MusicBrainz release ID. Return None
if the ID is not found.
"""
try:
candidates.append(mb.album_for_id(album_id))
return mb.album_for_id(release_id)
except mb.MusicBrainzAPIError as exc:
exc.log(log)
# From plugins.
def track_for_mbid(recording_id):
"""Get a TrackInfo object for a MusicBrainz recording ID. Return None
if the ID is not found.
"""
try:
return mb.track_for_id(recording_id)
except mb.MusicBrainzAPIError as exc:
exc.log(log)
def albums_for_id(album_id):
"""Get a list of albums for an ID."""
candidates = [album_for_mbid(album_id)]
candidates.extend(plugins.album_for_id(album_id))
return filter(None, candidates)
def _track_for_id(track_id):
"""Get an item for a recording ID."""
candidates = []
# From MusicBrainz.
try:
candidates.append(mb.track_for_id(track_id))
except mb.MusicBrainzAPIError as exc:
exc.log(log)
# From plugins.
def tracks_for_id(track_id):
"""Get a list of tracks for an ID."""
candidates = [track_for_mbid(track_id)]
candidates.extend(plugins.track_for_id(track_id))
return filter(None, candidates)
def _album_candidates(items, artist, album, va_likely):
def album_candidates(items, artist, album, va_likely):
"""Search for album matches. ``items`` is a list of Item objects
that make up the album. ``artist`` and ``album`` are the respective
names (strings), which may be derived from the item list or may be
@ -224,7 +224,7 @@ def _album_candidates(items, artist, album, va_likely):
return out
def _item_candidates(item, artist, title):
def item_candidates(item, artist, title):
"""Search for item matches. ``item`` is the Item to be matched.
``artist`` and ``title`` are strings and either reflect the item or
are specified by the user.

View file

@ -361,9 +361,7 @@ def match_by_id(items):
if bool(reduce(lambda x,y: x if x==y else (), albumids)):
albumid = albumids[0]
log.debug('Searching for discovered album ID: ' + albumid)
matches = hooks._album_for_id(albumid)
if matches:
return matches[0]
return hooks.album_for_mbid(albumid)
else:
log.debug('No album ID consensus.')
@ -485,7 +483,7 @@ def tag_album(items, search_artist=None, search_album=None,
# Search by explicit ID.
if search_id is not None:
log.debug('Searching for album ID: ' + search_id)
search_cands = hooks._album_for_id(search_id)
search_cands = hooks.albums_for_id(search_id)
# Use existing metadata or text search.
else:
@ -516,8 +514,8 @@ def tag_album(items, search_artist=None, search_album=None,
log.debug(u'Album might be VA: %s' % str(va_likely))
# Get the results from the data sources.
search_cands = hooks._album_candidates(items, search_artist,
search_album, va_likely)
search_cands = hooks.album_candidates(items, search_artist,
search_album, va_likely)
log.debug(u'Evaluating %i candidates.' % len(search_cands))
for info in search_cands:
@ -544,7 +542,7 @@ def tag_item(item, search_artist=None, search_title=None,
trackid = search_id or item.mb_trackid
if trackid:
log.debug('Searching for track ID: ' + trackid)
for track_info in hooks._track_for_id(trackid):
for track_info in hooks.tracks_for_id(trackid):
dist = track_distance(item, track_info, incl_artist=True)
candidates[track_info.track_id] = \
hooks.TrackMatch(dist, track_info)
@ -567,7 +565,7 @@ def tag_item(item, search_artist=None, search_title=None,
log.debug(u'Item search terms: %s - %s' % (search_artist, search_title))
# Get and evaluate candidate metadata.
for track_info in hooks._item_candidates(item, search_artist, search_title):
for track_info in hooks.item_candidates(item, search_artist, search_title):
dist = track_distance(item, track_info, incl_artist=True)
candidates[track_info.track_id] = hooks.TrackMatch(dist, track_info)

View file

@ -127,9 +127,9 @@ class AcoustidPlugin(plugins.BeetsPlugin):
def candidates(self, items, artist, album, va_likely):
albums = []
for relid in _all_releases(items):
matches = hooks._album_for_id(relid)
if matches:
albums.extend(matches)
album = hooks.album_for_mbid(relid)
if album:
albums.append(album)
log.debug('acoustid album candidates: %i' % len(albums))
return albums
@ -141,7 +141,7 @@ class AcoustidPlugin(plugins.BeetsPlugin):
recording_ids, _ = _matches[item.path]
tracks = []
for recording_id in recording_ids:
track = hooks._track_for_id(recording_id)
track = hooks.track_for_mbid(recording_id)
if track:
tracks.append(track)
log.debug('acoustid item candidates: {0}'.format(len(tracks)))

View file

@ -72,7 +72,7 @@ def mbsync_singletons(lib, query, move, pretend, write):
s.old_data = dict(s.record)
# Get the MusicBrainz recording info.
track_info = hooks._track_for_id(s.mb_trackid)
track_info = hooks.track_for_mbid(s.mb_trackid)
if not track_info:
log.info(u'Recording ID not found: {0}'.format(s.mb_trackid))
continue
@ -97,11 +97,10 @@ def mbsync_albums(lib, query, move, pretend, write):
item.old_data = dict(item.record)
# Get the MusicBrainz album information.
matches = hooks._album_for_id(a.mb_albumid)
if not matches:
album_info = hooks.album_for_mbid(a.mb_albumid)
if not album_info:
log.info(u'Release ID not found: {0}'.format(a.mb_albumid))
continue
album_info = matches[0]
# Construct a track mapping according to MBIDs. This should work
# for albums that have missing or extra tracks.

View file

@ -39,9 +39,7 @@ def _missing(album):
if len([i for i in album.items()]) < album.tracktotal:
# fetch missing items
# TODO: Implement caching that without breaking other stuff
matches = hooks._album_for_id(album.mb_albumid)
if matches:
album_info = matches[0]
album_info = hooks.album_for_mbid(album.mb_albumid)
for track_info in getattr(album_info, 'tracks', []):
if track_info.track_id not in item_mbids:
item = _item(track_info, album_info, album.id)