def process_tracks(lib, tracks, log): total = len(tracks) total_found = 0 total_fails = 0 log.info('Received {0} tracks in this page, processing...', total) for num in xrange(0, total): song = None trackid = tracks[num]['mbid'].strip() artist = tracks[num]['artist'].get('name', '').strip() title = tracks[num]['name'].strip() album = '' if 'album' in tracks[num]: album = tracks[num]['album'].get('name', '').strip() log.debug(u'query: {0} - {1} ({2})', artist, title, album) # First try to query by musicbrainz's trackid if trackid: song = lib.items(dbcore.query.MatchQuery('mb_trackid', trackid)).get() # If not, try just artist/title if song is None: log.debug(u'no album match, trying by artist/title') query = dbcore.AndQuery([ dbcore.query.SubstringQuery('artist', artist), dbcore.query.SubstringQuery('title', title) ]) song = lib.items(query).get() # Last resort, try just replacing to utf-8 quote if song is None: title = title.replace("'", u'\u2019') log.debug(u'no title match, trying utf-8 single quote') query = dbcore.AndQuery([ dbcore.query.SubstringQuery('artist', artist), dbcore.query.SubstringQuery('title', title) ]) song = lib.items(query).get() if song is not None: count = int(song.get('play_count', 0)) new_count = int(tracks[num]['playcount']) log.debug( u'match: {0} - {1} ({2}) ' u'updating: play_count {3} => {4}', song.artist, song.title, song.album, count, new_count) song['play_count'] = new_count song.store() total_found += 1 else: total_fails += 1 log.info(u' - No match: {0} - {1} ({2})', artist, title, album) if total_fails > 0: log.info('Acquired {0}/{1} play-counts ({2} unknown)', total_found, total, total_fails) return total_found, total_fails
def find_duplicates(self, lib): """Return a list of items from `lib` that have the same artist and title as the task. """ artist, title = self.chosen_ident() found_items = [] query = dbcore.AndQuery(( dbcore.MatchQuery('artist', artist), dbcore.MatchQuery('title', title), )) for other_item in lib.items(query): # Existing items not considered duplicates. if other_item.path != self.item.path: found_items.append(other_item) return found_items
def _item_duplicate_check(lib, task): """Check whether an item already exists in the library. Returns a list of Item objects. """ assert task.choice_flag in (action.ASIS, action.APPLY) artist, title = task.chosen_ident() found_items = [] query = dbcore.AndQuery(( dbcore.MatchQuery('artist', artist), dbcore.MatchQuery('title', title), )) for other_item in lib.items(query): # Existing items not considered duplicates. if other_item.path == task.item.path: continue found_items.append(other_item) return found_items
def find_duplicates(self, lib): """Return a list of albums from `lib` with the same artist and album name as the task. """ artist, album = self.chosen_ident() if artist is None: # As-is import with no artist. Skip check. return [] duplicates = [] task_paths = set(i.path for i in self.items if i) duplicate_query = dbcore.AndQuery(( dbcore.MatchQuery('albumartist', artist), dbcore.MatchQuery('album', album), )) for album in lib.albums(duplicate_query): # Check whether the album is identical in contents, in which # case it is not a duplicate (will be replaced). album_paths = set(i.path for i in album.items()) if album_paths != task_paths: duplicates.append(album) return duplicates
def tmpl_aunique(self, keys=None, disam=None): """Generate a string that is guaranteed to be unique among all albums in the library who share the same set of keys. A fields from "disam" is used in the string if one is sufficient to disambiguate the albums. Otherwise, a fallback opaque value is used. Both "keys" and "disam" should be given as whitespace-separated lists of field names. """ # Fast paths: no album, no item or library, or memoized value. if not self.item or not self.lib: return u'' if self.item.album_id is None: return u'' memokey = ('aunique', keys, disam, self.item.album_id) memoval = self.lib._memotable.get(memokey) if memoval is not None: return memoval keys = keys or 'albumartist album' disam = disam or 'albumtype year label catalognum albumdisambig' keys = keys.split() disam = disam.split() album = self.lib.get_album(self.item) if not album: # Do nothing for singletons. self.lib._memotable[memokey] = u'' return u'' # Find matching albums to disambiguate with. subqueries = [] for key in keys: value = album.get(key, '') subqueries.append(dbcore.MatchQuery(key, value)) albums = self.lib.albums(dbcore.AndQuery(subqueries)) # If there's only one album to matching these details, then do # nothing. if len(albums) == 1: self.lib._memotable[memokey] = u'' return u'' # Find the first disambiguator that distinguishes the albums. for disambiguator in disam: # Get the value for each album for the current field. disam_values = set([a.get(disambiguator, '') for a in albums]) # If the set of unique values is equal to the number of # albums in the disambiguation set, we're done -- this is # sufficient disambiguation. if len(disam_values) == len(albums): break else: # No disambiguator distinguished all fields. res = u' {0}'.format(album.id) self.lib._memotable[memokey] = res return res # Flatten disambiguation value into a string. disam_value = album.formatted(True).get(disambiguator) res = u' [{0}]'.format(disam_value) self.lib._memotable[memokey] = res return res
def process_tracks(lib, tracks): total = len(tracks) total_found = 0 total_fails = 0 log.info('lastimport: Received {0} tracks in this page, processing...' .format(total)) for num in xrange(0, total): song = '' trackid = tracks[num]['mbid'].strip() artist = tracks[num]['artist'].get('name', '').strip() title = tracks[num]['name'].strip() album = '' if 'album' in tracks[num]: album = tracks[num]['album'].get('name', '').strip() # log.debug(u'lastimport: query: {0} - {1} ({2})' # .format(artist, title, album)) # First try to query by musicbrainz's trackid if (trackid): song = lib.items('mb_trackid:'+trackid).get() # Otherwise try artist/title/album if (not song): # log.debug(u'lastimport: no match for mb_trackid {0}, trying by ' # 'artist/title/album'.format(trackid)) query = dbcore.AndQuery([ dbcore.query.SubstringQuery('artist', artist), dbcore.query.SubstringQuery('title', title), dbcore.query.SubstringQuery('album', album) ]) song = lib.items(query).get() # If not, try just artist/title if (not song): # log.debug(u'lastimport: no album match, trying by artist/title') query = dbcore.AndQuery([ dbcore.query.SubstringQuery('artist', artist), dbcore.query.SubstringQuery('title', title) ]) song = lib.items(query).get() # Last resort, try just replacing to utf-8 quote if (not song): title = title.replace('\'', u'’') # log.debug(u'lastimport: no title match, trying utf-8 single quote') query = dbcore.AndQuery([ dbcore.query.SubstringQuery('artist', artist), dbcore.query.SubstringQuery('title', title) ]) song = lib.items(query).get() if (song): count = int(song.get('play_count', 0)) new_count = int(tracks[num]['playcount']) log.debug(u'lastimport: match: {0} - {1} ({2}) updating: play_count {3} => {4}' .format(song.artist, song.title, song.album, count, new_count)) song['play_count'] = new_count song.store() total_found += 1 else: total_fails += 1 log.info(u'lastimport: - No match: {0} - {1} ({2})' .format(artist, title, album)) if total_fails > 0: log.info('lastimport: Acquired {0}/{1} play-counts ({2} unknown)' .format(total_found, total, total_fails)) return total_found, total_fails