Skip to content

Commit

Permalink
Merge branch 'master' of github.com:sampsyo/beets into prompthook
Browse files Browse the repository at this point in the history
Conflicts:
	docs/changelog.rst
  • Loading branch information
diego-plan9 committed Jan 2, 2016
2 parents 9bba782 + f582e04 commit cd225ca
Show file tree
Hide file tree
Showing 11 changed files with 181 additions and 17 deletions.
2 changes: 1 addition & 1 deletion beets/ui/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1172,7 +1172,7 @@ def _raw_main(args, lib=None):
parser.add_option('-d', '--directory', dest='directory',
help="destination music directory")
parser.add_option('-v', '--verbose', dest='verbose', action='count',
help='print debugging information')
help='log more details (use twice for even more)')
parser.add_option('-c', '--config', dest='config',
help='path to configuration file')
parser.add_option('-h', '--help', dest='help', action='store_true',
Expand Down
10 changes: 9 additions & 1 deletion beets/ui/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -1428,10 +1428,18 @@ def move_items(lib, dest, query, copy, album, pretend):
items, albums = _do_query(lib, query, album, False)
objs = albums if album else items

# Filter out files that don't need to be moved.
isitemmoved = lambda item: item.path != item.destination(basedir=dest)
isalbummoved = lambda album: any(isitemmoved(i) for i in album.items())
objs = [o for o in objs if (isalbummoved if album else isitemmoved)(o)]

action = 'Copying' if copy else 'Moving'
entity = 'album' if album else 'item'
log.info(u'{0} {1} {2}{3}.', action, len(objs), entity,
's' if len(objs) > 1 else '')
's' if len(objs) != 1 else '')
if not objs:
return

