diff --git a/beetsplug/convert.py b/beetsplug/convert.py index 37395db1a..8113c86ca 100644 --- a/beetsplug/convert.py +++ b/beetsplug/convert.py @@ -25,6 +25,7 @@ import pipes from beets import ui, util, plugins, config from beets.plugins import BeetsPlugin from beetsplug.embedart import embed_item +from beets.util.confit import ConfigTypeError log = logging.getLogger('beets') _fs_lock = threading.Lock() @@ -51,32 +52,33 @@ def get_format(format=None): if not format: format = config['convert']['format'].get(unicode).lower() format = ALIASES.get(format, format) - # TODO extension may default to format so this doesn't have to be a - # dictionary - format_info = config['convert']['formats'][format].get(dict) - - # Convenience and backwards-compatibility shortcuts. - keys = config['convert'].keys() - if 'command' in keys: - format_info['command'] = config['convert']['command'].get(unicode) - elif 'opts' in keys: - # Undocumented option for backwards compatibility with < 1.3.1. - format_info['command'] = u'ffmpeg -i $source -y {0} $dest'.format( - config['convert']['opts'].get(unicode) - ) - if 'extension' in keys: - format_info['extension'] = config['convert']['extension'].get(unicode) try: - return ( - format_info['command'].encode('utf8'), - format_info['extension'].encode('utf8'), - ) + format_info = config['convert']['formats'][format].get(dict) + command = format_info['command'] + extension = format_info['extension'] except KeyError: raise ui.UserError( u'convert: format {0} needs "command" and "extension" fields' .format(format) ) + except ConfigTypeError: + command = config['convert']['formats'][format].get(str) + extension = format + + # Convenience and backwards-compatibility shortcuts. + keys = config['convert'].keys() + if 'command' in keys: + command = config['convert']['command'].get(unicode) + elif 'opts' in keys: + # Undocumented option for backwards compatibility with < 1.3.1. + command = u'ffmpeg -i $source -y {0} $dest'.format( + config['convert']['opts'].get(unicode) + ) + if 'extension' in keys: + extension = config['convert']['extension'].get(unicode) + + return (command.encode('utf8'), extension.encode('utf8')) def encode(command, source, dest): @@ -263,29 +265,14 @@ class ConvertPlugin(BeetsPlugin): u'command': u'ffmpeg -i $source -y -vn -acodec alac $dest', u'extension': u'm4a', }, - u'flac': { - u'command': u'ffmpeg -i $source -y -vn -acodec flac $dest', - u'extension': u'flac', - }, - u'mp3': { - u'command': u'ffmpeg -i $source -y -vn -aq 2 $dest', - u'extension': u'mp3', - }, - u'opus': { - u'command': u'ffmpeg -i $source -y -vn -acodec libopus ' - u'-ab 96k $dest', - u'extension': u'opus', - }, - u'ogg': { - u'command': u'ffmpeg -i $source -y -vn -acodec libvorbis ' - u'-aq 2 $dest', - u'extension': u'ogg', - }, - u'windows media': { - u'command': u'ffmpeg -i $source -y -vn -acodec wmav2 ' - u'-vn $dest', - u'extension': u'wma', - }, + u'flac': u'ffmpeg -i $source -y -vn -acodec flac $dest', + u'mp3': u'ffmpeg -i $source -y -vn -aq 2 $dest', + u'opus': + u'ffmpeg -i $source -y -vn -acodec libopus -ab 96k $dest', + u'ogg': + u'ffmpeg -i $source -y -vn -acodec libvorbis -aq 2 $dest', + u'wma': + u'ffmpeg -i $source -y -vn -acodec wmav2 -vn $dest', }, u'max_bitrate': 500, u'auto': False, diff --git a/docs/plugins/convert.rst b/docs/plugins/convert.rst index bf5d62ddb..485c80400 100644 --- a/docs/plugins/convert.rst +++ b/docs/plugins/convert.rst @@ -89,19 +89,19 @@ and select a command with the ``--format`` command-line option or the speex: command: ffmpeg -i $source -y -acodec speex $dest extension: spx - wav: - command: ffmpeg -i $source -y -acodec pcm_s16le $dest - extension: wav + wav: ffmpeg -i $source -y -acodec pcm_s16le $dest In this example ``beet convert`` will use the *speex* command by default. To convert the audio to `wav`, run ``beet convert -f wav``. +This will also use the format key (`wav`) as the file extension. Each entry in the ``formats`` map consists of a key (the name of the -format) as well as the command and the extension. ``extension`` is the -filename extension to be used for newly transcoded files. -``command`` is the command-line to use to transcode audio. The tokens -``$source`` and ``$dest`` in the command are replaced with the paths to -the existing and new file. +format) as well as the command and the possibly the file extension. +``extension`` is the filename extension to be used for newly transcoded +files. If only the command is given as a string, the file extension +defaults to the format’s name. ``command`` is the command-line to use +to transcode audio. The tokens ``$source`` and ``$dest`` in the command +are replaced with the paths to the existing and new file. The plugin in comes with default commands for the most common audio formats: `mp3`, `alac`, `flac`, `aac`, `opus`, `ogg`, `wmv`. For diff --git a/test/test_convert.py b/test/test_convert.py index ebe30ad8c..24ed44748 100644 --- a/test/test_convert.py +++ b/test/test_convert.py @@ -77,13 +77,10 @@ class ConvertCliTest(unittest.TestCase, TestHelper): 'paths': {'default': 'converted'}, 'format': 'mp3', 'formats': { - 'mp3': { - 'command': 'cp $source $dest', - 'extension': 'mp3', - }, + 'mp3': 'cp $source $dest', 'opus': { 'command': 'cp $source $dest', - 'extension': 'opus', + 'extension': 'ops', } } } @@ -110,7 +107,7 @@ class ConvertCliTest(unittest.TestCase, TestHelper): def test_format_option(self): with control_stdin('y'): self.run_command('convert', '--format', 'opus', self.item.path) - converted = os.path.join(self.convert_dest, 'converted.opus') + converted = os.path.join(self.convert_dest, 'converted.ops') self.assertTrue(os.path.isfile(converted)) def test_embed_album_art(self):