From 2f8370669e15014a3d5ba9a82ca3a30aba7c8f7f Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Sat, 17 Sep 2011 11:04:51 -0700 Subject: [PATCH] translate plugin documentation --- docs/guides/index.rst | 4 +- docs/guides/main.rst | 2 +- docs/index.rst | 1 + docs/plugins/bpd.rst | 125 +++++++++++++++++++ docs/plugins/embedart.rst | 46 +++++++ docs/plugins/index.rst | 248 +++++++++++++++++++++++++++++++++++++ docs/plugins/lastid.rst | 65 ++++++++++ docs/plugins/mpdupdate.rst | 24 ++++ 8 files changed, 512 insertions(+), 3 deletions(-) create mode 100644 docs/plugins/bpd.rst create mode 100644 docs/plugins/embedart.rst create mode 100644 docs/plugins/index.rst create mode 100644 docs/plugins/lastid.rst create mode 100644 docs/plugins/mpdupdate.rst diff --git a/docs/guides/index.rst b/docs/guides/index.rst index dd7a42151..4d03b9b79 100644 --- a/docs/guides/index.rst +++ b/docs/guides/index.rst @@ -1,5 +1,5 @@ -Introduction -============ +Guides +====== Tutorial stuff diff --git a/docs/guides/main.rst b/docs/guides/main.rst index 1a5720d97..28ec70a9d 100644 --- a/docs/guides/main.rst +++ b/docs/guides/main.rst @@ -171,7 +171,7 @@ also implicitly joined by ANDs: a track must match *all* criteria in order to match the query.) To narrow a search term to a particular metadata field, just put the field before the term, separated by a : character. So ``album:bird`` only looks for ``bird`` in the "album" field of your songs. (Need to know more? -:doc:`/ref/queries/` will answer all your questions.) +:doc:`/reference/query/` will answer all your questions.) The ``beet list`` command has another useful option worth mentioning, ``-a``, which searches for albums instead of songs:: diff --git a/docs/index.rst b/docs/index.rst index d4ab925bd..0c7de5497 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -11,3 +11,4 @@ Contents guides/index reference/index + plugins/index diff --git a/docs/plugins/bpd.rst b/docs/plugins/bpd.rst new file mode 100644 index 000000000..5d30781d5 --- /dev/null +++ b/docs/plugins/bpd.rst @@ -0,0 +1,125 @@ +BPD Plugin +========== + +BPD is a music player using music from a beets library. It runs as a daemon and +implements the MPD protocol, so it's compatible with all the great MPD clients +out there. I'm using `Theremin`_, `gmpc`_, `Sonata`_, and `Ario`_ successfully. + +.. _Theremin: https://theremin.sigterm.eu/ +.. _gmpc: http://gmpc.wikia.com/wiki/Gnome_Music_Player_Client +.. _Sonata: http://sonata.berlios.de/ +.. _Ario: http://ario-player.sourceforge.net/ + +Dependencies +------------ + +Before you can use BPD, you'll need the media library called GStreamer (along +with its Python bindings) on your system. + +* On Mac OS X, you should use `MacPorts`_ and run ``port install + py26-gst-python``. (Note that you'll almost certainly need the Mac OS X + Developer Tools.) + +* On Linux, it's likely that you already have gst-python. (If not, your + distribution almost certainly has a package for it.) + +* On Windows, you may want to try `GStreamer WinBuilds`_ (cavet emptor: I + haven't tried this). + +.. _MacPorts: http://www.macports.org/ +.. _GStreamer WinBuilds: http://www.gstreamer-winbuild.ylatuya.es/ + +Using and Configuring +--------------------- + +BPD is a plugin for beets. It comes with beets, but it's disabled by default. To +enable it, you'll need to edit your ``.beetsconfig`` file and add the line +``plugins: bpd``. Like so:: + + [beets] + plugins: bpd + +Then, you can run BPD by invoking:: + + $ beet bpd + +Fire up your favorite MPD client to start playing music. The MPD site has `a +long list of available clients`_. Here are my favorites: + +.. _a long list of available clients: http://mpd.wikia.com/wiki/Clients + +* Linux: `gmpc`_, `Sonata`_ + +* Mac: `Theremin`_ + +* Windows: I don't know. Get in touch if you have a recommendation. + +* iPhone/iPod touch: `MPoD`_ + +.. _MPoD: http://www.katoemba.net/makesnosenseatall/mpod/ + +One nice thing about MPD's (and thus BPD's) client-server architecture is that +the client can just as easily on a different computer from the server as it can +be run locally. Control your music from your laptop (or phone!) while it plays +on your headless server box. Rad! + +To configure the BPD server, add a ``[bpd]`` section to your ``.beetsconfig`` +file. The configuration values, which are pretty self-explanatory, are ``host``, +``port``, and ``password``. Here's an example:: + + [bpd] + host: 127.0.0.1 + port: 6600 + password: seekrit + +Implementation Notes +-------------------- + +In the real MPD, the user can browse a music directory as it appears on disk. In +beets, we like to abstract away from the directory structure. Therefore, BPD +creates a "virtual" directory structure (artist/album/track) to present to +clients. This is static for now and cannot be reconfigured like the real on-disk +directory structure can. (Note that an obvious solution to this is just string +matching on items' destination, but this requires examining the entire library +Python-side for every query.) + +We don't currently support versioned playlists. Many clients, however, use +plchanges instead of playlistinfo to get the current playlist, so plchanges +contains a dummy implementation that just calls playlistinfo. + +The ``stats`` command always send zero for ``playtime``, which is supposed to +indicate the amount of time the server has spent playing music. BPD doesn't +currently keep track of this. Also, because database updates aren't yet +supported, ``db_update`` is just the time the server was started. + +Unimplemented Commands +---------------------- + +These are the commands from `the MPD protocol`_ that have not yet been +implemented in BPD. + +.. _the MPD protocol: http://mpd.wikia.com/wiki/MusicPlayerDaemonCommands + +Database: + +* update + +Saved playlists: + +* playlistclear +* playlistdelete +* playlistmove +* playlistadd +* playlistsearch +* listplaylist +* listplaylistinfo +* playlistfind +* rm +* save +* load +* rename + +Deprecated: + +* playlist +* volume diff --git a/docs/plugins/embedart.rst b/docs/plugins/embedart.rst new file mode 100644 index 000000000..ee5a8363d --- /dev/null +++ b/docs/plugins/embedart.rst @@ -0,0 +1,46 @@ +EmbedArt Plugin +=============== + +Typically, beets stores album art in a "file on the side": along with each +album, there is a file (named "cover.jpg" by default) that stores the album art. +You might want to embed the album art directly into each file's metadata. While +this will take more space than the external-file approach, it is necessary for +displaying album art in some media players (iPods, for example). + +This plugin was added in beets 1.0b8. + +Embedding Art Automatically +--------------------------- + +To automatically embed discovered album art into imported files, just +:doc:`enable the plugin `. Art will be embedded after each album +is added to the library. + +This behavior can be disabled with the ``autoembed`` config option (see below). + +Manually Embedding and Extracting Art +------------------------------------- + +The ``embedart`` plugin provides a couple of commands for manually managing +embedded album art: + +* ``beet embedart IMAGE QUERY``: given an image file and a query matching an + album, embed the image into the metadata of every track on the album. + +* ``beet extractart [-o FILE] QUERY``: extracts the image from an item matching + the query and stores it in a file. You can specify the destination file using + the ``-o`` option, but leave off the extension: it will be chosen + automatically. The destination filename defaults to ``cover`` if it's not + specified. + +* ``beet clearart QUERY``: removes all embedded images from all items matching + the query. (Use with caution!) + +Configuring +----------- + +The plugin has one configuration option, ``autoembed``, which lets you disable +automatic album art embedding. To do so, add this to your ``~/.beetsconfig``:: + + [embedart] + autoembed: no diff --git a/docs/plugins/index.rst b/docs/plugins/index.rst new file mode 100644 index 000000000..bc48ad19f --- /dev/null +++ b/docs/plugins/index.rst @@ -0,0 +1,248 @@ +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. + +Using Plugins +------------- + +To use a plugin, you have two options: + +* Make sure it's in the Python path (known as `sys.path` to developers). This + just means the plugin has to be installed on your system (e.g., with a + `setup.py` script or a command like `pip` or `easy_install`). + +* Set the `pythonpath` config variable to point to the directory containing the + plugin. (See :doc:`/reference/cli`.) + +Then, set the `plugins` option in your `~/.beetsconfig` file, like so:: + + [beets] + plugins = mygreatplugin someotherplugin + +The value for `plugins` should be a space-separated list of plugin module names. + +.. _included-plugins: + +Plugins Included With Beets +--------------------------- + +There are a few plugins that are included with the beets distribution. They're +disabled by default, but you can turn them on as described above: + +.. toctree:: + :maxdepth: 1 + + lastid + bpd + mpdupdate + embedart + +.. _other-plugins: + +Other Plugins +------------- + +Here are a few of the plugins written by the beets community: + +* `beets-replaygain`_ can analyze and store !ReplayGain normalization + information. + +* `beets-lyrics`_ searches Web repositories for song lyrics and adds them to your files. + +* `beetFs`_ is a FUSE filesystem for browsing the music in your beets library. + (Might be out of date.) + +* `Beet-MusicBrainz-Collection`_ lets you add albums from your library to your + !MusicBrainz `"music collection"`_. + +* `A cmus plugin`_ integrates with the `cmus`_ console music player. + +.. _beets-replaygain: https://github.com/Lugoues/beets-replaygain/ +.. _beets-lyrics: https://github.com/Lugoues/beets-lyrics/ +.. _beetFs: http://code.google.com/p/beetfs/ +.. _Beet-MusicBrainz-Collection: + https://github.com/jeffayle/Beet-MusicBrainz-Collection/ +.. _"music collection": http://musicbrainz.org/show/collection/ +.. _A cmus plugin: + https://github.com/coolkehon/beets/blob/master/beetsplug/cmus.py +.. _cmus: http://cmus.sourceforge.net/ + +Writing Plugins +--------------- + +A beets plugin is just a Python module inside the ``beetsplug`` namespace +package. (Check out this `Stack Overflow question about namespace packages`_ if +you haven't heard of them.) So, to make one, create a directory called +``beetsplug`` and put two files in it: one called ``__init__.py`` and one called +``myawesomeplugin.py`` (but don't actually call it that). Your directory +structure should look like this:: + + beetsplug/ + __init__.py + myawesomeplugin.py + +.. _Stack Overflow question about namespace packages: + http://stackoverflow.com/questions/1675734/how-do-i-create-a-namespace-package-in-python/1676069#1676069 + +Then, you'll need to put this stuff in ``__init__.py`` to make ``beetsplug`` a +namespace package:: + + from pkgutil import extend_path + __path__ = extend_path(__path__, __name__) + +That's all for ``__init__.py``; you can can leave it alone. The meat of your +plugin goes in ``myawesomeplugin.py``. There, you'll have to import the +``beets.plugins`` module and define a subclass of the ``BeetsPlugin`` class +found therein. Here's a skeleton of a plugin file:: + + from beets.plugins import BeetsPlugin + + class MyPlugin(BeetsPlugin): + pass + +Once you have your ``BeetsPlugin`` subclass, there's a variety of things your +plugin can do. (Read on!) + +To use your new plugin, make sure your ``beetsplug`` directory is in the Python +path (using ``PYTHONPATH`` or by installing in a `virtualenv`_, for example). +Then, as described above, edit your ``.beetsconfig`` to include +``plugins=myawesomeplugin`` (substituting the name of the Python module +containing your plugin). + +.. _virtualenv: http://pypi.python.org/pypi/virtualenv + +Add Commands to the CLI +^^^^^^^^^^^^^^^^^^^^^^^ + +Plugins can add new subcommands to the ``beet`` command-line interface. Define +the plugin class' ``commands()`` method to return a list of ``Subcommand`` +objects. (The ``Subcommand`` class is defined in the ``beets.ui`` module.) +Here's an example plugin that adds a simple command:: + + from beets.plugins import BeetsPlugin + from beets.ui import Subcommand + + my_super_command = Subcommand('super', help='do something super') + def say_hi(lib, config, opts, args): + print "Hello everybody! I'm a plugin!" + my_super_command.func = say_hi + + class SuperPlug(BeetsPlugin): + def commands(self): + return [my_super_command] + +To make a subcommand, invoke the constructor like so: ``Subcommand(name, parser, +help, aliases)``. The ``name`` parameter is the only required one and should +just be the name of your command. ``parser`` can be an `OptionParser instance`_, +but it defaults to an empty parser (you can extend it later). ``help`` is a +description of your command, and ``aliases`` is a list of shorthand versions of +your command name. + +.. _OptionParser instance: http://docs.python.org/library/optparse.html + +You'll need to add a function to your command by saying ``mycommand.func = +myfunction``. This function should take the following parameters: ``lib`` (a +beets ``Library`` object), ``config`` (a `ConfigParser object`_ containing the +configuration values), and ``opts`` and ``args`` (command-line options and +arguments as returned by `OptionParser.parse_args`_). + +.. _ConfigParser object: http://docs.python.org/library/configparser.html +.. _OptionParser.parse_args: + http://docs.python.org/library/optparse.html#parsing-arguments + +The function should use any of the utility functions defined in ``beets.ui``. +Try running ``pydoc beets.ui`` to see what's available. + +You can add command-line options to your new command using the ``parser`` member +of the ``Subcommand`` class, which is an ``OptionParser`` instance. Just use it +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. + +You can "listen" for events using the ``BeetsPlugin.listen`` decorator. Here's +an example:: + + from beets.plugins import BeetsPlugin + + class SomePlugin(BeetsPlugin): + pass + + @SomePlugin.listen('pluginload') + def loaded(): + print 'Plugin loaded!' + +Pass the name of the event in question to the ``listen`` decorator. The events +currently available are: + +* *pluginload*: called after all the plugins have been loaded after the ``beet`` + command starts + +* *save*: called whenever the library is changed and written to disk (the + ``lib`` keyword argument is the Library object that was written) + +* *import*: called after a ``beet import`` command fishes (the ``lib`` keyword + argument is a Library object; ``paths`` is a list of paths (strings) that were + imported) + +* *album_imported*: called with an ``Album`` object every time the ``import`` + command finishes adding an album to the library + +The included ``mpdupdate`` plugin provides an example use case for event listeners. + +Extend the Autotagger +^^^^^^^^^^^^^^^^^^^^^ + +Plugins in 1.0b5 can also enhance the functionality of the autotagger. For a +comprehensive example, try looking at the ``lastid`` plugin, which is included +with beets. + +A plugin can extend three parts of the autotagger's process: the track distance +function, the album distance function, and the initial MusicBrainz search. The +distance functions determine how "good" a match is at the track and album +levels; the initial search controls which candidates are presented to the +matching algorithm. Plugins implement these extensions by implementing three +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 + 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 + 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 + 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. + +Read Configuration Options +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Plugins can configure themselves using the ``.beetsconfig`` file. Define a +``configure`` method on your plugin that takes an ``OptionParser`` object as an +argument. Then use the ``beets.ui.config_val`` convenience function to access +values from the config file. Like so:: + + class MyPlugin(BeetsPlugin): + def configure(self, config): + number_of_goats = beets.ui.config_val(config, 'myplug', 'goats', '42') + +Try looking at the ``mpdupdate`` plugin (included with beets) for an example of +real-world use of this API. diff --git a/docs/plugins/lastid.rst b/docs/plugins/lastid.rst new file mode 100644 index 000000000..ce29eab6b --- /dev/null +++ b/docs/plugins/lastid.rst @@ -0,0 +1,65 @@ +LastID Plugin +============= + +Acoustic fingerprinting is a technique for identifying songs from the way they +"sound" rather from their existing metadata. That means that beets' autotagger +can theoretically use fingerprinting to tag files that don't have any ID3 +information at all (or have completely incorrect data). The MusicBrainz project +currently uses a fingerprinting technology called PUIDs, but beets uses a +different fingerprinting algorithm provided by `Last.fm`_. + +.. _Last.fm: http://last.fm/ + +Turning on fingerprinting can increase the accuracy of the +autotagger---especially on files with very poor metadata---but it comes at a +cost. First, it can be trickier to set up than beets itself (you need to compile +the fingerprinting code, whereas all of the beets core is written in Python). +Also, fingerprinting takes significantly more CPU and memory than ordinary +tagging---which means that imports will go substantially slower. + +If you're willing to pay the performance cost for fingerprinting, read on! + +Installing Dependencies +----------------------- + +To use lastid, you'll need to install the `pylastfp`_ fingerprinting library, +which has a few dependencies: `fftw`_, `libsamplerate`_, and `Gstreamer for +Python`_. How you install these will depend on your operating system. Here's a +few examples: + +.. _pylastfp: http://github.com/sampsyo/pylastfp +.. _fftw: http://www.fftw.org/ +.. _libsamplerate: http://www.mega-nerd.com/SRC/ +.. _Gstreamer for Python: + http://gstreamer.freedesktop.org/modules/gst-python.html + +* On Ubuntu, just run ``apt-get install libfftw3-dev libsamplerate0-dev + python-gst0.10-dev``. + +* On Arch Linux, you want + ``pacman -S fftw libsamplerate gstreamer0.10-python``. + +Let me know if you have a good source for installing the packages on Windows. + +To decode audio formats (MP3, FLAC, etc.), you'll need the standard set of +Gstreamer plugins. For example, on Ubuntu, install the packages +``gstreamer0.10-plugins-good``, ``gstreamer0.10-plugins-bad``, and +``gstreamer0.10-plugins-ugly``. + +Then, install pylastfp itself. You can do this using `pip`_, like so:: + + $ pip install pylastfp + +.. _pip: http://pip.openplans.org/ + +Using +----- + +Once you have all the dependencies sorted out, you can enable fingerprinting by +editing your :doc:`/reference/config`. Put ``lastid`` on your ``plugins:`` +line. Your config file should contain something like this:: + + [beets] + plugins: lastid + +With that, beets will use fingerprinting the next time you run ``beet import``. diff --git a/docs/plugins/mpdupdate.rst b/docs/plugins/mpdupdate.rst new file mode 100644 index 000000000..fda36e5b9 --- /dev/null +++ b/docs/plugins/mpdupdate.rst @@ -0,0 +1,24 @@ +MPDUpdate Plugin +================ + +``mpdupdate`` is a very simple plugin for beets that lets you automatically +update `MPD`_'s index whenever you change your beets library. The plugin is +included with beets as of version 1.0b5. + +.. _MPD: http://mpd.wikia.com/wiki/Music_Player_Daemon_Wiki + +To use it, enable it in your ``.beetsconfig`` by putting ``mpdupdate`` on your ``plugins`` line. Your ``.beetsconfig`` should look like this:: + + [beets] + plugins: mpdupdate + +Then, you'll probably want to configure the specifics of your MPD server. You +can do that using an ``[mpdupdate]`` section in your ``.beetsconfig``, which +looks like this:: + + [mpdupdate] + host = localhost + port = 6600 + password = seekrit + +With that all in place, you'll see beets send the "update" command to your MPD server every time you change your beets library.