diff --git a/beetsplug/inline.py b/beetsplug/inline.py index 81a003cb7..88628f900 100644 --- a/beetsplug/inline.py +++ b/beetsplug/inline.py @@ -46,7 +46,7 @@ def _compile_func(body): eval(code, env) return env[FUNC_NAME] -def compile_inline(python_code): +def compile_inline(python_code, album): """Given a Python expression or function body, compile it as a path field function. The returned function takes a single argument, an Item, and returns a Unicode string. If the expression cannot be @@ -68,10 +68,18 @@ def compile_inline(python_code): else: is_expr = True + def _dict_for(obj): + if album: + out = dict(obj._record) + out['items'] = list(obj.items()) + return out + else: + return dict(obj.record) + if is_expr: # For expressions, just evaluate and return the result. - def _expr_func(item): - values = dict(item.record) + def _expr_func(obj): + values = _dict_for(obj) try: return eval(code, values) except Exception as exc: @@ -80,8 +88,8 @@ def compile_inline(python_code): else: # For function bodies, invoke the function with values as global # variables. - def _func_func(item): - func.__globals__.update(item.record) + def _func_func(obj): + func.__globals__.update(_dict_for(obj)) try: return func() except Exception as exc: @@ -94,11 +102,18 @@ class InlinePlugin(BeetsPlugin): config.add({ 'pathfields': {}, + 'album_fields': {}, }) # Add field expressions. for key, view in config['pathfields'].items(): - log.debug(u'adding template field %s' % key) - func = compile_inline(view.get(unicode)) + log.debug(u'inline: adding item field %s' % key) + func = compile_inline(view.get(unicode), False) if func is not None: self.template_fields[key] = func + + for key, view in config['album_fields'].items(): + log.debug(u'inline: adding album field %s' % key) + func = compile_inline(view.get(unicode), True) + if func is not None: + self.album_template_fields[key] = func diff --git a/docs/changelog.rst b/docs/changelog.rst index a554c2005..2c42d65b1 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -31,8 +31,9 @@ Changelog Thanks to jayme on GitHub. * :doc:`/plugins/lyrics`: Lyrics searches should now turn up more results due to some fixes in dealing with special characters. -* Plugins can now provide fields for both Album and Item templates. Thanks - to Pedro Silva. +* Plugins can now provide fields for both Album and Item templates, thanks + to Pedro Silva. Accordingly, the :doc:`/plugins/inline` can also now define + album fields. * The :ref:`fields-cmd` command shows template fields provided by plugins. Thanks again to Pedro Silva. * Album art filenames now respect the :ref:`replace` configuration. diff --git a/docs/plugins/inline.rst b/docs/plugins/inline.rst index 2998de9fc..a98f52cd6 100644 --- a/docs/plugins/inline.rst +++ b/docs/plugins/inline.rst @@ -31,6 +31,10 @@ referenced in path templates like so:: paths: default: $initial/$artist/$album%aunique{}/$disc_and_track $title + +Function Fields +--------------- + If you need to use statements like ``import``, you can write a Python function body instead of a single expression. In this case, you'll need to ``return`` a result for the value of the path field, like so:: @@ -43,3 +47,22 @@ a result for the value of the path field, like so:: You might want to use the YAML syntax for "block literals," in which a leading ``|`` character indicates a multi-line block of text. + + +Album Fields +------------ + +The above examples define fields for *item* templates, but you can also define +fields for *album* templates. Use the ``album_fields`` configuration section. +In this context, all existing album fields are available as variables along +with ``items``, which is a list of items in the album. + +This example defines a ``$bitrate`` field for albums as the average of the +tracks' fields:: + + album_fields: + bitrate: | + total = 0 + for item in items: + total += item.bitrate + return total / len(items)