mirror of
https://github.com/beetbox/beets.git
synced 2026-01-15 12:41:22 +01:00
plugin hooks for template functions (#231)
This commit is contained in:
parent
dd4ee6b2e4
commit
f1ebc82a55
4 changed files with 69 additions and 16 deletions
|
|
@ -817,7 +817,9 @@ class Library(BaseLibrary):
|
|||
mapping['albumartist'] = mapping['artist']
|
||||
|
||||
# Perform substitution.
|
||||
subpath = subpath_tmpl.substitute(mapping, TEMPLATE_FUNCTIONS)
|
||||
funcs = dict(TEMPLATE_FUNCTIONS)
|
||||
funcs.update(plugins.template_funcs())
|
||||
subpath = subpath_tmpl.substitute(mapping, funcs)
|
||||
|
||||
# Encode for the filesystem, dropping unencodable characters.
|
||||
if isinstance(subpath, unicode) and not fragment:
|
||||
|
|
|
|||
|
|
@ -104,6 +104,21 @@ class BeetsPlugin(object):
|
|||
return func
|
||||
return helper
|
||||
|
||||
template_funcs = None
|
||||
|
||||
@classmethod
|
||||
def template_func(cls, name):
|
||||
"""Decorator that registers a path template function. The
|
||||
function will be invoked as ``%name{}`` from path format
|
||||
strings.
|
||||
"""
|
||||
def helper(func):
|
||||
if cls.template_funcs is None:
|
||||
cls.template_funcs = {}
|
||||
cls.template_funcs[name] = func
|
||||
return func
|
||||
return helper
|
||||
|
||||
def load_plugins(names=()):
|
||||
"""Imports the modules for a sequence of plugin names. Each name
|
||||
must be the name of a Python module under the "beetsplug" namespace
|
||||
|
|
@ -195,6 +210,16 @@ def configure(config):
|
|||
for plugin in find_plugins():
|
||||
plugin.configure(config)
|
||||
|
||||
def template_funcs():
|
||||
"""Get all the template functions declared by plugins as a
|
||||
dictionary.
|
||||
"""
|
||||
funcs = {}
|
||||
for plugin in find_plugins():
|
||||
if plugin.template_funcs:
|
||||
funcs.update(plugin.template_funcs)
|
||||
return funcs
|
||||
|
||||
|
||||
# Event dispatch.
|
||||
|
||||
|
|
|
|||
|
|
@ -274,10 +274,10 @@ def config_val(config, section, name, default, vtype=None):
|
|||
return config.getboolean(section, name)
|
||||
elif vtype is list:
|
||||
# Whitespace-separated strings.
|
||||
strval = config.get(section, name)
|
||||
strval = config.get(section, name, True)
|
||||
return strval.split()
|
||||
else:
|
||||
return config.get(section, name)
|
||||
return config.get(section, name, True)
|
||||
except ConfigParser.NoOptionError:
|
||||
return default
|
||||
|
||||
|
|
@ -637,7 +637,7 @@ def main(args=None, configfh=None):
|
|||
# If no legacy path format, use the defaults instead.
|
||||
path_formats = DEFAULT_PATH_FORMATS
|
||||
if config.has_section('paths'):
|
||||
path_formats.update(config.items('paths'))
|
||||
path_formats.update(config.items('paths', True))
|
||||
art_filename = \
|
||||
config_val(config, 'beets', 'art_filename', DEFAULT_ART_FILENAME)
|
||||
lib_timeout = config_val(config, 'beets', 'timeout', DEFAULT_TIMEOUT)
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
Plugins
|
||||
=======
|
||||
|
||||
As of the 1.0b3 release, beets started supporting plugins to modularize its
|
||||
functionality and allow other developers to add new functionality. Plugins can
|
||||
add new commands to the command-line interface, respond to events in beets, and
|
||||
augment the autotagger.
|
||||
Plugins can extend beets' core functionality. Plugins can add new commands to
|
||||
the command-line interface, respond to events in beets, augment the autotagger,
|
||||
or provide new path template functions.
|
||||
|
||||
Using Plugins
|
||||
-------------
|
||||
|
|
@ -169,10 +168,10 @@ like you would a normal ``OptionParser`` in an independent script.
|
|||
Listen for Events
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
As of beets 1.0b5, plugins can also define event handlers. Event handlers allow
|
||||
you to run code whenever something happens in beets' operation. For instance, a
|
||||
plugin could write a log message every time an album is successfully autotagged
|
||||
or update MPD's index whenever the database is changed.
|
||||
Event handlers allow plugins to run code whenever something happens in beets'
|
||||
operation. For instance, a plugin could write a log message every time an album
|
||||
is successfully autotagged or update MPD's index whenever the database is
|
||||
changed.
|
||||
|
||||
You can "listen" for events using the ``BeetsPlugin.listen`` decorator. Here's
|
||||
an example::
|
||||
|
|
@ -210,7 +209,7 @@ The included ``mpdupdate`` plugin provides an example use case for event listene
|
|||
Extend the Autotagger
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Plugins in 1.0b5 can also enhance the functionality of the autotagger. For a
|
||||
Plugins in can also enhance the functionality of the autotagger. For a
|
||||
comprehensive example, try looking at the ``chroma`` plugin, which is included
|
||||
with beets.
|
||||
|
||||
|
|
@ -223,19 +222,22 @@ methods on the plugin class:
|
|||
|
||||
* ``track_distance(self, item, info)``: adds a component to the distance
|
||||
function (i.e., the similarity metric) for individual tracks. ``item`` is the
|
||||
track to be matched (and Item object) and ``info`` is the !MusicBrainz track
|
||||
track to be matched (and Item object) and ``info`` is the MusicBrainz track
|
||||
entry that is proposed as a match. Should return a ``(dist, dist_max)`` pair
|
||||
of floats indicating the distance.
|
||||
|
||||
* ``album_distance(self, items, info)``: like the above, but compares a list of
|
||||
items (representing an album) to an album-level !MusicBrainz entry. Should
|
||||
items (representing an album) to an album-level MusicBrainz entry. Should
|
||||
only consider album-level metadata (e.g., the artist name and album title) and
|
||||
should not duplicate the factors considered by ``track_distance``.
|
||||
|
||||
* ``candidates(self, items)``: given a list of items comprised by an album to be
|
||||
matched, return a list of !MusicBrainz entries for candidate albums to be
|
||||
matched, return a list of ``AlbumInfo`` objects for candidate albums to be
|
||||
compared and matched.
|
||||
|
||||
* ``item_candidates(self, item)``: given a *singleton* item, return a list of
|
||||
``TrackInfo`` objects for candidate tracks to be compared and matched.
|
||||
|
||||
When implementing these functions, it will probably be very necessary to use the
|
||||
functions from the ``beets.autotag`` and ``beets.autotag.mb`` modules, both of
|
||||
which have somewhat helpful docstrings.
|
||||
|
|
@ -254,3 +256,27 @@ values from the config file. Like so::
|
|||
|
||||
Try looking at the ``mpdupdate`` plugin (included with beets) for an example of
|
||||
real-world use of this API.
|
||||
|
||||
Add Path Format Functions
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
As of 1.0b12, beets supports *function calls* in its path format syntax (see
|
||||
:doc:`/reference/pathformat`. Beets includes a few built-in functions, but
|
||||
plugins can add new functions using the ``template_func`` decorator. To use it,
|
||||
decorate a function with ``MyPlugin.template_func("name")`` where ``name`` is
|
||||
the name of the function as it should appear in template strings.
|
||||
|
||||
Here's an example::
|
||||
|
||||
class MyPlugin(BeetsPlugin):
|
||||
pass
|
||||
@MyPlugin.template_func('initial')
|
||||
def _tmpl_initial(text):
|
||||
if text:
|
||||
return text[0].upper()
|
||||
else:
|
||||
return u''
|
||||
|
||||
This plugin provides a function ``%initial`` to path templates where
|
||||
``%initial{$artist}`` expands to the artist's initial (its capitalized first
|
||||
character).
|
||||
|
|
|
|||
Loading…
Reference in a new issue