diff --git a/beetsplug/embedart.py b/beetsplug/embedart.py index afe8f86fa..71681f024 100644 --- a/beetsplug/embedart.py +++ b/beetsplug/embedart.py @@ -189,7 +189,7 @@ class EmbedCoverArtPlugin(BeetsPlugin): def remove_artfile(self, album): """Possibly delete the album art file for an album (if the - appropriate configuration option is enabled. + appropriate configuration option is enabled). """ if self.config['remove_art_file'] and album.artpath: if os.path.isfile(album.artpath): diff --git a/beetsplug/fetchart.py b/beetsplug/fetchart.py index 673f56169..d7a885315 100644 --- a/beetsplug/fetchart.py +++ b/beetsplug/fetchart.py @@ -31,7 +31,7 @@ from beets import util from beets import config from beets.mediafile import image_mime_type from beets.util.artresizer import ArtResizer -from beets.util import confit +from beets.util import confit, sorted_walk from beets.util import syspath, bytestring_path, py3_path import six @@ -666,12 +666,16 @@ class FileSystem(LocalArtSource): # Find all files that look like images in the directory. images = [] - for fn in os.listdir(syspath(path)): - fn = bytestring_path(fn) - for ext in IMAGE_EXTENSIONS: - if fn.lower().endswith(b'.' + ext) and \ - os.path.isfile(syspath(os.path.join(path, fn))): - images.append(fn) + ignore = config['ignore'].as_str_seq() + ignore_hidden = config['ignore_hidden'].get(bool) + for _, _, files in sorted_walk(path, ignore=ignore, + ignore_hidden=ignore_hidden): + for fn in files: + fn = bytestring_path(fn) + for ext in IMAGE_EXTENSIONS: + if fn.lower().endswith(b'.' + ext) and \ + os.path.isfile(syspath(os.path.join(path, fn))): + images.append(fn) # Look for "preferred" filenames. images = sorted(images, diff --git a/docs/changelog.rst b/docs/changelog.rst index cfe7924db..c1382b61c 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -115,6 +115,7 @@ Fixes: * The ``%title`` template function now works correctly with apostrophes. Thanks to :user:`GuilhermeHideki`. :bug:`3033` +* Fetchart now respects the ``ignore`` and ``ignore_hidden`` settings. :bug:`1632` .. _python-itunes: https://github.com/ocelma/python-itunes diff --git a/test/test_fetchart.py b/test/test_fetchart.py index 91bc34101..8288e8f71 100644 --- a/test/test_fetchart.py +++ b/test/test_fetchart.py @@ -15,7 +15,9 @@ from __future__ import division, absolute_import, print_function +import ctypes import os +import sys import unittest from test.helper import TestHelper from beets import util @@ -29,21 +31,31 @@ class FetchartCliTest(unittest.TestCase, TestHelper): self.config['fetchart']['cover_names'] = 'c\xc3\xb6ver.jpg' self.config['art_filename'] = 'mycover' self.album = self.add_album() + self.cover_path = os.path.join(self.album.path, b'mycover.jpg') def tearDown(self): self.unload_plugins() self.teardown_beets() + def check_cover_is_stored(self): + self.assertEqual(self.album['artpath'], self.cover_path) + with open(util.syspath(self.cover_path), 'r') as f: + self.assertEqual(f.read(), 'IMAGE') + + def hide_file_windows(self): + hidden_mask = 2 + success = ctypes.windll.kernel32.SetFileAttributesW(self.cover_path, + hidden_mask) + if not success: + self.skipTest("unable to set file attributes") + def test_set_art_from_folder(self): self.touch(b'c\xc3\xb6ver.jpg', dir=self.album.path, content='IMAGE') self.run_command('fetchart') - cover_path = os.path.join(self.album.path, b'mycover.jpg') self.album.load() - self.assertEqual(self.album['artpath'], cover_path) - with open(util.syspath(cover_path), 'r') as f: - self.assertEqual(f.read(), 'IMAGE') + self.check_cover_is_stored() def test_filesystem_does_not_pick_up_folder(self): os.makedirs(os.path.join(self.album.path, b'mycover.jpg')) @@ -51,6 +63,47 @@ class FetchartCliTest(unittest.TestCase, TestHelper): self.album.load() self.assertEqual(self.album['artpath'], None) + def test_filesystem_does_not_pick_up_ignored_file(self): + self.touch(b'co_ver.jpg', dir=self.album.path, content='IMAGE') + self.config['ignore'] = ['*_*'] + self.run_command('fetchart') + self.album.load() + self.assertEqual(self.album['artpath'], None) + + def test_filesystem_picks_up_non_ignored_file(self): + self.touch(b'cover.jpg', dir=self.album.path, content='IMAGE') + self.config['ignore'] = ['*_*'] + self.run_command('fetchart') + self.album.load() + self.check_cover_is_stored() + + def test_filesystem_does_not_pick_up_hidden_file(self): + self.touch(b'.cover.jpg', dir=self.album.path, content='IMAGE') + if sys.platform == 'win32': + self.hide_file_windows() + self.config['ignore'] = [] # By default, ignore includes '.*'. + self.config['ignore_hidden'] = True + self.run_command('fetchart') + self.album.load() + self.assertEqual(self.album['artpath'], None) + + def test_filesystem_picks_up_non_hidden_file(self): + self.touch(b'cover.jpg', dir=self.album.path, content='IMAGE') + self.config['ignore_hidden'] = True + self.run_command('fetchart') + self.album.load() + self.check_cover_is_stored() + + def test_filesystem_picks_up_hidden_file(self): + self.touch(b'.cover.jpg', dir=self.album.path, content='IMAGE') + if sys.platform == 'win32': + self.hide_file_windows() + self.config['ignore'] = [] # By default, ignore includes '.*'. + self.config['ignore_hidden'] = False + self.run_command('fetchart') + self.album.load() + self.check_cover_is_stored() + def suite(): return unittest.TestLoader().loadTestsFromName(__name__)