diff --git a/beetsplug/lyrics.py b/beetsplug/lyrics.py index cc491bcb2..7b12ce401 100644 --- a/beetsplug/lyrics.py +++ b/beetsplug/lyrics.py @@ -27,8 +27,7 @@ import itertools from HTMLParser import HTMLParseError from beets.plugins import BeetsPlugin -from beets import ui -from beets import config +from beets import config, ui, util from beets.util import feat_tokens @@ -431,6 +430,11 @@ def fetch_google(artist, title): # Plugin logic. +SOURCES_ALL = {'google': fetch_google, + 'lyricwiki': fetch_lyricswiki, + 'lyrics.com': fetch_lyricscom, + 'musixmatch': fetch_musixmatch} + class LyricsPlugin(BeetsPlugin): def __init__(self): @@ -441,12 +445,16 @@ class LyricsPlugin(BeetsPlugin): 'google_API_key': None, 'google_engine_ID': u'009217259823014548361:lndtuqkycfu', 'fallback': None, + 'sources': SOURCES_ALL }) - self.backends = [fetch_lyricswiki, fetch_lyricscom] - - if self.config['google_API_key'].get(): - self.backends.insert(0, fetch_google) + if not self.config['google_API_key'].get(): + SOURCES_ALL.pop('google', None) + self.config['sources'] = util.sanitize_choices( + self.config['sources'].as_str_seq(), SOURCES_ALL.keys()) + self.backends = [] + for key in self.config['sources'].as_str_seq(): + self.backends.append(SOURCES_ALL[key]) def commands(self): cmd = ui.Subcommand('lyrics', help='fetch song lyrics') diff --git a/docs/changelog.rst b/docs/changelog.rst index e0a9ed6b2..9aecb823b 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -11,6 +11,8 @@ library by typing ``pip install requests`` or the equivalent for your OS. New: * :doc:`/plugins/lyrics`: Add musixmatch source. +* :doc:`/plugins/lyrics`: New ``sources`` config option that lets you choose + exactly where to look for lyrics and in which order. * :doc:`/plugins/lyrics`: Add brazilian and hispanic sources to Google custom search engine. * A new :doc:`/plugins/permissions` makes it easy to fix permissions on music diff --git a/docs/plugins/lyrics.rst b/docs/plugins/lyrics.rst index 46b40e17f..d2a4ca593 100644 --- a/docs/plugins/lyrics.rst +++ b/docs/plugins/lyrics.rst @@ -43,8 +43,13 @@ configuration file. The available options are: backend). Default: None. - **google_engine_ID**: The custom search engine to use. - Default: The beets custom search engine, which gathers a list of sources + Default: The `beets custom search engine`_, which gathers a list of sources known to be scrapeable. +- **sources**: List of sources to search for lyrics. An asterisk `*` expands + to all available sources. + Default: ``google lyricwiki lyrics.com musixmatch``, i.e., all sources. + *google* source will be automatically deactivated if no `google_engine_ID` is + setup. Here's an example of ``config.yaml``:: @@ -53,6 +58,7 @@ Here's an example of ``config.yaml``:: google_API_key: AZERTYUIOPQSDFGHJKLMWXCVBN1234567890_ab google_engine_ID: 009217259823014548361:lndtuqkycfu +.. _beets custom search engine: https://www.google.com:443/cse/publicurl?cx=009217259823014548361:lndtuqkycfu Fetching Lyrics Manually ------------------------ @@ -93,7 +99,7 @@ default, beets use a list of sources known to be scrapeable. .. _define a custom search engine: http://www.google.com/cse/all Note that the Google custom search API is limited to 100 queries per day. -After that, the lyrics plugin will fall back on its other data sources. +After that, the lyrics plugin will fall back on other declared data sources. .. _pip: http://www.pip-installer.org/ .. _BeautifulSoup: http://www.crummy.com/software/BeautifulSoup/bs4/doc/ diff --git a/test/test_fetchart.py b/test/test_fetchart.py index 8b77914d6..5e36f9145 100644 --- a/test/test_fetchart.py +++ b/test/test_fetchart.py @@ -12,8 +12,6 @@ # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. -from beetsplug import fetchart - import os.path from _common import unittest from helper import TestHelper @@ -43,17 +41,6 @@ class FetchartCliTest(unittest.TestCase, TestHelper): with open(cover_path, 'r') as f: self.assertEqual(f.read(), 'IMAGE') - def test_sanitize_sources(self): - self.assertEqual(fetchart.sanitize_sources(['google', 'unknown']), - ['google']) - self.assertEqual(fetchart.sanitize_sources(['google', 'google']), - ['google']) - res = fetchart.sanitize_sources(['google', '*', 'amazon']) - # don't check strict egality on lengths as itunes source may be removed - # by plugin - self.assertTrue(len(res) >= len(fetchart.SOURCES_ALL) - 1 and - res[0] == 'google' and res[-1] == 'amazon') - def suite(): return unittest.TestLoader().loadTestsFromName(__name__) diff --git a/test/test_util.py b/test/test_util.py new file mode 100644 index 000000000..6dd54ff49 --- /dev/null +++ b/test/test_util.py @@ -0,0 +1,32 @@ +# This file is part of beets. +# Copyright 2013, Adrian Sampson. +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. + +from _common import unittest +from beets import util + + +class UtilTest(unittest.TestCase): + def test_sanitize_choices(self): + self.assertEqual(util.sanitize_choices(['A', 'Z'], ('A', 'B')), + ['A']) + self.assertEqual(util.sanitize_choices(['A', 'A'], ('A')), ['A']) + self.assertEqual(util.sanitize_choices(['D', '*', 'A'], + ('A', 'B', 'C', 'D')), ['D', 'B', 'C', 'A']) + + +def suite(): + return unittest.TestLoader().loadTestsFromName(__name__) + +if __name__ == '__main__': + unittest.main(defaultTest='suite')