diff --git a/beetsplug/info.py b/beetsplug/info.py index 87e21f916..3bd1a10fe 100644 --- a/beetsplug/info.py +++ b/beetsplug/info.py @@ -23,7 +23,51 @@ from beets import mediafile from beets import util -def info(paths): +def run(lib, opts, args): + """Print tag info 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. + """ + paths, query = parse_args(args) + + first = True + for path in paths: + if not first: + ui.print_() + print_tags(path) + first = False + + if not query: + return + + for item in lib.items(*query): + if not first: + ui.print_() + print_tags(item.path) + first = False + + +def parse_args(args): + """Split `args` into a tuple of paths and querys. + """ + if not args: + raise ui.UserError('no file specified') + paths = [] + query = [] + for arg in args: + if os.sep in arg and os.path.exists(arg): + paths.append(util.normpath(arg)) + else: + query.append(arg) + return paths, query + + +def print_tags(path): # Set up fields to output. fields = list(mediafile.MediaFile.readable_fields()) fields.remove('art') @@ -34,43 +78,25 @@ def info(paths): maxwidth = max(len(name) for name in fields + other_fields) lineformat = u'{{0:>{0}}}: {{1}}'.format(maxwidth) - first = True - for path in paths: - if not first: - ui.print_() + ui.print_(path) + try: + mf = mediafile.MediaFile(path) + except mediafile.UnreadableFileError: + ui.print_('cannot read file: {0}'.format( + util.displayable_path(path) + )) + return - path = util.normpath(path) - if not os.path.isfile(path): - ui.print_(u'not a file: {0}'.format( - util.displayable_path(path) - )) - continue - ui.print_(path) - try: - mf = mediafile.MediaFile(path) - except mediafile.UnreadableFileError: - ui.print_('cannot read file: {0}'.format( - util.displayable_path(path) - )) - continue - - # Basic fields. - for name in fields: - ui.print_(lineformat.format(name, getattr(mf, name))) - # Extra stuff. - ui.print_(lineformat.format('album art', mf.art is not None)) - - first = False + # Basic fields. + for name in fields: + ui.print_(lineformat.format(name, getattr(mf, name))) + # Extra stuff. + ui.print_(lineformat.format('album art', mf.art is not None)) class InfoPlugin(BeetsPlugin): def commands(self): cmd = ui.Subcommand('info', help='show file metadata') - - def func(lib, opts, args): - if not args: - raise ui.UserError('no file specified') - info(args) - cmd.func = func + cmd.func = run return [cmd] diff --git a/docs/changelog.rst b/docs/changelog.rst index 9805db98c..5b7802cab 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -6,6 +6,9 @@ Changelog This release adds **sorting** to beets queries. See :ref:`query-sort`. +Features: +* :doc:`/plugins/info`: Files can be specified through library queries. + Fixes: * Invalid state files don't crash the importer. diff --git a/test/helper.py b/test/helper.py index bfbd378d0..2e7732ede 100644 --- a/test/helper.py +++ b/test/helper.py @@ -80,12 +80,13 @@ def capture_stdout(): 'spam' """ org = sys.stdout - sys.stdout = StringIO() + sys.stdout = capture = StringIO() sys.stdout.encoding = 'utf8' try: yield sys.stdout finally: sys.stdout = org + print(capture.getvalue()) def has_program(cmd, args=['--version']): @@ -289,6 +290,11 @@ class TestHelper(object): lib = Library(':memory:') beets.ui._raw_main(list(args), lib) + def run_with_output(self, *args): + with capture_stdout() as out: + self.run_command(*args) + return out.getvalue() + def create_temp_dir(self): """Create a temporary directory and assign it into `self.temp_dir`. Call `remove_temp_dir` later to delete it.