chroma: "beet submit" command (#332)

This commit is contained in:
Adrian Sampson 2012-04-01 20:41:27 -07:00
parent 01dce53212
commit 44bcc5b3bd
3 changed files with 115 additions and 3 deletions

View file

@ -17,6 +17,8 @@ autotagger. Requires the pyacoustid library.
"""
from __future__ import with_statement
from beets import plugins
from beets import ui
from beets import util
from beets.autotag import hooks
import acoustid
import logging
@ -42,6 +44,9 @@ _matches = {}
_fingerprints = {}
_acoustids = {}
# The user's Acoustid API key, if provided.
_userkey = None
def acoustid_match(path):
"""Gets metadata for a file from Acoustid and populates the
@ -87,6 +92,9 @@ def acoustid_match(path):
log.debug('chroma: matched recording {}'.format(recording_id))
_matches[path] = recording_id, release_ids
# Plugin structure and autotagging logic.
def _all_releases(items):
"""Given an iterable of Items, determines (according to Acoustid)
which releases the items have in common. Generates release IDs.
@ -141,6 +149,23 @@ class AcoustidPlugin(plugins.BeetsPlugin):
log.debug('no acoustid item candidate found')
return []
def configure(self, config):
global _userkey
_userkey = ui.config_val(config, 'acoustid', 'apikey', None)
def commands(self):
submit_cmd = ui.Subcommand('submit',
help='submit Acoustid fingerprints')
def submit_cmd_func(lib, config, opts, args):
if not _userkey:
raise ui.UserError('no Acoustid user API key provided')
submit_items(_userkey, lib.items(ui.decargs(args)))
submit_cmd.func = submit_cmd_func
return [submit_cmd]
# Hooks into import process.
@AcoustidPlugin.listen('import_task_start')
def fingerprint_task(config=None, task=None):
"""Fingerprint each item in the task for later use during the
@ -158,3 +183,66 @@ def apply_acoustid_metadata(config=None, task=None):
item.acoustid_fingerprint = _fingerprints[item.path]
if item.path in _acoustids:
item.acoustid_id = _acoustids[item.path]
# UI commands.
def submit_items(userkey, items, chunksize=64):
"""Submit fingerprints for the items to the Acoustid server.
"""
data = [] # The running list of dictionaries to submit.
def submit_chunk():
"""Submit the current accumulated fingerprint data."""
log.info('submitting {} fingerprints'.format(len(data)))
acoustid.submit(API_KEY, userkey, data)
del data[:]
for item in items:
# Get a fingerprint and length for this track.
if not item.length:
log.info(u'{}: no duration available'.format(
util.displayable_path(item.path)
))
continue
elif item.acoustid_fingerprint:
log.info(u'{}: using existing fingerprint'.format(
util.displayable_path(item.path)
))
fp = item.acoustid_fingerprint
else:
log.info(u'{}: fingerprinting'.format(
util.displayable_path(item.path)
))
try:
_, fp = acoustid.fingerprint_file(item.path)
except acoustid.FingerprintGenerationError, exc:
log.info('fingerprint generation failed')
continue
# Construct a submission dictionary for this item.
item_data = {
'duration': int(item.length),
'fingerprint': fp,
}
if item.mb_trackid:
item_data['mbid'] = item.mb_trackid
log.debug('submitting MBID')
else:
item_data.update({
'track': item.title,
'artist': item.artist,
'album': item.album,
'albumartist': item.albumartist,
'year': item.year,
'trackno': item.track,
'discno': item.disc,
})
log.debug('submitting textual metadata')
data.append(item_data)
# If we have enough data, submit a chunk.
if len(data) > chunksize:
submit_chunk()
# Submit remaining data in a final chunk.
submit_chunk()

View file

@ -14,9 +14,12 @@ Changelog
fields, ``artist_sort`` and ``albumartist_sort``, that contain sortable artist
names like "Beatles, The". These fields are also used to sort albums and items
when using the ``list`` command. Thanks to Paul Provost.
* :doc:`/plugins/chroma`: The Chromaprint fingerprint and Acoustid ID are now
stored for all fingerprinted tracks. This version of beets *requires* at least
version 0.6 of `pyacoustid`_ for fingerprinting to work.
* :doc:`/plugins/chroma`: A new command, ``beet submit``, will **submit
fingerprints** to the Acoustid database. Submitting your library helps
increase the coverage and accuracy of Acoustid fingerprinting. The Chromaprint
fingerprint and Acoustid ID are also now stored for all fingerprinted tracks.
This version of beets *requires* at least version 0.6 of `pyacoustid`_ for
fingerprinting to work.
* New :doc:`/plugins/rdm`: Randomly select albums and tracks from your library.
Thanks to Philippe Mongeau.
* The :doc:`/plugins/mbcollection` by Jeffrey Aylesworth was added to the core

View file

@ -75,3 +75,24 @@ line. Your config file should contain something like this::
plugins: chroma
With that, beets will use fingerprinting the next time you run ``beet import``.
.. _submitfp:
Submitting Fingerprints
'''''''''''''''''''''''
You can help expand the `Acoustid`_ database by submitting fingerprints for the
music in your collection. To do this, first `get an API key`_ from the Acoustid
service. Just use an OpenID or MusicBrainz account to log in and you'll get a
short token string. Then, add the key to your :doc:`/reference/config` as the
value ``apikey`` in a section called ``acoustid`` like so::
[acoustid]
apikey=AbCd1234
Then, run ``beet submit``. (You can also provide a query to submit a subset of
your library.) The command will use stored fingerprints if they're available;
otherwise it will fingerprint each file before submitting it.
.. _get an API key: http://acoustid.org/api-key