def zero_fields(lib, opts, args): if not decargs(args) and not input_yn( u"Remove fields for all items? (Y/n)", True): return for item in lib.items(decargs(args)): self.process_item(item)
def embed_func(lib, opts, args): if opts.file: imagepath = normpath(opts.file) if not os.path.isfile(syspath(imagepath)): raise ui.UserError(u'image file {0} not found'.format( displayable_path(imagepath) )) items = lib.items(decargs(args)) # Confirm with user. if not opts.yes and not _confirm(items, not opts.file): return for item in items: art.embed_item(self._log, item, imagepath, maxwidth, None, compare_threshold, ifempty) else: albums = lib.albums(decargs(args)) # Confirm with user. if not opts.yes and not _confirm(albums, not opts.file): return for album in albums: art.embed_album(self._log, album, maxwidth, False, compare_threshold, ifempty) self.remove_artfile(album)
def lastgenre_func(lib, opts, args): write = ui.should_write() self.config.set_args(opts) if opts.album: # Fetch genres for whole albums for album in lib.albums(ui.decargs(args)): album.genre, src = self._get_genre(album) self._log.info(u'genre for album {0} ({1}): {0.genre}', album, src) album.store() for item in album.items(): # If we're using track-level sources, also look up each # track on the album. if 'track' in self.sources: item.genre, src = self._get_genre(item) item.store() self._log.info( u'genre for track {0} ({1}): {0.genre}', item, src) if write: item.try_write() else: # Just query singletons, i.e. items that are not part of # an album for item in lib.items(ui.decargs(args)): item.genre, src = self._get_genre(item) self._log.debug(u'added last.fm item genre ({0}): {1}', src, item.genre) item.store()
def func(lib, opts, args): write = config['import']['write'].get(bool) if opts.album: # Analyze albums. for album in lib.albums(ui.decargs(args)): log.info(u'analyzing {0} - {1}'.format(album.albumartist, album.album)) items = list(album.items()) results = self.compute_rgain(items, True) if results: self.store_gain(lib, items, results, album) if write: for item in items: item.write() else: # Analyze individual tracks. for item in lib.items(ui.decargs(args)): log.info(u'analyzing {0} - {1}'.format(item.artist, item.title)) results = self.compute_rgain([item], False) if results: self.store_gain(lib, [item], results, None) if write: item.write()
def func(lib, config, opts, args): write = ui.config_val(config, "beets", "import_write", commands.DEFAULT_IMPORT_WRITE, bool) if opts.album: # Analyze albums. for album in lib.albums(ui.decargs(args)): log.info("analyzing {0} - {1}".format(album.albumartist, album.album)) items = list(album.items()) results = self.compute_rgain(items, True) if results: self.store_gain(lib, items, results, album) if write: for item in items: item.write() else: # Analyze individual tracks. for item in lib.items(ui.decargs(args)): log.info("analyzing {0} - {1}".format(item.artist, item.title)) results = self.compute_rgain([item], False) if results: self.store_gain(lib, [item], results, None) if write: item.write()
def convert_func(lib, opts, args): dest = opts.dest if opts.dest is not None else \ config['convert']['dest'].get() if not dest: raise ui.UserError('no convert destination set') dest = util.bytestring_path(dest) threads = opts.threads if opts.threads is not None else \ config['convert']['threads'].get(int) keep_new = opts.keep_new if not config['convert']['paths']: path_formats = ui.get_path_formats() else: path_formats = ui.get_path_formats(config['convert']['paths']) ui.commands.list_items(lib, ui.decargs(args), opts.album, None) if not ui.input_yn("Convert? (Y/n)"): return if opts.album: items = (i for a in lib.albums(ui.decargs(args)) for i in a.items()) else: items = iter(lib.items(ui.decargs(args))) convert = [convert_item(lib, dest, keep_new, path_formats) for i in range(threads)] pipe = util.pipeline.Pipeline([items, convert]) pipe.run_parallel()
def play_music(lib, opts, args): """Execute query, create temporary playlist and execute player command passing that playlist. """ command = config['play']['command'].get() # If a command isn't set then let the OS decide how to open the playlist. if not command: sys_name = platform.system() if sys_name == 'Darwin': command = 'open' elif sys_name == 'Windows': command = 'start' else: # If not Mac or Win then assume Linux(or posix based). command = 'xdg-open' # Preform search by album and add folders rather then tracks to playlist. if opts.album: albums = lib.albums(ui.decargs(args)) paths = [] for album in albums: paths.append(album.item_dir()) item_type = 'album' # Preform item query and add tracks to playlist. else: paths = [item.path for item in lib.items(ui.decargs(args))] item_type = 'track' item_type += 's' if len(paths) > 1 else '' if not paths: ui.print_(ui.colorize('yellow', 'No {0} to play.'.format(item_type))) return # Warn user before playing any huge playlists. if len(paths) > 100: ui.print_(ui.colorize( 'yellow', 'You are about to queue {0} {1}.'.format(len(paths), item_type))) if ui.input_options(('Continue', 'Abort')) == 'a': return # Create temporary m3u file to hold our playlist. m3u = NamedTemporaryFile('w', suffix='.m3u', delete=False) for item in paths: m3u.write(item + '\n') m3u.close() # Invoke the command and log the output. output = util.command_output([command, m3u.name]) if output: log.debug(u'Output of {0}: {1}'.format(command, output)) ui.print_(u'Playing {0} {1}.'.format(len(paths), item_type))
def embed_func(lib, opts, args): if opts.file: imagepath = normpath(opts.file) for item in lib.items(decargs(args)): embed_item(item, imagepath, maxwidth) else: for album in lib.albums(decargs(args)): embed_album(album, maxwidth)
def _dup(lib, opts, args): self.config.set_args(opts) album = self.config['album'].get(bool) checksum = self.config['checksum'].get(str) copy = self.config['copy'].get(str) count = self.config['count'].get(bool) delete = self.config['delete'].get(bool) fmt = self.config['format'].get(str) full = self.config['full'].get(bool) keys = self.config['keys'].get(list) merge = self.config['merge'].get(bool) move = self.config['move'].get(str) path = self.config['path'].get(bool) tiebreak = self.config['tiebreak'].get(dict) strict = self.config['strict'].get(bool) tag = self.config['tag'].get(str) if album: if not keys: keys = ['mb_albumid'] items = lib.albums(decargs(args)) else: if not keys: keys = ['mb_trackid', 'mb_albumid'] items = lib.items(decargs(args)) if path: fmt = '$path' # Default format string for count mode. if count and not fmt: if album: fmt = '$albumartist - $album' else: fmt = '$albumartist - $album - $title' fmt += ': {0}' if checksum: for i in items: k, _ = self._checksum(i, checksum) keys = [k] for obj_id, obj_count, objs in self._duplicates(items, keys=keys, full=full, strict=strict, tiebreak=tiebreak, merge=merge): if obj_id: # Skip empty IDs. for o in objs: self._process_item(o, copy=copy, move=move, delete=delete, tag=tag, fmt=fmt.format(obj_count))
def func(lib, opts, args): write = ui.should_write() if opts.album: for album in lib.albums(ui.decargs(args)): self.handle_album(album, write) else: for item in lib.items(ui.decargs(args)): self.handle_track(item, write)
def func(lib, opts, args): write = config['import']['write'].get(bool) if opts.album: for album in lib.albums(ui.decargs(args)): self.handle_album(album, write) else: for item in lib.items(ui.decargs(args)): self.handle_track(item, write)
def embed_func(lib, opts, args): if opts.file: imagepath = normpath(opts.file) if not os.path.isfile(syspath(imagepath)): raise ui.UserError(u"image file {0} not found".format(displayable_path(imagepath))) for item in lib.items(decargs(args)): art.embed_item(self._log, item, imagepath, maxwidth, None, compare_threshold, ifempty) else: for album in lib.albums(decargs(args)): art.embed_album(self._log, album, maxwidth, False, compare_threshold, ifempty) self.remove_artfile(album)
def func(lib, opts, args): self._log.setLevel(logging.INFO) write = ui.should_write() if opts.album: for album in lib.albums(ui.decargs(args)): self.handle_album(album, write) else: for item in lib.items(ui.decargs(args)): self.handle_track(item, write)
def _dup(lib, opts, args): self.config.set_args(opts) fmt = self.config['format'].get() album = self.config['album'].get(bool) full = self.config['full'].get(bool) strict = self.config['strict'].get(bool) keys = self.config['keys'].get() checksum = self.config['checksum'].get() copy = self.config['copy'].get() move = self.config['move'].get() delete = self.config['delete'].get(bool) tag = self.config['tag'].get() if album: keys = ['mb_albumid'] items = lib.albums(decargs(args)) else: items = lib.items(decargs(args)) if self.config['path']: fmt = '$path' # Default format string for count mode. if self.config['count'] and not fmt: if album: fmt = '$albumartist - $album' else: fmt = '$albumartist - $album - $title' fmt += ': {0}' if checksum: if not isinstance(checksum, basestring): raise UserError( 'duplicates: "checksum" option must be a command' ) for i in items: k, _ = self._checksum(i, checksum) keys = [k] for obj_id, obj_count, objs in self._duplicates(items, keys=keys, full=full, strict=strict): if obj_id: # Skip empty IDs. for o in objs: self._process_item(o, lib, copy=copy, move=move, delete=delete, tag=tag, fmt=fmt.format(obj_count))
def encode(self, command, source, dest, pretend=False): """Encode `source` to `dest` using command template `command`. Raises `subprocess.CalledProcessError` if the command exited with a non-zero status code. """ # The paths and arguments must be bytes. assert isinstance(command, bytes) assert isinstance(source, bytes) assert isinstance(dest, bytes) quiet = self.config['quiet'].get(bool) if not quiet and not pretend: self._log.info(u'Encoding {0}', util.displayable_path(source)) # Substitute $source and $dest in the argument list. args = shlex.split(command) for i, arg in enumerate(args): args[i] = Template(arg).safe_substitute({ 'source': source, 'dest': dest, }) if pretend: self._log.info(u' '.join(ui.decargs(args))) return try: util.command_output(args) except subprocess.CalledProcessError as exc: # Something went wrong (probably Ctrl+C), remove temporary files self._log.info(u'Encoding {0} failed. Cleaning up...', util.displayable_path(source)) self._log.debug(u'Command {0} exited with status {1}: {2}', args, exc.returncode, exc.output) util.remove(dest) util.prune_dirs(os.path.dirname(dest)) raise except OSError as exc: raise ui.UserError( u"convert: couldn't invoke '{0}': {1}".format( u' '.join(ui.decargs(args)), exc ) ) if not quiet and not pretend: self._log.info(u'Finished encoding {0}', util.displayable_path(source))
def run(self, lib, opts, args): """Print tag info or library data for each file referenced by args. Main entry point for the `beet info ARGS...` command. If an argument is a path pointing to an existing file, then the tags of that file are printed. All other arguments are considered queries, and for each item matching all those queries the tags from the file are printed. If `opts.summarize` is true, the function merges all tags into one dictionary and only prints that. If two files have different values for the same tag, the value is set to '[various]' """ if opts.library: data_collector = library_data else: data_collector = tag_data included_keys = [] for keys in opts.included_keys: included_keys.extend(keys.split(',')) # Drop path even if user provides it multiple times included_keys = [k for k in included_keys if k != 'path'] key_filter = make_key_filter(included_keys) first = True summary = {} for data_emitter in data_collector(lib, ui.decargs(args)): try: data, item = data_emitter() except (mediafile.UnreadableFileError, IOError) as ex: self._log.error(u'cannot read file: {0}', ex) continue data = key_filter(data) if opts.summarize: update_summary(summary, data) else: if not first: ui.print_() if opts.keys_only: print_data_keys(data, item) else: fmt = ui.decargs([opts.format])[0] if opts.format else None print_data(data, item, fmt) first = False if opts.summarize: print_data(summary)
def extract_func(lib, opts, args): if opts.outpath: art.extract_first(self._log, normpath(opts.outpath), lib.items(decargs(args))) else: filename = bytestring_path(opts.filename or config["art_filename"].get()) if os.path.dirname(filename) != "": self._log.error(u"Only specify a name rather than a path for -n") return for album in lib.albums(decargs(args)): artpath = normpath(os.path.join(album.path, filename)) artpath = art.extract_first(self._log, artpath, album.items()) if artpath and opts.associate: album.set_art(artpath) album.store()
def _dup(lib, opts, args): self.config.set_args(opts) fmt = self.config['format'].get() path = self.config['path'].get() count = self.config['count'].get() album = self.config['album'].get() full = self.config['full'].get() keys = self.config['keys'].get() checksum = self.config['checksum'].get() copy = self.config['copy'].get() move = self.config['move'].get() delete = self.config['delete'].get() delete_file = self.config['delete_file'].get() tag = self.config['tag'].get() if album: keys = ['mb_albumid'] items = lib.albums(decargs(args)) else: items = lib.items(decargs(args)) if path: fmt = '$path' # Default format string for count mode. if count and not fmt: if album: fmt = '$albumartist - $album' else: fmt = '$albumartist - $album - $title' fmt += ': {0}' if checksum: for i in items: k, _ = _checksum(i, checksum) keys = ['k'] for obj_id, obj_count, objs in _duplicates(items, keys=keys, full=full): if obj_id: # Skip empty IDs. for o in objs: _process_item(o, lib, copy=copy, move=move, delete=delete if delete else delete_file, tag=tag, format=fmt.format(obj_count))
def _dup(lib, opts, args): self.config.set_args(opts) album = self.config["album"].get(bool) checksum = self.config["checksum"].get(str) copy = self.config["copy"].get(str) count = self.config["count"].get(bool) delete = self.config["delete"].get(bool) fmt = self.config["format"].get(str) full = self.config["full"].get(bool) keys = self.config["keys"].get(list) merge = self.config["merge"].get(bool) move = self.config["move"].get(str) path = self.config["path"].get(bool) tiebreak = self.config["tiebreak"].get(dict) strict = self.config["strict"].get(bool) tag = self.config["tag"].get(str) if album: if not keys: keys = ["mb_albumid"] items = lib.albums(decargs(args)) else: if not keys: keys = ["mb_trackid", "mb_albumid"] items = lib.items(decargs(args)) if path: fmt = "$path" # Default format string for count mode. if count and not fmt: if album: fmt = "$albumartist - $album" else: fmt = "$albumartist - $album - $title" fmt += ": {0}" if checksum: for i in items: k, _ = self._checksum(i, checksum) keys = [k] for obj_id, obj_count, objs in self._duplicates( items, keys=keys, full=full, strict=strict, tiebreak=tiebreak, merge=merge ): if obj_id: # Skip empty IDs. for o in objs: self._process_item(o, copy=copy, move=move, delete=delete, tag=tag, fmt=fmt.format(obj_count))
def check_bad(self, lib, opts, args): for item in lib.items(ui.decargs(args)): # First, check whether the path exists. If not, the user # should probably run `beet update` to cleanup your library. dpath = displayable_path(item.path) self._log.debug("checking path: {}", dpath) if not os.path.exists(item.path): ui.print_("{}: file does not exist".format( ui.colorize('text_error', dpath))) # Run the checker against the file if one is found ext = os.path.splitext(item.path)[1][1:] checker = self.get_checker(ext) if not checker: continue path = item.path if not isinstance(path, unicode): path = item.path.decode(sys.getfilesystemencoding()) status, errors, output = checker(path) if status > 0: ui.print_("{}: checker exited withs status {}" .format(ui.colorize('text_error', dpath), status)) for line in output: ui.print_(" {}".format(displayable_path(line))) elif errors > 0: ui.print_("{}: checker found {} errors or warnings" .format(ui.colorize('text_warning', dpath), errors)) for line in output: ui.print_(" {}".format(displayable_path(line))) else: ui.print_("{}: ok".format(ui.colorize('text_success', dpath)))
def func(lib, opts, args): write = config['import']['write'].get(bool) for item in lib.items(ui.decargs(args)): ft_in_title(item) item.store() if write: item.write()
def func(lib, opts, args): # The "write to files" option corresponds to the # import_write config value. write = ui.should_write() if opts.writerest: self.writerest_indexes(opts.writerest) for item in lib.items(ui.decargs(args)): if not opts.local_only and not self.config['local']: self.fetch_item_lyrics( lib, item, write, opts.force_refetch or self.config['force'], ) if item.lyrics: if opts.printlyr: ui.print_(item.lyrics) if opts.writerest: self.writerest(opts.writerest, item) if opts.writerest: # flush last artist self.writerest(opts.writerest, None) ui.print_(u'ReST files generated. to build, use one of:') ui.print_(u' sphinx-build -b html %s _build/html' % opts.writerest) ui.print_(u' sphinx-build -b epub %s _build/epub' % opts.writerest) ui.print_((u' sphinx-build -b latex %s _build/latex ' u'&& make -C _build/latex all-pdf') % opts.writerest)
def func(lib, opts, args): args = ui.decargs(args) if args: self.config['host'] = args.pop(0) if args: self.config['port'] = int(args.pop(0)) app.config['lib'] = lib # Normalizes json output app.config['JSONIFY_PRETTYPRINT_REGULAR'] = False app.config['INCLUDE_PATHS'] = self.config['include_paths'] # Enable CORS if required. if self.config['cors']: self._log.info(u'Enabling CORS with origin: {0}', self.config['cors']) from flask.ext.cors import CORS app.config['CORS_ALLOW_HEADERS'] = "Content-Type" app.config['CORS_RESOURCES'] = { r"/*": {"origins": self.config['cors'].get(str)} } CORS(app) # Start the web application. app.run(host=self.config['host'].as_str(), port=self.config['port'].get(int), debug=opts.debug, threaded=True)
def random_item(lib, config, opts, args): query = decargs(args) path = opts.path fmt = opts.format if fmt is None: # If no specific template is supplied, use a default if opts.album: fmt = u'$albumartist - $album' else: fmt = u'$artist - $album - $title' template = Template(fmt) if opts.album: objs = list(lib.albums(query=query)) else: objs = list(lib.items(query=query)) number = min(len(objs), opts.number) objs = random.sample(objs, number) if opts.album: for album in objs: if path: print_(album.item_dir()) else: print_(album.evaluate_template(template)) else: for item in objs: if path: print_(item.path) else: print_(item.evaluate_template(template, lib))
def commanded(self, lib, opts, args): """wlg as command""" if not self.wlg: self.setup(opts.cache, opts.verbose) if opts.force: self.config['force'] = True albums = lib.albums(decargs(args)) i = 1 try: for i, album in enumerate(albums, start=1): self._log.info(whatlastgenre.progressbar(i, len(albums))) genres = self.genres(album) if album.genre != genres: album.genre = genres album.store() for item in album.items(): item.genre = genres item.store() if config['import']['write'].get(bool): item.try_write() except KeyboardInterrupt: pass self.wlg.print_stats(i) self.setdown()
def _miss(lib, opts, args): self.config.set_args(opts) fmt = self.config['format'].get() count = self.config['count'].get() total = self.config['total'].get() albums = lib.albums(decargs(args)) if total: print(sum([_missing_count(a) for a in albums])) return # Default format string for count mode. if count and not fmt: fmt = '$albumartist - $album: $missing' print fmt for album in albums: if count: if _missing_count(album): print_(format(album, fmt)) else: for (is_found, item) in _missing(album): if is_found: sys.stdout.write('+ ') else: sys.stdout.write('- ') print_obj(item, lib)
def update_genres(lib, config, opts, args): global genres global fallback_str for item in lib.items(ui.decargs(args)): if item.album_id is not None: continue genre = get_genre(item.artist, genres) log.warn("title: %s, artist: %s, genre: %s" % (item.title, item.artist, genre)) if not genre and fallback_str != None: genre = fallback_str log.warn(u'no genre for %s in list: fallback to %s' % (item.artist, genre)) if genre is not None: log.warn(u'adding genre for %s from list: %s' % (item.artist, genre)) item.genre = genre lib.store(item) item.write() for album in lib.albums(): genre = get_genre(album.albumartist, genres) if (genre is None) and (fallback_str is not None): genre = fallback_str log.warn(u'no genre for %s in list: fallback to %s' % (album.albumartist, genre)) if genre is not None: log.warn(u'adding genre for %s from list: %s' % (album.albumartist, genre)) bluo='' album.genre = genre for item in album.items(): item.write()
def fuzzy_list(lib, opts, args): query = decargs(args) query = ' '.join(query).lower() queryMatcher = difflib.SequenceMatcher(b=query) if opts.threshold is not None: threshold = float(opts.threshold) else: threshold = config['fuzzy']['threshold'].as_number() if opts.path: fmt = '$path' else: fmt = opts.format template = Template(fmt) if fmt else None if opts.album: objs = lib.albums() else: objs = lib.items() items = filter(lambda i: is_match(queryMatcher, i, album=opts.album, threshold=threshold), objs) for item in items: print_obj(item, lib, template) if opts.verbose: print(is_match(queryMatcher, item, album=opts.album, verbose=True)[1])
def scrub_func(lib, opts, args): # This is a little bit hacky, but we set a global flag to # avoid autoscrubbing when we're also explicitly scrubbing. global scrubbing scrubbing = True # Walk through matching files and remove tags. for item in lib.items(ui.decargs(args)): log.info(u'scrubbing: {0}', util.displayable_path(item.path)) # Get album art if we need to restore it. if opts.write: mf = mediafile.MediaFile(item.path, config['id3v23'].get(bool)) art = mf.art # Remove all tags. _scrub(item.path) # Restore tags, if enabled. if opts.write: log.debug(u'writing new tags after scrub') item.try_write() if art: log.info(u'restoring art') mf = mediafile.MediaFile(item.path) mf.art = art mf.save() scrubbing = False
def lastgenre_func(lib, opts, args): write = config['import']['write'].get(bool) self.config.set_args(opts) for album in lib.albums(ui.decargs(args)): album.genre, src = self._get_genre(album) log.info(u'genre for album {0} - {1} ({2}): {3}'.format( album.albumartist, album.album, src, album.genre )) album.store() for item in album.items(): # If we're using track-level sources, also look up each # track on the album. if 'track' in self.sources: item.genre, src = self._get_genre(item) item.store() log.info( u'genre for track {0} - {1} ({2}): {3}'. format( item.artist, item.title, src, item.genre ) ) if write: item.try_write()
def func(lib, opts, args): self.config.set_args(opts) drop_feat = self.config['drop'].get(bool) write = ui.should_write() for item in lib.items(ui.decargs(args)): self.ft_in_title(item, drop_feat) item.store() if write: item.try_write()
def func(lib, opts, args): self.config.set_args(opts) drop_feat = self.config['drop'].get(bool) write = config['import']['write'].get(bool) for item in lib.items(ui.decargs(args)): ft_in_title(item, drop_feat, logging.INFO) item.store() if write: item.try_write()
def func(lib, opts, args): self.config.set_args(opts) force_parent = self.config['force'].get(bool) write = ui.should_write() for item in lib.items(ui.decargs(args)): self.find_work(item, force_parent) item.store() if write: item.try_write()
def func(self, lib: Library, options, arguments): self.lib = lib self.query = decargs(arguments) self.cfg_force = options.force if options.version: self.show_version_information() return self.handle_main_task()
def func(lib, opts, args): self.config.set_args(opts) for item in lib.items(ui.decargs(args)): log.info(u'echonest: {0} - {1} [{2}]'.format(item.artist, item.title, item.length)) if self.config['force'] or self.requires_update(item): song = self.fetch_song(item) if not song is None: self._songs[item.path] = song self.apply_metadata(item)
def do_normalize(self, lib, opts, args): objs = [] query = ui.decargs(args) if opts.album: [[objs.append(item) for item in album.items()] for album in lib.albums(query)] else: [objs.append(item) for item in lib.items(query)] for item in objs: self.process_file(item)
def func(self, lib, opts, args): """Command handler for the bpsync function. """ move = ui.should_move(opts.move) pretend = opts.pretend write = ui.should_write(opts.write) query = ui.decargs(args) self.singletons(lib, query, move, pretend, write) self.albums(lib, query, move, pretend, write)
def mbsync_func(lib, opts, args): """Command handler for the mbsync function. """ move = opts.move pretend = opts.pretend write = opts.write query = ui.decargs(args) mbsync_singletons(lib, query, move, pretend, write) mbsync_albums(lib, query, move, pretend, write)
def fetch_func(lib, opts, args): self.config.set_args(opts) write = config['import']['write'].get(bool) for item in lib.items(ui.decargs(args)): log.info(u'echonest: {0} - {1}'.format(item.artist, item.title)) if self.config['force'] or self.requires_update(item): song = self.fetch_song(item) if song: self.apply_metadata(item, song, write)
def convert_func(self, lib, opts, args): if not opts.dest: opts.dest = self.config['dest'].get() if not opts.dest: raise ui.UserError(u'no convert destination set') opts.dest = util.bytestring_path(opts.dest) if not opts.threads: opts.threads = self.config['threads'].get(int) if self.config['paths']: path_formats = ui.get_path_formats(self.config['paths']) else: path_formats = ui.get_path_formats() if not opts.format: opts.format = self.config['format'].as_str().lower() pretend = opts.pretend if opts.pretend is not None else \ self.config['pretend'].get(bool) if not pretend: ui.commands.list_items(lib, ui.decargs(args), opts.album) if not (opts.yes or ui.input_yn(u"Convert? (Y/n)")): return if opts.album: albums = lib.albums(ui.decargs(args)) items = (i for a in albums for i in a.items()) if self.config['copy_album_art']: for album in albums: self.copy_album_art(album, opts.dest, path_formats, pretend) else: items = iter(lib.items(ui.decargs(args))) convert = [ self.convert_item(opts.dest, opts.keep_new, path_formats, opts.format, pretend) for _ in range(opts.threads) ] pipe = util.pipeline.Pipeline([items, convert]) pipe.run_parallel()
def func(self, lib, opts, args): self._log.debug("func called") self.library = lib # TODO: Allow querying for subset of library query = ui.decargs(args) results = self.perform_audit() print(json.dumps(results, ensure_ascii=False))
def func(lib, opts, args): # The "write to files" option corresponds to the # import_write config value. write = ui.should_write() for item in lib.items(ui.decargs(args)): self.fetch_item_lyrics( lib, item, write, opts.force_refetch or self.config['force'], ) if opts.printlyr and item.lyrics: ui.print_(item.lyrics)
def convert_func(lib, opts, args): dest = opts.dest if opts.dest is not None else \ config['convert']['dest'].get() if not dest: raise ui.UserError('no convert destination set') threads = opts.threads if opts.threads is not None else \ config['convert']['threads'].get(int) ui.commands.list_items(lib, ui.decargs(args), opts.album, None) if not ui.input_yn("Convert? (Y/n)"): return if opts.album: items = (i for a in lib.albums(ui.decargs(args)) for i in a.items()) else: items = lib.items(ui.decargs(args)) convert = [convert_item(lib, dest) for i in range(threads)] pipe = util.pipeline.Pipeline([items, convert]) pipe.run_parallel()
def func(lib, opts, args): args = ui.decargs(args) if args: self.config['host'] = args.pop(0) if args: self.config['port'] = int(args.pop(0)) app.config['lib'] = lib app.run(host=self.config['host'].get(unicode), port=self.config['port'].get(int), debug=opts.debug, threaded=True)
def func(self, lib, opts, args): """Command handler for the mbsync function. """ move = opts.move pretend = opts.pretend write = opts.write query = ui.decargs(args) fmt = opts.format self.singletons(lib, query, move, pretend, write, fmt) self.albums(lib, query, move, pretend, write, fmt)
def list_func(lib, config, opts, args): fmt = opts.format if not fmt: # If no format is specified, fall back to a default. if opts.album: fmt = ui.config_val(config, 'beets', 'list_format_album', DEFAULT_LIST_FORMAT_ALBUM) else: fmt = ui.config_val(config, 'beets', 'list_format_item', DEFAULT_LIST_FORMAT_ITEM) list_items(lib, decargs(args), opts.album, opts.path, fmt)
def func(lib, opts, args): # The "write to files" option corresponds to the # import_write config value. write = config['import']['write'].get(bool) for item in lib.items(ui.decargs(args)): self.fetch_item_lyrics( lib, logging.INFO, item, write, opts.force_refetch or self.config['force'], ) if opts.printlyr and item.lyrics: ui.print_(item.lyrics)
def command(self, lib, opts, args): write = ui.should_write() items = lib.items(ui.decargs(args)) total_items = len(items) for num, item in enumerate(items): self._log.info(u'{0}/{1} {2}', num + 1, total_items, util.displayable_path(item.path)) new_comments = self.build_structured_comment(item) self._log.info(u'{0}', new_comments) if not opts.dry_run: if new_comments != item.comments or opts.force: self.write_structured_comment(item, new_comments, write)
def handle_common_args(self, opts, args): self.config.set_args(opts) query = ui.decargs(args) if query: self.config["query"] = query self._log.debug(f'Using base query {" ".join(query)}') base_query, _ = library.parse_query_parts(query, library.Item) else: query = self.config["query"].as_str() self._log.debug(f"Using base query {query}") base_query, _ = library.parse_query_string(query, library.Item) self.base_query = base_query
def modify_func(lib, config, opts, args): args = decargs(args) mods = [a for a in args if '=' in a] query = [a for a in args if '=' not in a] if not mods: raise ui.UserError('no modifications specified') write = opts.write if opts.write is not None else \ ui.config_val(config, 'beets', 'import_write', DEFAULT_IMPORT_WRITE, bool) color = ui.config_val(config, 'beets', 'color', DEFAULT_COLOR, bool) modify_items(lib, mods, query, write, opts.move, opts.album, color, not opts.yes)
def list_tracks(self, lib, options): if options.format is not None: fmt, = decargs([options.format]) beets.config[beets.library.Item._format_config_key].set(fmt) alt = self.alternative(options.name, lib) # This is slow but we cannot use a native SQL query since the # path key is a flexible attribute for item in lib.items(): if alt.path_key in item: print_(format(item))
def command(self, lib, opts, args): # Get items from arguments items = lib.items(ui.decargs(args)) if sys.version_info[0] < 3: for item in items: self.analyze_submit(item) else: # Analyze in parallel using a thread pool. pool = ThreadPool() pool.map(self.analyze_submit, items) pool.close() pool.join()
def unidecode_list(self, lib, opts, args): """Emulate normal 'list' command but with unidecode output.""" query = decargs(args) album = opts.album # Copied from commands.py - list_items if album: for album in lib.albums(query): bare = unidecode(str(album)) print_(bare) else: for item in lib.items(query): bare = unidecode(str(item)) print_(bare)
def func(lib, config, opts, args): # The "write to files" option corresponds to the # import_write config value. if not _echonest_apikey: raise ui.UserError('no EchoNest user API key provided') write = ui.config_val(config, 'beets', 'import_write', commands.DEFAULT_IMPORT_WRITE, bool) for item in lib.items(ui.decargs(args)): fetch_item_tempo(lib, logging.INFO, item, write) if opts.printlyr and item.bpm: ui.print_(item.bpm)
def embed_func(lib, opts, args): if opts.file: imagepath = normpath(opts.file) if not os.path.isfile(syspath(imagepath)): raise ui.UserError(u'image file {0} not found'.format( displayable_path(imagepath))) for item in lib.items(decargs(args)): art.embed_item(self._log, item, imagepath, maxwidth, None, compare_threshold, ifempty) else: for album in lib.albums(decargs(args)): art.embed_album(self._log, album, maxwidth, False, compare_threshold, ifempty) if remove_art_file and album.artpath is not None: if os.path.isfile(album.artpath): self._log.debug( u'Removing album art file ' u'for {0}', album) os.remove(album.artpath) album.artpath = None album.store()
def convert_func(lib, opts, args): if not opts.dest: opts.dest = config['convert']['dest'].get() if not opts.dest: raise ui.UserError('no convert destination set') opts.dest = util.bytestring_path(opts.dest) if not opts.threads: opts.threads = config['convert']['threads'].get(int) if config['convert']['paths']: path_formats = ui.get_path_formats(config['convert']['paths']) else: path_formats = ui.get_path_formats() if not opts.format: opts.format = config['convert']['format'].get(unicode).lower() command, ext = get_format(opts.format) pretend = opts.pretend if opts.pretend is not None else \ config['convert']['pretend'].get(bool) if not pretend: ui.commands.list_items(lib, ui.decargs(args), opts.album, None) if not ui.input_yn("Convert? (Y/n)"): return if opts.album: items = (i for a in lib.albums(ui.decargs(args)) for i in a.items()) else: items = iter(lib.items(ui.decargs(args))) convert = [ convert_item(opts.dest, opts.keep_new, path_formats, command, ext, pretend) for _ in range(opts.threads) ] pipe = util.pipeline.Pipeline([items, convert]) pipe.run_parallel()
def func(self, lib: Library, options, arguments): self.lib = lib self.query = decargs(arguments) # You must either pass a training name or request listing if len(self.query) < 1 and not options.version: self.parser.print_help() return if options.version: self.show_version_information() return self.handle_display()
def func(lib, opts, args): """Hook the arguments of the configuration-file.""" args = ui.decargs(args) if args: self.config['host'] = args.pop(0) if args: self.config['port'] = int(args.pop(0)) app.config['lib'] = lib # Start the Web-FrontEnd Plugin. app.run(host=self.config['host'].get(unicode), port=self.config['port'].get(int), debug=True, threaded=True)
def commands(self): """ Return the "userrating" ui subcommand. """ cmd = ui.Subcommand('userrating', help=u'manage user ratings for tracks') cmd.func = lambda lib, opts, args: self.handle_tracks( lib.items(ui.decargs(args)), opts) cmd.parser.add_option( u'-u', u'--update', action='store', help=u'all files will be rated with given value', ) cmd.parser.add_option( u'-i', u'--imported', action='store_true', help= u'all files will be rated if possible with known players value in file', ) cmd.parser.add_option( u'-o', u'--overwrite', action='store_true', help= u'allow overwriting rated file (default is to skip already rated file)', ) cmd.parser.add_option( u'-s', u'--sync', action='store', help= u'write rating for existing players rating (default is to not update any players rating but beets)', ) cmd.parser.add_option( u'-a', u'--all', action='store_true', help= u'write rating for all known players (default is to not update any players rating but beets)', ) cmd2 = ui.Subcommand('ratingsfile', help=u'write library ratings to playlist file') cmd2.func = lambda lib, opts, args: self.write_ratings_file(lib) return [cmd, cmd2]
def random_func(lib, opts, args): """Select some random items or albums and print the results. """ # Fetch all the objects matching the query into a list. query = decargs(args) if opts.album: objs = list(lib.albums(query)) else: objs = list(lib.items(query)) # Print a random subset. objs = random_objs(objs, opts.album, opts.number, opts.time, opts.equal_chance) for obj in objs: print_(format(obj))