diff --git a/headphones/config.py b/headphones/config.py index 7cae3861..176c49cb 100644 --- a/headphones/config.py +++ b/headphones/config.py @@ -91,6 +91,7 @@ _CONFIG_DEFINITIONS = { 'HTTP_ROOT': (str, 'General', '/'), 'HTTP_USERNAME': (str, 'General', ''), 'IGNORED_WORDS': (str, 'General', ''), + 'IGNORED_FOLDERS': (list, 'Advanced', ''), 'INCLUDE_EXTRAS': (int, 'General', 0), 'INTERFACE': (str, 'General', 'default'), 'JOURNAL_MODE': (str, 'Advanced', 'wal'), diff --git a/headphones/helpers.py b/headphones/helpers.py index bc15b015..57715cf1 100644 --- a/headphones/helpers.py +++ b/headphones/helpers.py @@ -13,17 +13,19 @@ # You should have received a copy of the GNU General Public License # along with Headphones. If not, see . -import os -import re -import time -import shutil -import datetime -import headphones -import unicodedata -import sys +from beets.mediafile import MediaFile, FileTypeError, UnreadableFileError from operator import itemgetter -from beets.mediafile import MediaFile, FileTypeError, UnreadableFileError + +import unicodedata +import headphones +import datetime +import fnmatch +import shutil +import time +import sys +import re +import os # Modified from https://github.com/Verrus/beets-plugin-featInTitle RE_FEATURING = re.compile(r"[fF]t\.|[fF]eaturing|[fF]eat\.|\b[wW]ith\b|&|vs\.") @@ -330,6 +332,20 @@ def expand_subfolders(f): return media_folders +def path_match_patterns(path, patterns): + """ + Check if a path matches one or more patterns. The whole path will be + matched be matched against the patterns. + """ + + for pattern in patterns: + if fnmatch.fnmatch(path, pattern): + return True + + # No match + return False + + def extract_data(s): s = s.replace('_', ' ') @@ -474,8 +490,8 @@ def get_downloaded_track_list(albumpath): def preserve_torrent_direcory(albumpath): """ - Copy torrent directory to headphones-modified to keep files for seeding. - """ + Copy torrent directory to headphones-modified to keep files for seeding. + """ from headphones import logger new_folder = os.path.join(albumpath, 'headphones-modified'.encode(headphones.SYS_ENCODING, 'replace')) logger.info("Copying files to 'headphones-modified' subfolder to preserve downloaded files for seeding") diff --git a/headphones/librarysync.py b/headphones/librarysync.py index 3644dbc5..a05d1938 100644 --- a/headphones/librarysync.py +++ b/headphones/librarysync.py @@ -79,12 +79,16 @@ def libraryScan(dir=None, append=False, ArtistID=None, ArtistName=None, cron=Fal latest_subdirectory = [] for r, d, f in helpers.walk_directory(dir): - # Need to abuse slicing to get a copy of the list, doing it directly - # will skip the element after a deleted one using a list comprehension - # will not work correctly for nested subdirectories (os.walk keeps its - # original list) + # Scan for ignored folders. A copy of the list is taken because the + # original list is modified and list comprehensions don't work because + # of logging. + patterns = headphones.CONFIG.IGNORED_FOLDERS + for directory in d[:]: - if directory.startswith("."): + full_path = os.path.join(r, directory) + + if helpers.path_match_patterns(full_path, patterns): + logger.debug("Folder ignored by pattern: %s", full_path) d.remove(directory) for files in f: diff --git a/headphones/postprocessor.py b/headphones/postprocessor.py index 238703da..5359ffd3 100755 --- a/headphones/postprocessor.py +++ b/headphones/postprocessor.py @@ -1078,10 +1078,22 @@ def forcePostProcess(dir=None, expand_subfolders=True, album_dir=None): else: folders.append(path_to_folder) + # Scan for ignored folders. A copy of the list is taken because the original + # list is modified and list comprehensions don't work because of logging. + patterns = headphones.CONFIG.IGNORED_FOLDERS + ignored = 0 + + for folder in folders[:]: + if helpers.path_match_patterns(folder, patterns): + logger.debug("Folder ignored by pattern: %s", folder) + folders.remove(folder) + ignored += 1 + # Log number of folders if folders: - logger.info('Found %i folders to process.', len(folders)) logger.debug('Expanded post processing folders: %s', folders) + logger.info('Found %d folders to process (%d ignored).', + len(folders), ignored) else: logger.info('Found no folders to process. Aborting.') return