diff --git a/beetsplug/lyrics.py b/beetsplug/lyrics.py index 59937d480..2f1e3529e 100644 --- a/beetsplug/lyrics.py +++ b/beetsplug/lyrics.py @@ -224,6 +224,70 @@ class MusiXmatch(SymbolsReplaced): return lyrics.strip(',"').replace('\\n', '\n') +class Genius(Backend): + """Fetch lyrics from Genius via genius-api.""" + def __init__(self, config, log): + super(Genius, self).__init__(config, log) + self.api_key = config['genius_api_key'].get(unicode) + self.headers = {'Authorization': "Bearer %s" % self.api_key} + + def search_genius(self, artist, title): + query = u"%s %s" % (artist, title) + url = u'https://api.genius.com/search?q=%s' \ + % (urllib.quote(query.encode('utf8'))) + + data = requests.get( + url, + headers=self.headers, + allow_redirects=True + ).content + + return json.loads(data) + + def get_lyrics(self, link): + url = u'http://genius-api.com/api/lyricsInfo' + + data = requests.post( + url, + data={'link': link}, + headers=self.headers, + allow_redirects=True + ).content + + return json.loads(data) + + def build_lyric_string(self, lyrics): + if 'lyrics' not in lyrics: + return + sections = lyrics['lyrics']['sections'] + + lyrics_list = [] + for section in sections: + lyrics_list.append(section['name']) + lyrics_list.append('\n') + for verse in section['verses']: + if 'content' in verse: + lyrics_list.append(verse['content']) + + return ''.join(lyrics_list) + + def fetch(self, artist, title): + search_data = self.search_genius(artist, title) + + if not search_data['meta']['status'] == 200: + return + else: + records = search_data['response']['hits'] + if not records: + return + + record_url = records[0]['result']['url'] + lyric_data = self.get_lyrics(record_url) + lyrics = self.build_lyric_string(lyric_data) + + return lyrics + + class LyricsWiki(SymbolsReplaced): """Fetch lyrics from LyricsWiki.""" URL_PATTERN = 'http://lyrics.wikia.com/%s:%s' @@ -444,12 +508,13 @@ class Google(Backend): class LyricsPlugin(plugins.BeetsPlugin): - SOURCES = ['google', 'lyricwiki', 'lyrics.com', 'musixmatch'] + SOURCES = ['google', 'lyricwiki', 'lyrics.com', 'musixmatch', 'genius'] SOURCE_BACKENDS = { 'google': Google, 'lyricwiki': LyricsWiki, 'lyrics.com': LyricsCom, 'musixmatch': MusiXmatch, + 'genius': Genius, } def __init__(self): @@ -459,12 +524,16 @@ class LyricsPlugin(plugins.BeetsPlugin): 'auto': True, 'google_API_key': None, 'google_engine_ID': u'009217259823014548361:lndtuqkycfu', + 'genius_api_key': + "Ryq93pUGm8bM6eUWwD_M3NOFFDAtp2yEE7W" + "76V-uFL5jks5dNvcGCdarqFjDhP9c", 'fallback': None, 'force': False, 'sources': self.SOURCES, }) self.config['google_API_key'].redact = True self.config['google_engine_ID'].redact = True + self.config['genius_api_key'].redact = True available_sources = list(self.SOURCES) if not self.config['google_API_key'].get() and \ diff --git a/docs/changelog.rst b/docs/changelog.rst index c3b57df03..f819a6b53 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -26,7 +26,7 @@ The new features: * :doc:`/plugins/zero`: The plugin can now use a "whitelist" policy as an alternative to the (default) "blacklist" mode. Thanks to :user:`adkow`. :bug:`1621` :bug:`1641` - +* :doc:`/plugins/lyrics`: Genius.com is now a source for lyrics. Fixes: diff --git a/docs/plugins/lyrics.rst b/docs/plugins/lyrics.rst index 1d91a00eb..b174751db 100644 --- a/docs/plugins/lyrics.rst +++ b/docs/plugins/lyrics.rst @@ -3,11 +3,12 @@ Lyrics Plugin The ``lyrics`` plugin fetches and stores song lyrics from databases on the Web. Namely, the current version of the plugin uses `Lyric Wiki`_, `Lyrics.com`_, -`Musixmatch`_, and, optionally, the Google custom search API. +`Musixmatch`_, `Genius.com`_, and, optionally, the Google custom search API. .. _Lyric Wiki: http://lyrics.wikia.com/ .. _Lyrics.com: http://www.lyrics.com/ .. _Musixmatch: https://www.musixmatch.com/ +.. _Genius.com: http://genius.com/ Fetch Lyrics During Import