Create echonest_tempo plugin - use EchoNest API to get tempo (bpm).

A simple plugin that connects to the EchoNest API to retrieve
tempo (bpm) metadata for tracks. Functions similarly to the lyrics
plugin.

Requires the pyechonest library.
This commit is contained in:
David Brenner 2012-12-02 18:27:20 -05:00
parent 02fe85df89
commit 0fe2331842
3 changed files with 179 additions and 0 deletions

108
beetsplug/echonest_tempo.py Normal file
View file

@ -0,0 +1,108 @@
# This file is part of beets.
# Copyright 2012, David Brenner <david.a.brenner gmail>
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
"""Gets tempo (bpm) for imported music from the EchoNest API. Requires
the pyechonest library (https://github.com/echonest/pyechonest).
"""
import logging
from beets.plugins import BeetsPlugin
from beets import ui
from beets.ui import commands
import pyechonest.config
import pyechonest.song
# Global logger.
log = logging.getLogger('beets')
# The user's EchoNest API key, if provided
_echonest_apikey = None
def fetch_item_tempo(lib, loglevel, item, write):
"""Fetch and store tempo for a single item. If ``write``, then the
tempo will also be written to the file itself in the bpm field. The
``loglevel`` parameter controls the visibility of the function's
status log messages.
"""
# Skip if the item already has the tempo field.
if item.bpm:
log.log(loglevel, u'bpm already present: %s - %s' %
(item.artist, item.title))
return
# Fetch tempo.
tempo = get_tempo(item.artist, item.title)
if not tempo:
log.log(loglevel, u'tempo not found: %s - %s' %
(item.artist, item.title))
return
log.log(loglevel, u'fetched tempo: %s - %s' %
(item.artist, item.title))
item.bpm = tempo
if write:
item.write()
lib.store(item)
def get_tempo(artist, title):
"gets the tempo for a song"
# Unfortunately, all we can do is search by artist and title. EchoNest
# supports foreign ids from MusicBrainz, but currently only for artists,
# not individual tracks/recordings.
results = pyechonest.song.search(artist=artist, title=title, results=1, buckets=['audio_summary'])
if len(results) > 0:
return results[0].audio_summary['tempo']
else:
return None
AUTOFETCH = True
class EchoNestTempoPlugin(BeetsPlugin):
def __init__(self):
super(EchoNestTempoPlugin, self).__init__()
self.import_stages = [self.imported]
def commands(self):
cmd = ui.Subcommand('tempo', help='fetch song tempo (bpm)')
cmd.parser.add_option('-p', '--print', dest='printlyr',
action='store_true', default=False,
help='print tempo (bpm) to console')
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)
cmd.func = func
return [cmd]
def configure(self, config):
global AUTOFETCH, _echonest_apikey
AUTOFETCH = ui.config_val(config, 'echonest_tempo', 'autofetch', True, bool)
_echonest_apikey = ui.config_val(config, 'echonest_tempo', 'apikey',
None)
pyechonest.config.ECHO_NEST_API_KEY = _echonest_apikey
# Auto-fetch tempo on import.
def imported(self, config, task):
if AUTOFETCH:
for item in task.imported_items():
fetch_item_tempo(config.lib, logging.DEBUG, item, False)

View file

@ -0,0 +1,69 @@
EchoNest Tempo Plugin
=============
The ``echonest_tempo`` plugin fetches and stores a track's tempo (bpm field)
from the `EchoNest API`_
.. _EchoNest API: http://developer.echonest.com/
Installing Dependencies
-----------------------
This plugin requires the pyechonest library in order to talk to the EchoNest
API.
There are packages for most major linux distributions, you can download the
library from the EchoNest, or you can install the library from `pip`_,
like so::
$ pip install pyacoustid
.. _pip: http://pip.openplans.org/
Configuring
-----------
The plugin requires an EchoNest API key in order to function. To do this,
first `apply for an API key`_ from the EchoNest. Then, add the key to
your :doc:`/reference/config` as the value ``apikey`` in a section called
``echonest_tempo`` like so::
[echonest_tempo]
apikey=YOUR_API_KEY
In addition, this plugin has one configuration option, ``autofetch``, which
lets you disable automatic tempo fetching during import. To do so, add this
to your ``~/.beetsconfig``::
[echonest_tempo]
apikey=YOUR_API_KEY
autofetch: no
.. _apply for an API key: http://developer.echonest.com/account/register
Fetch Tempo During Import
--------------------------
To automatically fetch the tempo for songs you import, just enable the plugin
by putting ``echonest_tempo`` on your config file's ``plugins`` line (see
:doc:`/plugins/index`), along with adding your EchoNest API key to your
``~/.beetsconfig``. When importing new files, beets will now fetch the
tempo for files that don't already have them. The bpm field will be stored in
the beets database. If the ``import_write`` config option is on, then the
tempo will also be written to the files' tags.
This behavior can be disabled with the ``autofetch`` config option (see below).
Fetching Tempo Manually
------------------------
The ``echonest_tempo`` command provided by this plugin fetches tempos for
items that match a query (see :doc:`/reference/query`). For example,
``beet tempo magnetic fields absolutely cuckoo`` will get the tempo for the
appropriate Magnetic Fields song, ``beet tempo magnetic fields`` will get
tempos for all my tracks by that band, and ``beet tempo`` will get tempos for
my entire library. The tempos will be added to the beets database and, if
``import_write`` is on, embedded into files' metadata.
The ``-p`` option to the ``tempo`` command makes it print tempos out to the
console so you can view the fetched (or previously-stored) tempos.

View file

@ -37,6 +37,7 @@ disabled by default, but you can turn them on as described above.
chroma
lyrics
echonest_tempo
bpd
mpdupdate
fetchart
@ -67,6 +68,7 @@ Metadata
''''''''
* :doc:`lyrics`: Automatically fetch song lyrics.
* :doc:`echonest_tempo`: Automatically fetch song tempos (bpm).
* :doc:`lastgenre`: Fetch genres based on Last.fm tags.
* :doc:`fetchart`: Fetch album cover art from various sources.
* :doc:`embedart`: Embed album art images into files' metadata.