diff --git a/beets/util/__init__.py b/beets/util/__init__.py index 529bbb2f3..56134621d 100644 --- a/beets/util/__init__.py +++ b/beets/util/__init__.py @@ -678,3 +678,17 @@ def max_filename_length(path, limit=MAX_FILENAME_LENGTH): return min(res[9], limit) else: return limit + + +def feat_tokens(extended=False): + """Returns the tokens to use to detect featuring artists in strings.""" + + FEAT_SPECIAL_CHARS = ['&', 'feat.', 'ft.'] + FEAT_WORDS = ['ft', 'featuring', 'feat'] + if extended: + FEAT_WORDS += ['with', 'vs', 'and', 'con'] + regex = r'(%s)' % '|'.join(['\\b%s\\b' % re.escape(x) for x in FEAT_WORDS]) + if extended: + regex = r'(%s|%s)' % \ + ('|'.join([re.escape(x) for x in FEAT_SPECIAL_CHARS]), regex) + return regex diff --git a/beetsplug/ftintitle.py b/beetsplug/ftintitle.py index 5de16f69a..3fc1badb7 100644 --- a/beetsplug/ftintitle.py +++ b/beetsplug/ftintitle.py @@ -16,7 +16,7 @@ """ from beets.plugins import BeetsPlugin from beets import ui -from beets.util import displayable_path +from beets.util import displayable_path, feat_tokens from beets import config import logging import re @@ -30,24 +30,24 @@ def split_on_feat(artist): artist, which is always a string, and the featuring artist, which may be a string or None if none is present. """ + # split on the first "feat". + feat_tokens(extended=True).strip('()') parts = re.split( - r'[fF]t\.|[fF]eaturing|[fF]eat\.|\b[wW]ith\b|&|vs\.|and', - artist, - 1, # Only split on the first "feat". - ) + feat_tokens(extended=True).translate(None, '()'), + artist, 1, flags=re.IGNORECASE) parts = [s.strip() for s in parts] if len(parts) == 1: return parts[0], None else: - return parts + return tuple(parts) def contains_feat(title): """Determine whether the title contains a "featured" marker. """ return bool(re.search( - r'[fF]t\.|[fF]eaturing|[fF]eat\.|\b[wW]ith\b|&', - title, + feat_tokens(extended=True), + title, flags=re.IGNORECASE )) diff --git a/beetsplug/lyrics.py b/beetsplug/lyrics.py index 73821ee22..487628ee6 100644 --- a/beetsplug/lyrics.py +++ b/beetsplug/lyrics.py @@ -29,6 +29,7 @@ from HTMLParser import HTMLParseError from beets.plugins import BeetsPlugin from beets import ui from beets import config +from beets.util import feat_tokens # Global logger. @@ -137,7 +138,7 @@ def search_pairs(item): artists = [artist] # Remove any featuring artists from the artists name - pattern = r"(.*?) (&|\b(and|ft|feat(uring)?\b))" + pattern = r"(.*?) %s" % feat_tokens(extended=True) match = re.search(pattern, artist, re.IGNORECASE) if match: artists.append(match.group(1)) @@ -150,8 +151,8 @@ def search_pairs(item): titles.append(match.group(1)) # Remove any featuring artists from the title - pattern = r"(.*?) \b(ft|feat(uring)?)\b" - for title in titles: + pattern = r"(.*?) %s" % feat_tokens() + for title in titles[:]: match = re.search(pattern, title, re.IGNORECASE) if match: titles.append(match.group(1))