def finalize(config): """A coroutine that finishes up importer tasks. In particular, the coroutine sends plugin events, deletes old files, and saves progress. This is a "terminal" coroutine (it yields None). """ while True: task = yield if task.should_skip(): if config.resume is not False: task.save_progress() if config.incremental: task.save_history() continue items = task.imported_items() # Announce that we've added an album. if task.is_album: album = config.lib.get_album(task.album_id) plugins.send('album_imported', lib=config.lib, album=album, config=config) else: for item in items: plugins.send('item_imported', lib=config.lib, item=item, config=config) # Finally, delete old files. if config.copy and config.delete: new_paths = [os.path.realpath(item.path) for item in items] for old_path in task.old_paths: # Only delete files that were actually copied. if old_path not in new_paths: util.remove(syspath(old_path), False) task.prune(old_path) # Update progress. if config.resume is not False: task.save_progress() if config.incremental: task.save_history()
def apply_choices(config): """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, per_disc_numbering=config.per_disc_numbering ) else: autotag.apply_item_metadata(task.item, task.match.info) plugins.send('import_task_apply', config=config, 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 = config.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(config.lib, task): duplicate_items += album.items() else: duplicate_items = _item_duplicate_check(config.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 config.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), config.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 config.lib.transaction(): # Remove old items. for replaced in task.replaced_items.itervalues(): for item in replaced: config.lib.remove(item) for item in duplicate_items: config.lib.remove(item) # Add new ones. if task.is_album: # Add an album. album = config.lib.add_album(items) task.album_id = album.id else: # Add tracks. for item in items: config.lib.add(item)