mirror of
https://github.com/beetbox/beets.git
synced 2025-12-08 17:49:11 +01:00
Merge branch 'master' of git://github.com/sampsyo/beets
This commit is contained in:
commit
ae807bccfc
10 changed files with 69 additions and 34 deletions
1
.hgtags
1
.hgtags
|
|
@ -18,3 +18,4 @@ f3cd4c138c6f40dc324a23bf01c4c7d97766477e 1.0rc2
|
|||
6f29c0f4dc7025e8d8216ea960000c353886c4f4 v1.1.0-beta.1
|
||||
f28ea9e2ef8d39913d79dbba73db280ff0740c50 v1.1.0-beta.2
|
||||
8f070ce28a7b33d8509b29a8dbe937109bbdbd21 v1.1.0-beta.3
|
||||
97f04ce252332dbda013cbc478d702d54a8fc1bd v1.1.0
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ def im_resize(maxwidth, path_in, path_out=None):
|
|||
# "-resize widthxheight>" shrinks images with dimension(s) larger
|
||||
# than the corresponding width and/or height dimension(s). The >
|
||||
# "only shrink" flag is prefixed by ^ escape char for Windows
|
||||
# compatability.
|
||||
# compatibility.
|
||||
call([
|
||||
'convert', util.syspath(path_in),
|
||||
'-resize', '{0}x^>'.format(maxwidth), path_out
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ class WaitableEvent(Event):
|
|||
return (), (), ()
|
||||
|
||||
def fire(self):
|
||||
"""Called when an assoicated file descriptor becomes ready
|
||||
"""Called when an associated file descriptor becomes ready
|
||||
(i.e., is returned from a select() call).
|
||||
"""
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -667,7 +667,7 @@ class Configuration(RootView):
|
|||
"""
|
||||
dirs = list(self._search_dirs())
|
||||
|
||||
# First, look for an existant configuration file.
|
||||
# First, look for an existent configuration file.
|
||||
for appdir in dirs:
|
||||
if os.path.isfile(os.path.join(appdir, CONFIG_FILENAME)):
|
||||
return appdir
|
||||
|
|
|
|||
|
|
@ -189,7 +189,7 @@ class ConvertPlugin(BeetsPlugin):
|
|||
help='choose albums instead of tracks')
|
||||
cmd.parser.add_option('-t', '--threads', action='store', type='int',
|
||||
help='change the number of threads, \
|
||||
defaults to maximum availble processors ')
|
||||
defaults to maximum available processors')
|
||||
cmd.parser.add_option('-k', '--keep-new', action='store_true',
|
||||
dest='keep_new', help='keep only the converted \
|
||||
and move the old files')
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ from beets import util
|
|||
from beets import config
|
||||
|
||||
IMAGE_EXTENSIONS = ['png', 'jpg', 'jpeg']
|
||||
COVER_NAMES = ['cover', 'front', 'art', 'album', 'folder']
|
||||
CONTENT_TYPES = ('image/jpeg',)
|
||||
DOWNLOAD_EXTENSION = '.jpg'
|
||||
|
||||
|
|
@ -111,7 +110,7 @@ def aao_art(asin):
|
|||
|
||||
# Art from the filesystem.
|
||||
|
||||
def art_in_path(path):
|
||||
def art_in_path(path, cover_names, cautious):
|
||||
"""Look for album art files in a specified directory."""
|
||||
if not os.path.isdir(path):
|
||||
return
|
||||
|
|
@ -124,16 +123,16 @@ def art_in_path(path):
|
|||
images.append(fn)
|
||||
|
||||
# Look for "preferred" filenames.
|
||||
cover_pat = r"(\b|_)({0})(\b|_)".format('|'.join(cover_names))
|
||||
for fn in images:
|
||||
for name in COVER_NAMES:
|
||||
if fn.lower().startswith(name):
|
||||
log.debug(u'fetchart: using well-named art file {0}'.format(
|
||||
util.displayable_path(fn)
|
||||
))
|
||||
return os.path.join(path, fn)
|
||||
if re.search(cover_pat, os.path.splitext(fn)[0], re.I):
|
||||
log.debug(u'fetchart: using well-named art file {0}'.format(
|
||||
util.displayable_path(fn)
|
||||
))
|
||||
return os.path.join(path, fn)
|
||||
|
||||
# Fall back to any image in the folder.
|
||||
if images:
|
||||
if images and not cautious:
|
||||
log.debug(u'fetchart: using fallback art file {0}'.format(
|
||||
util.displayable_path(images[0])
|
||||
))
|
||||
|
|
@ -172,9 +171,11 @@ def art_for_album(album, paths, maxwidth=None, local_only=False):
|
|||
out = None
|
||||
|
||||
# Local art.
|
||||
cover_names = config['fetchart']['cover_names'].as_str_seq()
|
||||
cautious = config['fetchart']['cautious'].get(bool)
|
||||
if paths:
|
||||
for path in paths:
|
||||
out = art_in_path(path)
|
||||
out = art_in_path(path, cover_names, cautious)
|
||||
if out:
|
||||
break
|
||||
|
||||
|
|
@ -221,6 +222,8 @@ class FetchArtPlugin(BeetsPlugin):
|
|||
'auto': True,
|
||||
'maxwidth': 0,
|
||||
'remote_priority': False,
|
||||
'cautious': False,
|
||||
'cover_names': ['cover', 'front', 'art', 'album', 'folder'],
|
||||
})
|
||||
|
||||
# Holds paths to downloaded images between fetching them and
|
||||
|
|
|
|||
|
|
@ -1,8 +1,16 @@
|
|||
Changelog
|
||||
=========
|
||||
|
||||
1.1.0 (in development)
|
||||
----------------------
|
||||
1.1.0 (April 29, 203)
|
||||
---------------------
|
||||
|
||||
This final release of 1.1 brings a little polish to the betas that introduced
|
||||
the new configuration system. The album art and lyrics plugins also got a
|
||||
little love.
|
||||
|
||||
If you're upgrading from 1.0.0 or earlier, this release (like the 1.1 betas)
|
||||
will automatically migrate your configuration to the new system. See
|
||||
:doc:`/guides/migration`.
|
||||
|
||||
* :doc:`/plugins/embedart`: The ``embedart`` command now embeds each album's
|
||||
associated art by default. The ``--file`` option invokes the old behavior,
|
||||
|
|
@ -14,6 +22,10 @@ Changelog
|
|||
guess more than 200 characters. This prevents errors on systems where the
|
||||
maximum length was misreported. You can, of course, override this default
|
||||
with the :ref:`max_filename_length` option.
|
||||
* :doc:`/plugins/fetchart`: Two new configuration options were added:
|
||||
``cover_names``, the list of keywords used to identify preferred images, and
|
||||
``cautious``, which lets you avoid falling back to images that don't contain
|
||||
those keywords. Thanks to Fabrice Laporte.
|
||||
* 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.
|
||||
|
|
|
|||
|
|
@ -67,17 +67,27 @@ Currently, this plugin searches for art in the local filesystem as well as on
|
|||
the Cover Art Archive, Amazon, and AlbumArt.org (in that order).
|
||||
|
||||
When looking for local album art, beets checks for image files located in the
|
||||
same folder as the music files you're importing. If you have an image file
|
||||
called "cover," "front," "art," "album," for "folder" alongside your music,
|
||||
beets will treat it as album art and skip searching any online databases.
|
||||
same folder as the music files you're importing. Beets prefers to use an image
|
||||
file whose name contains "cover", "front", "art", "album" or "folder", but in
|
||||
the absence of well-known names, it will use any image file in the same folder
|
||||
as your music files.
|
||||
|
||||
When you choose to apply changes during an import, beets searches all sources
|
||||
for album art. For "as-is" imports (and non-autotagged imports using the ``-A``
|
||||
flag), beets only looks for art on the local filesystem.
|
||||
You can change the list of filename keywords using the ``cover_names`` config
|
||||
option. Or, to use *only* filenames containing the keywords and not fall back
|
||||
to any image, set ``cautious`` to true. For example::
|
||||
|
||||
fetchart:
|
||||
cautious: true
|
||||
cover_names: front back
|
||||
|
||||
By default, remote (Web) art sources are only queried if no local art is found
|
||||
in the filesystem. To query remote sources every time, set the
|
||||
``remote_priority`` configuration option to false.
|
||||
``remote_priority`` configuration option to true, which will cause beets to
|
||||
prefer remote cover art over any local image files.
|
||||
|
||||
When you choose to apply changes during an import, beets will search for art as
|
||||
described above. For "as-is" imports (and non-autotagged imports using the
|
||||
``-A`` flag), beets only looks for art on the local filesystem.
|
||||
|
||||
Embedding Album Art
|
||||
-------------------
|
||||
|
|
|
|||
|
|
@ -195,7 +195,7 @@ Ordinary metadata:
|
|||
* encoder
|
||||
|
||||
.. _artist credit: http://wiki.musicbrainz.org/Artist_Credit
|
||||
.. _list of type names: http://wiki.musicbrainz.org/Development/XML_Web_Service/Version_2#Release_Type_and_Status
|
||||
.. _list of type names: http://musicbrainz.org/doc/Release_Group/Type
|
||||
|
||||
Audio information:
|
||||
|
||||
|
|
|
|||
|
|
@ -58,18 +58,27 @@ class FSArtTest(_common.TestCase):
|
|||
|
||||
def test_finds_jpg_in_directory(self):
|
||||
_common.touch(os.path.join(self.dpath, 'a.jpg'))
|
||||
fn = fetchart.art_in_path(self.dpath)
|
||||
fn = fetchart.art_in_path(self.dpath, ('art',), False)
|
||||
self.assertEqual(fn, os.path.join(self.dpath, 'a.jpg'))
|
||||
|
||||
def test_appropriately_named_file_takes_precedence(self):
|
||||
_common.touch(os.path.join(self.dpath, 'a.jpg'))
|
||||
_common.touch(os.path.join(self.dpath, 'cover.jpg'))
|
||||
fn = fetchart.art_in_path(self.dpath)
|
||||
self.assertEqual(fn, os.path.join(self.dpath, 'cover.jpg'))
|
||||
_common.touch(os.path.join(self.dpath, 'art.jpg'))
|
||||
fn = fetchart.art_in_path(self.dpath, ('art',), False)
|
||||
self.assertEqual(fn, os.path.join(self.dpath, 'art.jpg'))
|
||||
|
||||
def test_non_image_file_not_identified(self):
|
||||
_common.touch(os.path.join(self.dpath, 'a.txt'))
|
||||
fn = fetchart.art_in_path(self.dpath)
|
||||
fn = fetchart.art_in_path(self.dpath, ('art',), False)
|
||||
self.assertEqual(fn, None)
|
||||
|
||||
def test_cautious_skips_fallback(self):
|
||||
_common.touch(os.path.join(self.dpath, 'a.jpg'))
|
||||
fn = fetchart.art_in_path(self.dpath, ('art',), True)
|
||||
self.assertEqual(fn, None)
|
||||
|
||||
def test_empty_dir(self):
|
||||
fn = fetchart.art_in_path(self.dpath, ('art',), True)
|
||||
self.assertEqual(fn, None)
|
||||
|
||||
class CombinedTest(_common.TestCase):
|
||||
|
|
@ -107,11 +116,11 @@ class CombinedTest(_common.TestCase):
|
|||
self.assertEqual(artpath, None)
|
||||
|
||||
def test_main_interface_gives_precedence_to_fs_art(self):
|
||||
_common.touch(os.path.join(self.dpath, 'a.jpg'))
|
||||
_common.touch(os.path.join(self.dpath, 'art.jpg'))
|
||||
fetchart.urllib.urlretrieve = MockUrlRetrieve('image/jpeg')
|
||||
album = _common.Bag(asin='xxxx')
|
||||
artpath = fetchart.art_for_album(album, [self.dpath])
|
||||
self.assertEqual(artpath, os.path.join(self.dpath, 'a.jpg'))
|
||||
self.assertEqual(artpath, os.path.join(self.dpath, 'art.jpg'))
|
||||
|
||||
def test_main_interface_falls_back_to_amazon(self):
|
||||
fetchart.urllib.urlretrieve = MockUrlRetrieve('image/jpeg')
|
||||
|
|
@ -150,12 +159,12 @@ class CombinedTest(_common.TestCase):
|
|||
self.assertFalse(mock_retrieve.fetched)
|
||||
|
||||
def test_local_only_gets_fs_image(self):
|
||||
_common.touch(os.path.join(self.dpath, 'a.jpg'))
|
||||
_common.touch(os.path.join(self.dpath, 'art.jpg'))
|
||||
mock_retrieve = MockUrlRetrieve('image/jpeg')
|
||||
fetchart.urllib.urlretrieve = mock_retrieve
|
||||
album = _common.Bag(mb_albumid='releaseid', asin='xxxx')
|
||||
artpath = fetchart.art_for_album(album, [self.dpath], local_only=True)
|
||||
self.assertEqual(artpath, os.path.join(self.dpath, 'a.jpg'))
|
||||
artpath = fetchart.art_for_album(album, [self.dpath], None, local_only=True)
|
||||
self.assertEqual(artpath, os.path.join(self.dpath, 'art.jpg'))
|
||||
self.assertFalse(self.urlopen_called)
|
||||
self.assertFalse(mock_retrieve.fetched)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue