diff --git a/.hgtags b/.hgtags index 2cf45afe0..914d3b40b 100644 --- a/.hgtags +++ b/.hgtags @@ -17,3 +17,4 @@ c84744f4519be7416dc1653142f1763f406d6896 1.0rc1 f3cd4c138c6f40dc324a23bf01c4c7d97766477e 1.0rc2 6f29c0f4dc7025e8d8216ea960000c353886c4f4 v1.1.0-beta.1 f28ea9e2ef8d39913d79dbba73db280ff0740c50 v1.1.0-beta.2 +8f070ce28a7b33d8509b29a8dbe937109bbdbd21 v1.1.0-beta.3 diff --git a/beets/__init__.py b/beets/__init__.py index dcd1a8f34..957bac223 100644 --- a/beets/__init__.py +++ b/beets/__init__.py @@ -12,7 +12,7 @@ # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. -__version__ = '1.1.0-beta.3' +__version__ = '1.1.0' __author__ = 'Adrian Sampson ' import beets.library diff --git a/beets/ui/commands.py b/beets/ui/commands.py index 3f76a8328..f13232808 100644 --- a/beets/ui/commands.py +++ b/beets/ui/commands.py @@ -798,7 +798,12 @@ def update_items(lib, query, album, move, pretend): # Read new data. old_data = dict(item.record) - item.read() + try: + item.read() + except Exception as exc: + log.error(u'error reading {0}: {1}'.format( + displayable_path(item.path), exc)) + continue # Special-case album artist when it matches track artist. (Hacky # but necessary for preserving album-level metadata for non- diff --git a/beetsplug/embedart.py b/beetsplug/embedart.py index 5fca4c367..2b342c989 100644 --- a/beetsplug/embedart.py +++ b/beetsplug/embedart.py @@ -20,7 +20,7 @@ from beets.plugins import BeetsPlugin from beets import mediafile from beets import ui from beets.ui import decargs -from beets.util import syspath, normpath +from beets.util import syspath, normpath, displayable_path from beets.util.artresizer import ArtResizer from beets import config @@ -46,7 +46,7 @@ def _embed(path, items, maxwidth=0): f = mediafile.MediaFile(syspath(item.path)) except mediafile.UnreadableFileError as exc: log.warn('Could not embed art in {0}: {1}'.format( - repr(item.path), exc + displayable_path(item.path), exc )) continue f.art = data @@ -70,12 +70,15 @@ class EmbedCoverArtPlugin(BeetsPlugin): def commands(self): # Embed command. embed_cmd = ui.Subcommand('embedart', - help='embed an image file into file metadata') + help='embed image files into file metadata') + embed_cmd.parser.add_option('-f', '--file', metavar='PATH', + help='the image file to embed') def embed_func(lib, opts, args): - if not args: - raise ui.UserError('specify an image file') - imagepath = normpath(args.pop(0)) - embed(lib, imagepath, decargs(args)) + if opts.file: + imagepath = normpath(opts.file) + embed(lib, imagepath, decargs(args)) + else: + embed_current(lib, decargs(args)) embed_cmd.func = embed_func # Extract command. @@ -97,7 +100,7 @@ class EmbedCoverArtPlugin(BeetsPlugin): return [embed_cmd, extract_cmd, clear_cmd] -# "embedart" command. +# "embedart" command with --file argument. def embed(lib, imagepath, query): albums = lib.albums(query) for i_album in albums: @@ -112,6 +115,20 @@ def embed(lib, imagepath, query): _embed(imagepath, album.items(), config['embedart']['maxwidth'].get(int)) +# "embedart" command without explicit file. +def embed_current(lib, query): + albums = lib.albums(query) + for album in albums: + if not album.artpath: + log.info(u'No album art present: {0} - {1}'. + format(album.albumartist, album.album)) + continue + + log.info(u'Embedding album art into {0} - {1}'. + format(album.albumartist, album.album)) + _embed(album.artpath, album.items(), + config['embedart']['maxwidth'].get(int)) + # "extractart" command. def extract(lib, outpath, query): items = lib.items(query) @@ -123,7 +140,14 @@ def extract(lib, outpath, query): return # Extract the art. - mf = mediafile.MediaFile(syspath(item.path)) + try: + mf = mediafile.MediaFile(syspath(item.path)) + except mediafile.UnreadableFileError as exc: + log.error(u'Could not extract art from {0}: {1}'.format( + displayable_path(item.path), exc + )) + return + art = mf.art if not art: log.error('No album art present in %s - %s.' % @@ -148,7 +172,13 @@ def clear(lib, query): log.info('Clearing album art from items:') for item in lib.items(query): log.info(u'%s - %s' % (item.artist, item.title)) - mf = mediafile.MediaFile(syspath(item.path)) + try: + mf = mediafile.MediaFile(syspath(item.path)) + except mediafile.UnreadableFileError as exc: + log.error(u'Could not clear art from {0}: {1}'.format( + displayable_path(item.path), exc + )) + continue mf.art = None mf.save() diff --git a/beetsplug/mbsync.py b/beetsplug/mbsync.py index 97ecee3ae..fa6a3abd5 100644 --- a/beetsplug/mbsync.py +++ b/beetsplug/mbsync.py @@ -47,7 +47,12 @@ def _print_and_apply_changes(lib, item, move, pretend, write): lib.move(item, with_album=False) if write: - item.write() + try: + item.write() + except Exception as exc: + log.error(u'could not sync {0}: {1}'.format( + util.displayable_path(item.path), exc)) + return False lib.store(item) return True @@ -111,8 +116,8 @@ def mbsync_albums(lib, query, move, pretend, write): autotag.apply_metadata(album_info, mapping) changed = False for item in items: - changed = changed or \ - _print_and_apply_changes(lib, item, move, pretend, write) + changed = _print_and_apply_changes(lib, item, move, pretend, + write) or changed if not changed: # No change to any item. continue diff --git a/docs/changelog.rst b/docs/changelog.rst index b00876395..21449ae1b 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,9 +1,26 @@ Changelog ========= -1.1b3 (in development) +1.1.0 (in development) ---------------------- +* :doc:`/plugins/embedart`: The ``embedart`` command now embeds each album's + associated art by default. The ``--file`` option invokes the old behavior, + in which a specific image file is used. +* Avoid some error cases in the ``update`` command and the ``embedart`` and + ``mbsync`` plugins. Invalid or missing files now cause error logs instead of + crashing beets. Thanks to Lucas Duailibe. + +1.1b3 (March 16, 2013) +---------------------- + +This third beta of beets 1.1 brings a hodgepodge of little new features (and +internal overhauls that will make improvements easier in the future). There +are new options for getting metadata in a particular language and seeing more +detail during the import process. There's also a new plugin for synchronizing +your metadata with MusicBrainz. Under the hood, plugins can now extend the +query syntax. + New configuration options: * :ref:`languages` controls the preferred languages when selecting an alias diff --git a/docs/conf.py b/docs/conf.py index ccd96e730..51e9f2056 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -13,7 +13,7 @@ project = u'beets' copyright = u'2012, Adrian Sampson' version = '1.1' -release = '1.1b3' +release = '1.1.0' pygments_style = 'sphinx' diff --git a/docs/plugins/embedart.rst b/docs/plugins/embedart.rst index 9ce3f7257..1200071cf 100644 --- a/docs/plugins/embedart.rst +++ b/docs/plugins/embedart.rst @@ -25,8 +25,10 @@ Manually Embedding and Extracting Art The ``embedart`` plugin provides a couple of commands for manually managing embedded album art: -* ``beet embedart IMAGE QUERY``: given an image file and a query matching an - album, embed the image into the metadata of every track on the album. +* ``beet embedart [-f IMAGE] QUERY``: embed images into the every track on the + albums matching the query. If the ``-f`` (``--file``) option is given, then + use a specific image file from the filesystem; otherwise, each album embeds + its own currently associated album art. * ``beet extractart [-o FILE] QUERY``: extracts the image from an item matching the query and stores it in a file. You can specify the destination file using @@ -40,7 +42,7 @@ embedded album art: Configuring ----------- -The ``auto`` option lets you disable automatic album art embedding. +The ``auto`` option lets you disable automatic album art embedding. To do so, add this to your ``config.yaml``:: embedart: diff --git a/setup.py b/setup.py index 295759b94..09d95968a 100755 --- a/setup.py +++ b/setup.py @@ -42,7 +42,7 @@ if 'sdist' in sys.argv: shutil.copytree(os.path.join(docdir, '_build', 'man'), mandir) setup(name='beets', - version='1.1.0-beta.3', + version='1.1.0', description='music tagger and library organizer', author='Adrian Sampson', author_email='adrian@radbox.org',