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 = library.AndQuery(( library.MatchQuery('artist', artist), library.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 get_item(self, path): """Return the beets item related to path. """ query = library.MatchQuery('path', path) item = self.lib.items(query).get() if item: return item else: log.info(u'mpdstats: item not found: {0}'.format( displayable_path(path)))
def _duplicate_check(lib, task): """Check whether an album already exists in the library. Returns a list of Album objects (empty if no duplicates are found). """ assert task.choice_flag in (action.ASIS, action.APPLY) artist, album = task.chosen_ident() if artist is None: # As-is import with no artist. Skip check. return [] found_albums = [] cur_paths = set(i.path for i in task.items if i) for album_cand in lib.albums(library.MatchQuery('albumartist', artist)): if album_cand.album == album: # Check whether the album is identical in contents, in which # case it is not a duplicate (will be replaced). other_paths = set(i.path for i in album_cand.items()) if other_paths == cur_paths: continue found_albums.append(album_cand) return found_albums
def apply_choices(session): """A coroutine for applying changes to albums and singletons during the autotag process. """ task = None while True: task = yield task if task.should_skip(): continue items = task.imported_items() # Clear IDs in case the items are being re-tagged. for item in items: item.id = None item.album_id = None # Change metadata. if task.should_write_tags(): if task.is_album: autotag.apply_metadata(task.match.info, task.match.mapping) else: autotag.apply_item_metadata(task.item, task.match.info) plugins.send('import_task_apply', session=session, task=task) # Infer album-level fields. if task.is_album: _infer_album_fields(task) # Find existing item entries that these are replacing (for # re-imports). Old album structures are automatically cleaned up # when the last item is removed. task.replaced_items = defaultdict(list) for item in items: dup_items = session.lib.items(library.MatchQuery( 'path', item.path)) for dup_item in dup_items: task.replaced_items[item].append(dup_item) log.debug('replacing item %i: %s' % (dup_item.id, displayable_path(item.path))) log.debug('%i of %i items replaced' % (len(task.replaced_items), len(items))) # Find old items that should be replaced as part of a duplicate # resolution. duplicate_items = [] if task.remove_duplicates: if task.is_album: for album in _duplicate_check(session.lib, task): duplicate_items += album.items() else: duplicate_items = _item_duplicate_check(session.lib, task) log.debug('removing %i old duplicated items' % len(duplicate_items)) # Delete duplicate files that are located inside the library # directory. for duplicate_path in [i.path for i in duplicate_items]: if session.lib.directory in util.ancestry(duplicate_path): log.debug(u'deleting replaced duplicate %s' % util.displayable_path(duplicate_path)) util.remove(duplicate_path) util.prune_dirs(os.path.dirname(duplicate_path), session.lib.directory) # Add items -- before path changes -- to the library. We add the # items now (rather than at the end) so that album structures # are in place before calls to destination(). with session.lib.transaction(): # Remove old items. for replaced in task.replaced_items.itervalues(): for item in replaced: session.lib.remove(item) for item in duplicate_items: session.lib.remove(item) # Add new ones. if task.is_album: # Add an album. album = session.lib.add_album(items) task.album_id = album.id else: # Add tracks. for item in items: session.lib.add(item)
def apply_choices(config): """A coroutine for applying changes to albums during the autotag process. """ lib = _reopen_lib(config.lib) task = None while True: task = yield task if task.should_skip(): continue items = [i for i in task.items if i] if task.is_album else [task.item] # Clear IDs in case the items are being re-tagged. for item in items: item.id = None item.album_id = None # Change metadata. if task.should_write_tags(): if task.is_album: autotag.apply_metadata(task.items, task.info) else: autotag.apply_item_metadata(task.item, task.info) # Infer album-level fields. if task.is_album: _infer_album_fields(task) # Find existing item entries that these are replacing. Old # album structures are automatically cleaned up when the # last item is removed. replaced_items = defaultdict(list) for item in items: dup_items = lib.items(library.MatchQuery('path', item.path)) for dup_item in dup_items: replaced_items[item].append(dup_item) log.debug('replacing item %i: %s' % (dup_item.id, displayable_path(item.path))) log.debug('%i of %i items replaced' % (len(replaced_items), len(items))) # Move/copy files. task.old_paths = [item.path for item in items] for item in items: if config.copy: # If we're replacing an item, then move rather than # copying. do_copy = not bool(replaced_items[item]) lib.move(item, do_copy, task.is_album) if config.write and task.should_write_tags(): item.write() # Add items to library. We consolidate this at the end to avoid # locking while we do the copying and tag updates. try: # Remove old items. for replaced in replaced_items.itervalues(): for item in replaced: lib.remove(item) # Add new ones. if task.is_album: # Add an album. album = lib.add_album(items) task.album_id = album.id else: # Add tracks. for item in items: lib.add(item) finally: lib.save()