diff --git a/beets/plugins.py b/beets/plugins.py index 2b68f2d02..64da5d912 100755 --- a/beets/plugins.py +++ b/beets/plugins.py @@ -16,8 +16,10 @@ import logging import traceback -from collections import defaultdict import inspect +import re +from collections import defaultdict + import beets from beets import mediafile @@ -402,3 +404,33 @@ def send(event, **arguments): argspec = inspect.getargspec(handler).args args = dict((k, v) for k, v in arguments.items() if k in argspec) handler(**args) + + +def feat_tokens(for_artist=True): + """Return a regular expression that matches phrases like "featuring" + that separate a main artist or a song title from secondary artists. + The `for_artist` option determines whether the regex should be + suitable for matching artist fields (the default) or title fields. + """ + feat_words = ['ft', 'featuring', 'feat', 'feat.', 'ft.'] + if for_artist: + feat_words += ['with', 'vs', 'and', 'con', '&'] + return '(?<=\s)(?:{0})(?=\s)'.format( + '|'.join(re.escape(x) for x in feat_words) + ) + + +def sanitize_choices(choices, choices_all): + """Clean up a stringlist configuration attribute: keep only choices + elements present in choices_all, remove duplicate elements, expand '*' + wildcard while keeping original stringlist order. + """ + seen = set() + others = [x for x in choices_all if x not in choices] + print others + res = [] + for s in choices: + if s in list(choices_all) + ['*']: + if not (s in seen or seen.add(s)): + res.extend(list(others) if s == '*' else [s]) + return res diff --git a/beets/util/__init__.py b/beets/util/__init__.py index 14e9b0306..529bbb2f3 100644 --- a/beets/util/__init__.py +++ b/beets/util/__init__.py @@ -678,32 +678,3 @@ def max_filename_length(path, limit=MAX_FILENAME_LENGTH): return min(res[9], limit) else: return limit - - -def feat_tokens(for_artist=True): - """Return a regular expression that matches phrases like "featuring" - that separate a main artist or a song title from secondary artists. - The `for_artist` option determines whether the regex should be - suitable for matching artist fields (the default) or title fields. - """ - feat_words = ['ft', 'featuring', 'feat', 'feat.', 'ft.'] - if for_artist: - feat_words += ['with', 'vs', 'and', 'con', '&'] - return '(?<=\s)(?:{0})(?=\s)'.format( - '|'.join(re.escape(x) for x in feat_words) - ) - - -def sanitize_choices(choices, choices_all): - """Clean up a stringlist configuration attribute by removing unknown or - duplicate string while keeping original order. - """ - seen = set() - others = [x for x in choices_all if x not in choices] - print others - res = [] - for s in choices: - if s in list(choices_all) + ['*']: - if not (s in seen or seen.add(s)): - res.extend(list(others) if s == '*' else [s]) - return res diff --git a/beetsplug/fetchart.py b/beetsplug/fetchart.py index 9beb33663..aa670c5ab 100644 --- a/beetsplug/fetchart.py +++ b/beetsplug/fetchart.py @@ -22,12 +22,12 @@ from tempfile import NamedTemporaryFile import requests -from beets.plugins import BeetsPlugin -from beets.util.artresizer import ArtResizer +from beets import plugins from beets import importer from beets import ui from beets import util from beets import config +from beets.util.artresizer import ArtResizer try: import itunes @@ -319,7 +319,7 @@ def batch_fetch_art(lib, albums, force, maxwidth=None): message)) -class FetchArtPlugin(BeetsPlugin): +class FetchArtPlugin(plugins.BeetsPlugin): def __init__(self): super(FetchArtPlugin, self).__init__() @@ -345,7 +345,7 @@ class FetchArtPlugin(BeetsPlugin): if not HAVE_ITUNES and u'itunes' in SOURCES_ALL: SOURCES_ALL.remove(u'itunes') - self.config['sources'] = util.sanitize_choices( + self.config['sources'] = plugins.sanitize_choices( self.config['sources'].as_str_seq(), SOURCES_ALL) # Asynchronous; after music is added to the library. diff --git a/beetsplug/ftintitle.py b/beetsplug/ftintitle.py index e83836e0e..75134ae9c 100644 --- a/beetsplug/ftintitle.py +++ b/beetsplug/ftintitle.py @@ -14,9 +14,9 @@ """Moves "featured" artists to the title from the artist field. """ -from beets.plugins import BeetsPlugin +from beets import plugins from beets import ui -from beets.util import displayable_path, feat_tokens +from beets.util import displayable_path from beets import config import logging import re @@ -31,7 +31,7 @@ def split_on_feat(artist): may be a string or None if none is present. """ # split on the first "feat". - regex = re.compile(feat_tokens(), re.IGNORECASE) + regex = re.compile(plugins.feat_tokens(), re.IGNORECASE) parts = [s.strip() for s in regex.split(artist, 1)] if len(parts) == 1: return parts[0], None @@ -42,7 +42,7 @@ def split_on_feat(artist): def contains_feat(title): """Determine whether the title contains a "featured" marker. """ - return bool(re.search(feat_tokens(), title, flags=re.IGNORECASE)) + return bool(re.search(plugins.feat_tokens(), title, flags=re.IGNORECASE)) def update_metadata(item, feat_part, drop_feat): @@ -110,7 +110,7 @@ def ft_in_title(item, drop_feat): ui.print_() -class FtInTitlePlugin(BeetsPlugin): +class FtInTitlePlugin(plugins.BeetsPlugin): def __init__(self): super(FtInTitlePlugin, self).__init__() diff --git a/beetsplug/lyrics.py b/beetsplug/lyrics.py index 0567ae68a..6ec5e3a9e 100644 --- a/beetsplug/lyrics.py +++ b/beetsplug/lyrics.py @@ -26,9 +26,8 @@ import difflib import itertools from HTMLParser import HTMLParseError -from beets.plugins import BeetsPlugin -from beets import config, ui, util -from beets.util import feat_tokens +from beets import plugins +from beets import config, ui # Global logger. @@ -144,7 +143,7 @@ def search_pairs(item): artists = [artist] # Remove any featuring artists from the artists name - pattern = r"(.*?) {0}".format(feat_tokens()) + pattern = r"(.*?) {0}".format(plugins.feat_tokens()) match = re.search(pattern, artist, re.IGNORECASE) if match: artists.append(match.group(1)) @@ -157,7 +156,7 @@ def search_pairs(item): titles.append(match.group(1)) # Remove any featuring artists from the title - pattern = r"(.*?) {0}".format(feat_tokens(for_artist=False)) + pattern = r"(.*?) {0}".format(plugins.feat_tokens(for_artist=False)) for title in titles[:]: match = re.search(pattern, title, re.IGNORECASE) if match: @@ -437,7 +436,7 @@ SOURCES_ALL = {'google': fetch_google, 'musixmatch': fetch_musixmatch} -class LyricsPlugin(BeetsPlugin): +class LyricsPlugin(plugins.BeetsPlugin): def __init__(self): super(LyricsPlugin, self).__init__() self.import_stages = [self.imported] @@ -452,7 +451,7 @@ class LyricsPlugin(BeetsPlugin): if not self.config['google_API_key'].get() and \ 'google' in SOURCES_KEYS: SOURCES_KEYS.remove('google') - self.config['sources'] = util.sanitize_choices( + self.config['sources'] = plugins.sanitize_choices( self.config['sources'].as_str_seq(), SOURCES_KEYS) self.backends = [] for key in self.config['sources'].as_str_seq():