convert: add option to symlink instead of copying

As proposed in #2324.

Updated commit from #2326.

Co-authored-by: Vexatos <stuarzt@gmx.de>
This commit is contained in:
Kier Davis 2019-08-20 14:38:25 +02:00 committed by Vexatos
parent 96d61b8b93
commit 4820cee35c
No known key found for this signature in database
GPG key ID: 5E2F3F029A7B94E4
3 changed files with 67 additions and 20 deletions

View file

@ -114,6 +114,7 @@ class ConvertPlugin(BeetsPlugin):
self.config.add({
u'dest': None,
u'pretend': False,
u'link': False,
u'threads': util.cpu_count(),
u'format': u'mp3',
u'id3v23': u'inherit',
@ -167,6 +168,9 @@ class ConvertPlugin(BeetsPlugin):
help=u'set the target format of the tracks')
cmd.parser.add_option('-y', '--yes', action='store_true', dest='yes',
help=u'do not ask for confirmation')
cmd.parser.add_option('-l', '--link', action='store_true', dest='link',
help=u'symlink files that do not need transcoding. \
Don\'t use with \'embed\'.')
cmd.parser.add_album_option()
cmd.func = self.convert_func
return [cmd]
@ -251,7 +255,7 @@ class ConvertPlugin(BeetsPlugin):
util.displayable_path(source))
def convert_item(self, dest_dir, keep_new, path_formats, fmt,
pretend=False):
pretend=False, link=False):
"""A pipeline thread that converts `Item` objects from a
library.
"""
@ -304,15 +308,26 @@ class ConvertPlugin(BeetsPlugin):
except subprocess.CalledProcessError:
continue
else:
if pretend:
self._log.info(u'cp {0} {1}',
util.displayable_path(original),
util.displayable_path(converted))
if link:
if pretend:
self._log.info(u'ln -s {0} {1}',
util.displayable_path(original),
util.displayable_path(converted))
else:
# No transcoding necessary.
self._log.info(u'Linking {0}',
util.displayable_path(item.path))
util.link(original, converted)
else:
# No transcoding necessary.
self._log.info(u'Copying {0}',
util.displayable_path(item.path))
util.copy(original, converted)
if pretend:
self._log.info(u'cp {0} {1}',
util.displayable_path(original),
util.displayable_path(converted))
else:
# No transcoding necessary.
self._log.info(u'Copying {0}',
util.displayable_path(item.path))
util.copy(original, converted)
if pretend:
continue
@ -346,7 +361,8 @@ class ConvertPlugin(BeetsPlugin):
plugins.send('after_convert', item=item,
dest=converted, keepnew=False)
def copy_album_art(self, album, dest_dir, path_formats, pretend=False):
def copy_album_art(self, album, dest_dir, path_formats, pretend=False,
link=False):
"""Copies or converts the associated cover art of the album. Album must
have at least one track.
"""
@ -399,15 +415,26 @@ class ConvertPlugin(BeetsPlugin):
if not pretend:
ArtResizer.shared.resize(maxwidth, album.artpath, dest)
else:
if pretend:
self._log.info(u'cp {0} {1}',
util.displayable_path(album.artpath),
util.displayable_path(dest))
if link:
if pretend:
self._log.info(u'ln -s {0} {1}',
util.displayable_path(album.artpath),
util.displayable_path(dest))
else:
self._log.info(u'Linking cover art from {0} to {1}',
util.displayable_path(album.artpath),
util.displayable_path(dest))
util.link(album.artpath, dest)
else:
self._log.info(u'Copying cover art from {0} to {1}',
util.displayable_path(album.artpath),
util.displayable_path(dest))
util.copy(album.artpath, dest)
if pretend:
self._log.info(u'cp {0} {1}',
util.displayable_path(album.artpath),
util.displayable_path(dest))
else:
self._log.info(u'Copying cover art from {0} to {1}',
util.displayable_path(album.artpath),
util.displayable_path(dest))
util.copy(album.artpath, dest)
def convert_func(self, lib, opts, args):
dest = opts.dest or self.config['dest'].get()
@ -426,6 +453,11 @@ class ConvertPlugin(BeetsPlugin):
else:
pretend = self.config['pretend'].get(bool)
if opts.link is not None:
link = opts.link
else:
link = self.config['link'].get(bool)
if opts.album:
albums = lib.albums(ui.decargs(args))
items = [i for a in albums for i in a.items()]
@ -446,13 +478,14 @@ class ConvertPlugin(BeetsPlugin):
if opts.album and self.config['copy_album_art']:
for album in albums:
self.copy_album_art(album, dest, path_formats, pretend)
self.copy_album_art(album, dest, path_formats, pretend, link)
convert = [self.convert_item(dest,
opts.keep_new,
path_formats,
fmt,
pretend)
pretend,
link)
for _ in range(threads)]
pipe = util.pipeline.Pipeline([iter(items), convert])
pipe.run_parallel()

View file

@ -11,6 +11,9 @@ New features:
(the MBID), and ``work_disambig`` (the disambiguation string).
Thanks to :user:`dosoe`.
:bug:`2580` :bug:`3272`
* :doc:`/plugins/convert`: Added new ``-l`` (``--link``) flag and ``link`` option
which symlinks files that do not need to be converted instead of copying them.
:bug:`2324`
* :doc:`/plugins/bpd`: BPD now supports most of the features of version 0.16
of the MPD protocol. This is enough to get it talking to more complicated
clients like ncmpcpp, but there are still some incompatibilities, largely due

View file

@ -48,6 +48,10 @@ To test your configuration without taking any actions, use the ``--pretend``
flag. The plugin will print out the commands it will run instead of executing
them.
By default, files that do not need to be transcoded will be copied to their
destination. Passing the ``-l`` (``--link``) flag creates symbolic links
instead. Refer to the ``link`` option below for potential issues with this.
Configuration
-------------
@ -93,6 +97,13 @@ file. The available options are:
- **threads**: The number of threads to use for parallel encoding.
By default, the plugin will detect the number of processors available and use
them all.
- **link**: By default, files that do not need to be transcoded will be copied
to their destination. This option creates symbolic links instead. Note that
options such as ``embed`` that modify the output files after the transcoding
step will cause the original files to be modified as well if ``link`` is
enabled. For this reason, it is highly recommended not use to ``link`` and
``embed`` at the same time.
Default: ``false``.
You can also configure the format to use for transcoding (see the next
section):