def candidates(self, items, artist, album, va_likely): albums = [] for relid in _all_releases(items): album = hooks._album_for_id(relid) if album: albums.append(album) log.debug('acoustid album candidates: %i' % len(albums)) return albums
def candidates(self, items): albums = [] for relid in _all_releases(items): album = hooks._album_for_id(relid) if album: albums.append(album) log.debug('acoustid album candidates: %i' % len(albums)) return albums
def mbsync_albums(lib, query, move, pretend, write): """Synchronize matching albums. """ # Process matching albums. for a in lib.albums(query): if not a.mb_albumid: log.info(u'Skipping album {0}: has no mb_albumid'.format(a.id)) continue items = list(a.items()) for item in items: item.old_data = dict(item.record) # Get the MusicBrainz album information. matches = hooks._album_for_id(a.mb_albumid) if not matches: 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. mapping = {} for item in items: for track_info in album_info.tracks: if item.mb_trackid == track_info.track_id: mapping[item] = track_info break # Apply. with lib.transaction(): autotag.apply_metadata(album_info, mapping) changed = False for item in items: changed = _print_and_apply_changes(lib, item, move, pretend, write) or changed if not changed: # No change to any item. continue if not pretend: # Update album structure to reflect an item in it. for key in library.ALBUM_KEYS_ITEM: setattr(a, key, getattr(items[0], key)) # Move album art (and any inconsistent items). if move and lib.directory in util.ancestry(items[0].path): log.debug(u'moving album {0}'.format(a.id)) a.move()
def _missing(album): """Query MusicBrainz to determine items missing from `album`. """ item_mbids = map(lambda x: x.mb_trackid, album.items()) if len([i for i in album.items()]) < album.tracktotal: # fetch missing items # TODO: Implement caching that without breaking other stuff album_info = hooks._album_for_id(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) log.debug('{}: track {} in album {}'.format( PLUGIN, track_info.track_id, album_info.album_id)) yield item
def _missing(album): """Query MusicBrainz to determine items missing from `album`. """ item_mbids = map(lambda x: x.mb_trackid, album.items()) if len([i for i in album.items()]) < album.tracktotal: # fetch missing items # TODO: Implement caching that without breaking other stuff album_info = hooks._album_for_id(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) log.debug('{}: track {} in album {}' .format(PLUGIN, track_info.track_id, album_info.album_id)) yield item
def match_by_id(items): """If the items are tagged with a MusicBrainz album ID, returns an info dict for the corresponding album. Otherwise, returns None. """ # Is there a consensus on the MB album ID? albumids = [item.mb_albumid for item in items if item.mb_albumid] if not albumids: log.debug('No album IDs found.') 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] log.debug('Searching for discovered album ID: ' + albumid) return hooks._album_for_id(albumid) else: log.debug('No album ID consensus.') return None
def match_by_id(items): """If the items are tagged with a MusicBrainz album ID, returns an info dict for the corresponding album. Otherwise, returns None. """ # Is there a consensus on the MB album ID? albumids = [item.mb_albumid for item in items if item.mb_albumid] if not albumids: log.debug('No album IDs found.') 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] log.debug('Searching for discovered album ID: ' + albumid) return hooks._album_for_id(albumid) else: log.debug('No album ID consensus.') return None
def tag_album(items, search_artist=None, search_album=None, search_id=None): """Bundles together the functionality used to infer tags for a set of items comprised by an album. Returns everything relevant: - The current artist. - The current album. - A list of AlbumMatch objects. The candidates are sorted by distance (i.e., best match first). - A recommendation, one of RECOMMEND_STRONG, RECOMMEND_MEDIUM, or RECOMMEND_NONE; indicating that the first candidate is very likely, it is somewhat likely, or no conclusion could be reached. If search_artist and search_album or search_id are provided, then they are used as search terms in place of the current metadata. May raise an AutotagError if existing metadata is insufficient. """ # Get current metadata. cur_artist, cur_album, artist_consensus = current_metadata(items) log.debug('Tagging %s - %s' % (cur_artist, cur_album)) # The output result (distance, AlbumInfo) tuples (keyed by MB album # ID). candidates = {} # Try to find album indicated by MusicBrainz IDs. if search_id: log.debug('Searching for album ID: ' + search_id) id_info = hooks._album_for_id(search_id) else: id_info = match_by_id(items) if id_info: _add_candidate(items, candidates, id_info) rec = recommendation(candidates.values()) log.debug('Album ID match recommendation is ' + str(rec)) if candidates and not config['import']['timid']: # If we have a very good MBID match, return immediately. # Otherwise, this match will compete against metadata-based # matches. if rec == RECOMMEND_STRONG: log.debug('ID match.') return cur_artist, cur_album, candidates.values(), rec # If searching by ID, don't continue to metadata search. if search_id is not None: if candidates: return cur_artist, cur_album, candidates.values(), rec else: return cur_artist, cur_album, [], RECOMMEND_NONE # Search terms. if not (search_artist and search_album): # No explicit search terms -- use current metadata. search_artist, search_album = cur_artist, cur_album log.debug(u'Search terms: %s - %s' % (search_artist, search_album)) # Is this album likely to be a "various artist" release? va_likely = ((not artist_consensus) or (search_artist.lower() in VA_ARTISTS) or any(item.comp for item in items)) 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) log.debug(u'Evaluating %i candidates.' % len(search_cands)) for info in search_cands: _add_candidate(items, candidates, info) # Sort and get the recommendation. candidates = sorted(candidates.itervalues()) rec = recommendation(candidates) return cur_artist, cur_album, candidates, rec
def tag_album(items, search_artist=None, search_album=None, search_id=None): """Bundles together the functionality used to infer tags for a set of items comprised by an album. Returns everything relevant: - The current artist. - The current album. - A list of AlbumMatch objects. The candidates are sorted by distance (i.e., best match first). - A recommendation. If search_artist and search_album or search_id are provided, then they are used as search terms in place of the current metadata. """ # Get current metadata. cur_artist, cur_album, artist_consensus = current_metadata(items) log.debug("Tagging %s - %s" % (cur_artist, cur_album)) # The output result (distance, AlbumInfo) tuples (keyed by MB album # ID). candidates = {} # Try to find album indicated by MusicBrainz IDs. if search_id: log.debug("Searching for album ID: " + search_id) id_info = hooks._album_for_id(search_id) else: id_info = match_by_id(items) if id_info: _add_candidate(items, candidates, id_info) rec = _recommendation(candidates.values()) log.debug("Album ID match recommendation is " + str(rec)) if candidates and not config["import"]["timid"]: # If we have a very good MBID match, return immediately. # Otherwise, this match will compete against metadata-based # matches. if rec == recommendation.strong: log.debug("ID match.") return cur_artist, cur_album, candidates.values(), rec # If searching by ID, don't continue to metadata search. if search_id is not None: if candidates: return cur_artist, cur_album, candidates.values(), rec else: return cur_artist, cur_album, [], recommendation.none # Search terms. if not (search_artist and search_album): # No explicit search terms -- use current metadata. search_artist, search_album = cur_artist, cur_album log.debug(u"Search terms: %s - %s" % (search_artist, search_album)) # Is this album likely to be a "various artist" release? va_likely = (not artist_consensus) or (search_artist.lower() in VA_ARTISTS) or any(item.comp for item in items) 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) log.debug(u"Evaluating %i candidates." % len(search_cands)) for info in search_cands: _add_candidate(items, candidates, info) # Sort and get the recommendation. candidates = sorted(candidates.itervalues()) rec = _recommendation(candidates) return cur_artist, cur_album, candidates, rec
def tag_album(items, search_artist=None, search_album=None, search_id=None): """Bundles together the functionality used to infer tags for a set of items comprised by an album. Returns everything relevant: - The current artist. - The current album. - A list of AlbumMatch objects. The candidates are sorted by distance (i.e., best match first). - A recommendation. If search_artist and search_album or search_id are provided, then they are used as search terms in place of the current metadata. """ # Get current metadata. likelies, consensus = current_metadata(items) cur_artist = likelies['artist'] cur_album = likelies['album'] log.debug('Tagging %s - %s' % (cur_artist, cur_album)) # The output result (distance, AlbumInfo) tuples (keyed by MB album # ID). candidates = {} # 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) # Use existing metadata or text search. else: # Try search based on current ID. id_info = match_by_id(items) if id_info: _add_candidate(items, candidates, id_info) rec = _recommendation(candidates.values()) log.debug('Album ID match recommendation is ' + str(rec)) if candidates and not config['import']['timid']: # If we have a very good MBID match, return immediately. # Otherwise, this match will compete against metadata-based # matches. if rec == recommendation.strong: log.debug('ID match.') return cur_artist, cur_album, candidates.values(), rec # Search terms. if not (search_artist and search_album): # No explicit search terms -- use current metadata. search_artist, search_album = cur_artist, cur_album log.debug(u'Search terms: %s - %s' % (search_artist, search_album)) # Is this album likely to be a "various artist" release? va_likely = ((not consensus['artist']) or (search_artist.lower() in VA_ARTISTS) or any(item.comp for item in items)) 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) log.debug(u'Evaluating %i candidates.' % len(search_cands)) for info in search_cands: _add_candidate(items, candidates, info) # Sort and get the recommendation. candidates = sorted(candidates.itervalues()) rec = _recommendation(candidates) return cur_artist, cur_album, candidates, rec