def simple_import(lib, paths, copy, delete, resume): """Add files from the paths to the library without changing any tags. """ for toppath, path, items in read_albums(paths, resume): if items is None: continue if copy: if delete: old_paths = [os.path.realpath(item.path) for item in items] for item in items: item.move(lib, True) album = lib.add_album(items, True) lib.save() if resume is not False: progress_set(toppath, path) if copy and delete: new_paths = [os.path.realpath(item.path) for item in items] for old_path in old_paths: # Only delete files that were actually moved. if old_path not in new_paths: os.remove(library._syspath(old_path)) log.info('added album: %s - %s' % (album.albumartist, album.album))
def _sorted_walk(path): """Like os.walk, but yields things in sorted, breadth-first order. """ # Make sure the path isn't a Unicode string. path = library._bytestring_path(path) # Get all the directories and files at this level. dirs = [] files = [] for base in os.listdir(path): cur = os.path.join(path, base) if os.path.isdir(library._syspath(cur)): dirs.append(base) else: files.append(base) # Sort lists and yield the current level. dirs.sort() files.sort() yield (path, dirs, files) # Recurse into directories. for base in dirs: cur = os.path.join(path, base) # yield from _sorted_walk(cur) for res in _sorted_walk(cur): yield res
def apply_choices(lib, copy, write, art, delete, progress): """A coroutine for applying changes to albums during the autotag process. The parameters to the generator control the behavior of the import. The coroutine accepts (items, info) pairs and yields nothing. items the set of Items to import; info is either a candidate info dictionary or CHOICE_ASIS. """ lib = _reopen_lib(lib) while True: # Get next chunk of work. toppath, path, items, info = yield # Check for "path finished" message. if path is DONE_SENTINEL: if progress: # Mark path as complete. progress_set(toppath, None) continue # Only process the items if info is not None (indicating a # skip). if info is not None: # Change metadata, move, and copy. if info is not CHOICE_ASIS: autotag.apply_metadata(items, info) if copy and delete: old_paths = [os.path.realpath(item.path) for item in items] for item in items: if copy: item.move(lib, True) if write and info is not CHOICE_ASIS: item.write() # Add items to library. We consolidate this at the end to avoid # locking while we do the copying and tag updates. albuminfo = lib.add_album(items, infer_aa = (info is CHOICE_ASIS)) # Get album art if requested. if art and info is not CHOICE_ASIS: artpath = beets.autotag.art.art_for_album(info) if artpath: albuminfo.set_art(artpath) # Write the database after each album. lib.save() # Finally, delete old files. if copy and delete: new_paths = [os.path.realpath(item.path) for item in items] for old_path in old_paths: # Only delete files that were actually moved. if old_path not in new_paths: os.remove(library._syspath(old_path)) # Update progress. if progress: progress_set(toppath, path)
def read_albums(paths, resume): """A generator yielding all the albums (as sets of Items) found in the user-specified list of paths. `progress` specifies whether the resuming feature should be used. It may be True (resume if possible), False (never resume), or None (ask). """ # Use absolute paths. paths = [library._normpath(path) for path in paths] # Check the user-specified directories. for path in paths: if not os.path.isdir(library._syspath(path)): raise ui.UserError('not a directory: ' + path) # Look for saved progress. progress = resume is not False if progress: resume_dirs = {} for path in paths: resume_dir = progress_get(path) if resume_dir: # Either accept immediately or prompt for input to decide. if resume: do_resume = True ui.print_('Resuming interrupted import of %s' % path) else: do_resume = ui.input_yn("Import of the directory:\n%s" "\nwas interrupted. Resume (Y/n)?" % path) ui.print_() if do_resume: resume_dirs[path] = resume_dir else: # Clear progress; we're starting from the top. progress_set(path, None) for toppath in paths: # Produce each path. if progress: resume_dir = resume_dirs.get(toppath) for path, items in autotag.albums_in_dir(os.path.expanduser(toppath)): if progress and resume_dir: # We're fast-forwarding to resume a previous tagging. if path == resume_dir: # We've hit the last good path! Turn off the # fast-forwarding. resume_dir = None continue yield toppath, path, items # Indicate the directory is finished. yield toppath, DONE_SENTINEL, None
def read_albums(paths): """A generator yielding all the albums (as sets of Items) found in the user-specified list of paths. """ # Use absolute paths. paths = [library._normpath(path) for path in paths] # Check the user-specified directories. for path in paths: if not os.path.isdir(library._syspath(path)): raise ui.UserError('not a directory: ' + path) # Look for saved progress. resume_dirs = {} for path in paths: resume_dir = progress_get(path) if resume_dir: resume = ui.input_yn("Import of the directory:\n%s" "\nwas interrupted. Resume (Y/n)? " % path) if resume: resume_dirs[path] = resume_dir else: # Clear progress; we're starting from the top. progress_set(path, None) ui.print_() for toppath in paths: # Produce each path. resume_dir = resume_dirs.get(toppath) for path, items in autotag.albums_in_dir(os.path.expanduser(toppath)): if resume_dir: # We're fast-forwarding to resume a previous tagging. if path == resume_dir: # We've hit the last good path! Turn off the # fast-forwarding. resume_dir = None continue yield toppath, path, items # Indicate the directory is finished. yield toppath, DONE_SENTINEL, None
def simple_import(lib, paths, copy, delete): """Add files from the paths to the library without changing any tags. """ for toppath, path, items in read_albums(paths): if items is None: continue if copy: if delete: old_paths = [item.path for item in items] for item in items: item.move(lib, True) album = lib.add_album(items) lib.save() progress_set(toppath, path) if copy and delete: for old_path in old_paths: os.remove(library._syspath(old_path)) log.info('added album: %s - %s' % (album.artist, album.album))