diff --git a/beetsplug/lyrics.py b/beetsplug/lyrics.py index f6092f625..92757a40a 100644 --- a/beetsplug/lyrics.py +++ b/beetsplug/lyrics.py @@ -25,8 +25,8 @@ import re import requests import unicodedata import warnings -from six.moves import urllib import six +from six.moves import urllib try: from bs4 import SoupStrainer, BeautifulSoup @@ -144,29 +144,32 @@ def search_pairs(item): The method also tries to split multiple titles separated with `/`. """ + def generate_alternatives(string, patterns): + """Generate string alternatives by extracting first matching group for + each given pattern.""" + alternatives = [string] + for pattern in patterns: + match = re.search(pattern, string, re.IGNORECASE) + if match: + alternatives.append(match.group(1)) + return alternatives + title, artist = item.title, item.artist - titles = [title] - artists = [artist] - # Remove any featuring artists from the artists name - pattern = r"(.*?) {0}".format(plugins.feat_tokens()) - match = re.search(pattern, artist, re.IGNORECASE) - if match: - artists.append(match.group(1)) + patterns = [ + # Remove any featuring artists from the artists name + r"(.*?) {0}".format(plugins.feat_tokens())] + artists = generate_alternatives(artist, patterns) - # Remove a parenthesized suffix from a title string. Common - # examples include (live), (remix), and (acoustic). - pattern = r"(.+?)\s+[(].*[)]$" - match = re.search(pattern, title, re.IGNORECASE) - if match: - titles.append(match.group(1)) - - # Remove any featuring artists from the title - pattern = r"(.*?) {0}".format(plugins.feat_tokens(for_artist=False)) - for title in titles[:]: - match = re.search(pattern, title, re.IGNORECASE) - if match: - titles.append(match.group(1)) + patterns = [ + # Remove a parenthesized suffix from a title string. Common + # examples include (live), (remix), and (acoustic). + r"(.+?)\s+[(].*[)]$", + # Remove any featuring artists from the title + r"(.*?) {0}".format(plugins.feat_tokens(for_artist=False)), + # Remove part of title after colon ':' for songs with subtitles + r"(.+?)\s*:.*"] + titles = generate_alternatives(title, patterns) # Check for a dual song (e.g. Pink Floyd - Speak to Me / Breathe) # and each of them. diff --git a/docs/changelog.rst b/docs/changelog.rst index 4c94af42b..2f09c0599 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -60,6 +60,8 @@ And there are a few bug fixes too: This is fixed. :bug:`2168` * :doc:`/plugins/embyupdate`: Fixes authentication header problem that caused a problem that it was not possible to get tokens from the Emby API. +* :doc:`/plugins/lyrics`: Search for lyrics using the title part preceding the + colon character. :bug:`2206` The last release, 1.3.19, also erroneously reported its version as "1.3.18" when you typed ``beet version``. This has been corrected. diff --git a/test/test_lyrics.py b/test/test_lyrics.py index d49c4d980..429dee4e8 100644 --- a/test/test_lyrics.py +++ b/test/test_lyrics.py @@ -84,6 +84,10 @@ class LyricsPluginTest(unittest.TestCase): self.assertIn(('Alice', ['song']), lyrics.search_pairs(item)) + item = Item(artist='Alice and Bob', title='song') + self.assertEqual(('Alice and Bob', ['song']), + list(lyrics.search_pairs(item))[0]) + def test_search_pairs_multi_titles(self): item = Item(title='1 / 2', artist='A') self.assertIn(('A', ['1 / 2']), lyrics.search_pairs(item)) @@ -118,6 +122,10 @@ class LyricsPluginTest(unittest.TestCase): self.assertNotIn(('A', ['Song']), lyrics.search_pairs(item)) self.assertIn(('A', ['Song and B']), lyrics.search_pairs(item)) + item = Item(title='Song: B', artist='A') + self.assertIn(('A', ['Song']), lyrics.search_pairs(item)) + self.assertIn(('A', ['Song: B']), lyrics.search_pairs(item)) + def test_remove_credits(self): self.assertEqual( lyrics.remove_credits("""It's close to midnight