if pretend:
if album:
show_path_changes([(item.path, item.destination(basedir=dest))
Expand Down
106 changes: 106 additions & 0 deletions beetsplug/acousticbrainz.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# -*- coding: utf-8 -*-
# This file is part of beets.
# Copyright 2015-2016, Ohm Patel.
#
# 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.

""" Fetch various AcousticBrainz metadata using MBID
"""
from __future__ import (division, absolute_import, print_function,
unicode_literals)

import requests

from beets import plugins, ui

ACOUSTIC_URL = "http://acousticbrainz.org/"
LEVEL = "/high-level"


class AcousticPlugin(plugins.BeetsPlugin):
def __init__(self):
super(AcousticPlugin, self).__init__()

def commands(self):
cmd = ui.Subcommand('acousticbrainz',
help="fetch metadata from AcousticBrainz")

def func(lib, opts, args):
items = lib.items(ui.decargs(args))
fetch_info(self._log, items)

cmd.func = func
return [cmd]


def fetch_info(log, items):
"""Currently outputs MBID and corresponding request status code
"""
for item in items:
if item.mb_trackid:
log.info('getting data for: {}', item)

# Fetch the data from the AB API.
url = generate_url(item.mb_trackid)
log.debug('fetching URL: {}', url)
try:
rs = requests.get(url)
except requests.RequestException as exc:
log.info('request error: {}', exc)
continue

# Check for missing tracks.
if rs.status_code == 404:
log.info('recording ID {} not found', item.mb_trackid)
continue

# Parse the JSON response.
try:
data = rs.json()
except ValueError:
log.debug('Invalid Response: {}', rs.text)

# Get each field and assign it on the item.
item.danceable = get_value(
log,
data,
["highlevel", "danceability", "all", "danceable"],
)
item.mood_happy = get_value(
log,
data,
["highlevel", "mood_happy", "all", "happy"],
)
item.mood_party = get_value(
log,
data,
["highlevel", "mood_party", "all", "party"],
)

# Store the data. We only update flexible attributes, so we
# don't call `item.try_write()` here.
item.store()


def generate_url(mbid):
"""Generates url of AcousticBrainz end point for given MBID
"""
return ACOUSTIC_URL + mbid + LEVEL


def get_value(log, data, map_path):
"""Allows traversal of dictionary with cleaner formatting
"""
try:
return reduce(lambda d, k: d[k], map_path, data)
except KeyError:
log.debug('Invalid Path: {}', map_path)
2 changes: 1 addition & 1 deletion beetsplug/echonest.py
Original file line number Diff line number Diff line change
Expand Up @@ -465,7 +465,7 @@ def requires_update(self, item):

def commands(self):
fetch_cmd = ui.Subcommand('echonest',
help='Fetch metadata from the EchoNest')
help='fetch metadata from The Echo Nest')
fetch_cmd.parser.add_option(
'-f', '--force', dest='force', action='store_true', default=False,
help='(re-)download information from the EchoNest'
Expand Down
7 changes: 1 addition & 6 deletions beetsplug/play.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,13 +129,8 @@ def play_music(self, lib, opts, args):
try:
util.interactive_open(open_args, command_str)
except OSError as exc:
raise ui.UserError("Could not play the music playlist: "
raise ui.UserError("Could not play the query: "
"{0}".format(exc))
finally:
if not raw:
self._log.debug('Removing temporary playlist: {}',
open_args[0])
util.remove(open_args[0])

def _create_tmp_playlist(self, paths_list):
"""Create a temporary .m3u file. Return the filename.
Expand Down
15 changes: 15 additions & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,25 @@ New:
* :doc:`/plugins/fetchart`: The Google Images backend has been restored. It
now requires an API key from Google. Thanks to :user:`lcharlick`.
:bug:`1778`
* A new :doc:`/plugins/acousticbrainz` fetches acoustic-analysis information
from the `AcousticBrainz`_ project. Thanks to :user:`opatel99`. :bug:`1784`
* A new :doc:`/plugins/mbsubmit` lets you print the tracks of an album in a
format parseable by MusicBrainz track parser during an interactive import
session. :bug:`1779`

.. _AcousticBrainz: http://acousticbrainz.org/

Fixes:

* :doc:`/plugins/play`: Remove dead code. From this point on, beets isn't
supposed and won't try to delete the playlists generated by ``beet play``
(Note that although it was supposed to, beet didn't actually remove the
generated ``.m3u`` files beforehand either.). If this is an issue for you, you
might want to take a look at the ``raw`` config option of the
:doc:`/plugins/play`. :bug:`1785`, :bug:`1600`
* The :ref:`move-cmd` command does not display files whose path does not change
anymore. :bug:`1583`


1.3.16 (December 28, 2015)
--------------------------
Expand Down
16 changes: 9 additions & 7 deletions docs/dev/plugins.rst
Original file line number Diff line number Diff line change
Expand Up @@ -517,16 +517,18 @@ str.format-style string formatting. So you can write logging calls like this::
When beets is in verbose mode, plugin messages are prefixed with the plugin
name to make them easier to see.

What messages will be logged depends on the logging level and the action
Which messages will be logged depends on the logging level and the action
performed:

* On import stages and event handlers, the default is ``WARNING`` messages and
above.
* On direct actions, the default is ``INFO`` or above, as with the rest of
beets.
* Inside import stages and event handlers, the default is ``WARNING`` messages
and above.
* Everywhere else, the default is ``INFO`` or above.

The verbosity can be increased with ``--verbose`` flags: each flags lowers the
level by a notch.
The verbosity can be increased with ``--verbose`` (``-v``) flags: each flags
lowers the level by a notch. That means that, with a single ``-v`` flag, event
handlers won't have their ``DEBUG`` messages displayed, but command functions
(for example) will. With ``-vv`` on the command line, ``DEBUG`` messages will
be displayed everywhere.

This addresses a common pattern where plugins need to use the same code for a
command and an import stage, but the command needs to print more messages than
Expand Down
22 changes: 22 additions & 0 deletions docs/plugins/acousticbrainz.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
AcousticBrainz Plugin
=====================

The ``acoustricbrainz`` plugin gets acoustic-analysis information from the
`AcousticBrainz`_ project. The spirit is similar to the
:doc:`/plugins/echonest`.

.. _AcousticBrainz: http://acousticbrainz.org/

Enable the ``acousticbrainz`` plugin in your configuration (see :ref:`using-plugins`) and run it by typing::

$ beet acousticbrainz [QUERY]

For all tracks with a MusicBrainz recording ID, the plugin currently sets
these fields:

* ``danceable``: Predicts how easy the track is to dance to.
* ``mood_happy``: Predicts the probability this track will evoke happiness.
* ``mood_party``: Predicts the probability this track should be played at a
party.

These three fields are all numbers between 0.0 and 1.0.
2 changes: 2 additions & 0 deletions docs/plugins/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ Each plugin has its own set of options that can be defined in a section bearing
.. toctree::
:hidden:

acousticbrainz
badfiles
bpd
bpm
Expand Down Expand Up @@ -95,6 +96,7 @@ Autotagger Extensions
Metadata
--------

* :doc:`acousticbrainz`: Fetch various AcousticBrainz metadata
* :doc:`bpm`: Measure tempo using keystrokes.
* :doc:`echonest`: Automatically fetch `acoustic attributes`_ from
`the Echo Nest`_ (tempo, energy, danceability, ...).
Expand Down
14 changes: 14 additions & 0 deletions docs/plugins/play.rst
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,17 @@ example::

indicates that you need to insert extra arguments before specifying the
playlist.

Note on the Leakage of the Generated Playlists
_______________________________________________

Because the command that will open the generated ``.m3u`` files can be
arbitrarily configured by the user, beets won't try to delete those files. For
this reason, using this plugin will leave one or several playlist(s) in the
directory selected to create temporary files (Most likely ``/tmp/`` on Unix-like
systems. See `tempfile.tempdir`_.). Leaking those playlists until they are
externally wiped could be an issue for privacy or storage reasons. If this is
the case for you, you might want to use the ``raw`` config option described
above.

.. _tempfile.tempdir: https://docs.python.org/2/library/tempfile.html#tempfile.tempdir
2 changes: 1 addition & 1 deletion docs/reference/cli.rst
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ anywhere in your filesystem. The ``-c`` option copies files instead of moving
them. As with other commands, the ``-a`` option matches albums instead of items.

To perform a "dry run", just use the ``-p`` (for "pretend") flag. This will
show you all how the files would be moved but won't actually change anything
show you a list of files that would be moved but won't actually change anything
on disk.

.. _update-cmd:
Expand Down

0 comments on commit cd225ca

Please sign in to comment.