Merge branch 'master' of https://github.com/sampsyo/beets into bs1770gainsupport

This commit is contained in:
jean-marie winters 2015-03-06 22:02:48 +01:00
commit efb7370e04
9 changed files with 56 additions and 40 deletions

View file

@ -624,7 +624,7 @@ def cpu_count():
num = 0
elif sys.platform == b'darwin':
try:
num = int(command_output(['sysctl', '-n', 'hw.ncpu']))
num = int(command_output([b'sysctl', b'-n', b'hw.ncpu']))
except ValueError:
num = 0
else:
@ -641,8 +641,8 @@ def cpu_count():
def command_output(cmd, shell=False):
"""Runs the command and returns its output after it has exited.
``cmd`` is a list of arguments starting with the command names. If
``shell`` is true, ``cmd`` is assumed to be a string and passed to a
``cmd`` is a list of byte string arguments starting with the command names.
If ``shell`` is true, ``cmd`` is assumed to be a string and passed to a
shell to execute.
If the process exits with a non-zero return code

View file

@ -91,8 +91,8 @@ def im_resize(maxwidth, path_in, path_out=None):
# compatibility.
try:
util.command_output([
'convert', util.syspath(path_in),
'-resize', '{0}x^>'.format(maxwidth), path_out
b'convert', util.syspath(path_in),
b'-resize', b'{0}x^>'.format(maxwidth), path_out
])
except subprocess.CalledProcessError:
log.warn(u'artresizer: IM convert failed for {0}',
@ -187,7 +187,7 @@ class ArtResizer(object):
# Try invoking ImageMagick's "convert".
try:
out = util.command_output(['identify', '--version'])
out = util.command_output([b'identify', b'--version'])
if 'imagemagick' in out.lower():
pattern = r".+ (\d+)\.(\d+)\.(\d+).*"

View file

@ -192,7 +192,13 @@ class DiscogsPlugin(BeetsPlugin):
# Strip medium information from query, Things like "CD1" and "disk 1"
# can also negate an otherwise positive result.
query = re.sub(r'(?i)\b(CD|disc)\s*\d+', '', query)
releases = self.discogs_client.search(query, type='release').page(1)
try:
releases = self.discogs_client.search(query,
type='release').page(1)
except CONNECTION_ERRORS as exc:
self._log.debug("Communication error while searching for {0!r}: "
"{1}".format(query, exc))
return []
return [self.get_album_info(release) for release in releases[:5]]
def get_album_info(self, result):

View file

@ -196,13 +196,13 @@ class EmbedCoverArtPlugin(BeetsPlugin):
# Converting images to grayscale tends to minimize the weight
# of colors in the diff score.
convert_proc = subprocess.Popen(
['convert', syspath(imagepath), syspath(art),
'-colorspace', 'gray', 'MIFF:-'],
[b'convert', syspath(imagepath), syspath(art),
b'-colorspace', b'gray', b'MIFF:-'],
stdout=subprocess.PIPE,
close_fds=not is_windows,
)
compare_proc = subprocess.Popen(
['compare', '-metric', 'PHASH', '-', 'null:'],
[b'compare', b'-metric', b'PHASH', b'-', b'null:'],
stdin=convert_proc.stdout,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,

View file

@ -33,14 +33,12 @@ from beets import config
# Utilities.
class ReplayGainError(Exception):
"""Raised when a local (to a track or an album) error occurs in one
of the backends.
"""
class FatalReplayGainError(Exception):
"""Raised when a fatal error occurs in one of the backends.
"""
@ -69,7 +67,6 @@ AlbumGain = collections.namedtuple("AlbumGain", "album_gain track_gains")
class Backend(object):
"""An abstract class representing engine for calculating RG values.
"""
@ -90,20 +87,18 @@ class Backend(object):
# bsg1770gain backend
class Bs1770gainBackend(Backend):
"""bs1770gain is a loudness scanner compliant with ITU-R BS.1770 and its
flavors EBU R128,ATSC A/85 and Replaygain 2.0. It uses a special
designed algorithm to normalize audio to the same level.
"""bs1770gain is a loudness scanner compliant with ITU-R BS.1770 and
its flavors EBU R128, ATSC A/85 and Replaygain 2.0.
"""
def __init__(self, config, log):
super(Bs1770gainBackend, self).__init__(config, log)
cmd = 'bs1770gain'
cmd = b'bs1770gain'
try:
self.method = '--' + config['method'].get(unicode)
self.method = b'--' + config['method'].get(str)
except:
self.method = '--replaygain'
self.method = b'--replaygain'
try:
call([cmd, self.method])
@ -215,9 +210,9 @@ class CommandBackend(Backend):
)
else:
# Check whether the program is in $PATH.
for cmd in ('mp3gain', 'aacgain'):
for cmd in (b'mp3gain', b'aacgain'):
try:
call([cmd, '-v'])
call([cmd, b'-v'])
self.command = cmd
except OSError:
pass
@ -281,14 +276,14 @@ class CommandBackend(Backend):
# tag-writing; this turns the mp3gain/aacgain tool into a gain
# calculator rather than a tag manipulator because we take care
# of changing tags ourselves.
cmd = [self.command, '-o', '-s', 's']
cmd = [self.command, b'-o', b'-s', b's']
if self.noclip:
# Adjust to avoid clipping.
cmd = cmd + ['-k']
cmd = cmd + [b'-k']
else:
# Disable clipping warning.
cmd = cmd + ['-c']
cmd = cmd + ['-d', bytes(self.gain_offset)]
cmd = cmd + [b'-c']
cmd = cmd + [b'-d', bytes(self.gain_offset)]
cmd = cmd + [syspath(i.path) for i in items]
self._log.debug(u'analyzing {0} files', len(items))
@ -576,7 +571,6 @@ class GStreamerBackend(Backend):
class AudioToolsBackend(Backend):
"""ReplayGain backend that uses `Python Audio Tools
<http://audiotools.sourceforge.net/>`_ and its capabilities to read more
file formats and compute ReplayGain values using it replaygain module.
@ -706,7 +700,6 @@ class AudioToolsBackend(Backend):
# Main plugin logic.
class ReplayGainPlugin(BeetsPlugin):
"""Provides ReplayGain analysis.
"""
@ -802,7 +795,6 @@ class ReplayGainPlugin(BeetsPlugin):
)
self.store_album_gain(album, album_gain.album_gain)
for item, track_gain in itertools.izip(album.items(),
album_gain.track_gains):
self.store_track_gain(item, track_gain)

View file

@ -6,6 +6,8 @@ Changelog
Features:
* :doc:`/plugins/replaygain`: There is a new backend for the `bs1770gain`_
tool. Thanks to :user:`jmwatte`. :bug:`1343`
* There are now multiple levels of verbosity. On the command line, you can
make beets somewhat verbose with ``-v`` or very verbose with ``-vv``.
:bug:`1244`
@ -129,6 +131,8 @@ For developers:
immediately after they are initialized. It's also possible to replace the
originally created tasks by returning new ones using this event.
.. _bs1770gain: http://bs1770gain.sourceforge.net
1.3.10 (January 5, 2015)
------------------------

View file

@ -90,7 +90,8 @@ backend in your configuration file::
replaygain:
backend: bs1770gain
Configuration
-------------
@ -118,11 +119,10 @@ These options only work with the "command" backend:
This option only works with the "bs1770gain" backend:
- **method**: The loudness scanning standard: either 'replaygain' for ReplayGain 2.0,
'ebu' for EBU R128 or 'atsc' for ATSC A/85.
This dictates the reference level: -18, -23, or -24 LUFS respectively. Default: replaygain
- **method**: The loudness scanning standard: either `replaygain` for
ReplayGain 2.0, `ebu` for EBU R128, or `atsc` for ATSC A/85. This dictates
the reference level: -18, -23, or -24 LUFS respectively. Default:
`replaygain`
Manual Analysis

View file

@ -51,6 +51,7 @@ from beets.library import Library, Item, Album
from beets import importer
from beets.autotag.hooks import AlbumInfo, TrackInfo
from beets.mediafile import MediaFile, Image
from beets.ui import _encoding
# TODO Move AutotagMock here
from test import _common
@ -117,9 +118,13 @@ def capture_stdout():
def has_program(cmd, args=['--version']):
"""Returns `True` if `cmd` can be executed.
"""
full_cmd = [cmd] + args
for i, elem in enumerate(full_cmd):
if isinstance(elem, unicode):
full_cmd[i] = elem.encode(_encoding())
try:
with open(os.devnull, 'wb') as devnull:
subprocess.check_call([cmd] + args, stderr=devnull,
subprocess.check_call(full_cmd, stderr=devnull,
stdout=devnull, stdin=devnull)
except OSError:
return False

View file

@ -25,7 +25,7 @@ try:
import gi
gi.require_version('Gst', '1.0')
GST_AVAILABLE = True
except ImportError, ValueError:
except (ImportError, ValueError):
GST_AVAILABLE = False
if any(has_program(cmd, ['-v']) for cmd in ['mp3gain', 'aacgain']):
@ -47,9 +47,18 @@ class ReplayGainCliTestBase(TestHelper):
try:
self.load_plugins('replaygain')
except:
self.teardown_beets()
self.unload_plugins()
raise
import sys
# store exception info so an error in teardown does not swallow it
exc_info = sys.exc_info()
try:
self.teardown_beets()
self.unload_plugins()
except:
# if load_plugins() failed then setup is incomplete and
# teardown operations may fail. In particular # {Item,Album}
# may not have the _original_types attribute in unload_plugins
pass
raise exc_info[1], None, exc_info[2]
self.config['replaygain']['backend'] = self.backend
album = self.add_album_fixture(2)