mirror of
https://github.com/beetbox/beets.git
synced 2025-12-26 18:43:38 +01:00
chroma: "beet submit" command (#332)
This commit is contained in:
parent
01dce53212
commit
44bcc5b3bd
3 changed files with 115 additions and 3 deletions
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue