Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Musixmatch Support #84

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
11 changes: 2 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ It is intended as a replacement of the built-in lyrics plugin of Rhythmbox with
Lyrics sources
---------------

- Musixmatch
- Lyricwiki.org
- Letras.terra.com.br
- Vagalume.com.br
Expand All @@ -36,7 +37,7 @@ Requirements

The 'master' branch supports Rhythmbox 3.0 and above. **It is incompatible with older Rhythmbox 2.xx versions!**

To get the plugin for Rhythmbox 2.xx, change to branch 'RB2'! It provides the last version compatible with Rhythmbox 2.xx, but please note, that it will not be updated or developed any further.
To get the plugin for Rhythmbox 2.xx, change to branch 'RB2'! It provides the last version compatible with Rhythmbox 2.xx, but please note, that it will not be updated or developed any further and it does not have Musixmatch support.

To install lLyrics from source you will need the package `gettext`.

Expand All @@ -49,14 +50,6 @@ lLyrics can be run without the need of any additional packages, but it is recomm
Installation
---------------

#### Ubuntu & derivates: PPA ####

In Ubuntu based distribution, you can install this plugin via [this PPA by fossfreedom](https://launchpad.net/~fossfreedom/+archive/rhythmbox-plugins).

#### Archlinux: AUR ####

Archlinux user can install the plugin via [this AUR package](https://aur.archlinux.org/packages/rhythmbox-llyrics/).

#### Manual installation ####

1.) Press the "Download ZIP" button and extract the .zip file.
Expand Down
109 changes: 109 additions & 0 deletions lLyrics/MusixmatchParser.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import functools
import json
import traceback
import urllib.request
import urllib.parse
from lxml import html


class Parser(object):

def __init__(self, artist, title):
self.artist = artist
self.title = title
self.lyrics = ""
self.API_KEY = '1a2244035bb2332c83f241548413509f'
self.API_URL = 'https://api.musixmatch.com/ws/1.1/'

def parse(self):
# URL encode artist and title strings
encoded_artist = urllib.parse.quote(self.artist)
encoded_title = urllib.parse.quote(self.title)

# Match & Fetch Track Details
METHOD = 'matcher.track.get'
query = '%s%s?apikey=%s' % (self.API_URL, METHOD, self.API_KEY)

# Add artist or title to query URL
if encoded_artist:
query += '&q_artist=%s' % (encoded_artist)
if encoded_title:
query += '&q_track=%s' % (encoded_title)

# Call the API
try:
resp = urllib.request.urlopen(query, None, 5)
except:
print("Cannot connect to Musixmatch\ncall Musixmatch API:%s" % (query))
traceback.print_exc()
return ""

# Stop if HTTP Response code is not 200
if resp.status != 200:
print("Error! call Musixmatch API:%s\nHTML Reponse Code:%s" % (query, resp.status))
return ""

# Parse JSON response
resp = resp.read().decode('utf-8')
resp = json.loads(resp)

# Check API Response Status Code
status_code = resp['message']['header']['status_code']
if status_code != 200:
print("call Musixmatch API: %s\nError from Musixmatch API>> %s: %s" % (query, status_code, self.get_error_details_from_status_code(status_code)))
return ""

# Fetch and log track details and confidence score from the API
track_details = resp['message']['body']['track']
confidence_score = resp['message']['header']['confidence']
print("Musixmatch Identified Track(Confidence %s%%) Details:>> %s" % (confidence_score, track_details))

# Find if lyrics are available or terminate if not available
has_lyrics = resp['message']['body']['track']['has_lyrics']
if has_lyrics == 0:
print("Musixmatch does not have lyrics for this song")
return ""

# Fetch track URL for getting lyrics
track_url = track_details['track_share_url']
# Fetch and return lyrics
self.lyrics = self.get_lyrics(track_url)

return self.lyrics

def get_lyrics(self, url):

try:
lyrics_request = urllib.request.Request(url, headers={
'Host': 'www.musixmatch.com',
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36'
})
lyrics_html = urllib.request.urlopen(lyrics_request).read()
except:
print("Cannot connect to Musixmatch")
traceback.print_exc()
return ""

# Parse response to a html page
lyrics_html = html.fromstring(lyrics_html)
# Extract lyrics from html
lyrics = lyrics_html.xpath('//span[@class="lyrics__content__ok"]/text()')
# Join parts of lyrics
lyrics = functools.reduce(lambda a, b: a+b, lyrics)

return lyrics

def get_error_details_from_status_code(self, statusCode):
details = {
200: "The request was successful.",
400: "The request had bad syntax or was inherently impossible to be satisfied.",
401: "Authentication failed, probably because of invalid/missing API key.",
402: "The usage limit has been reached, either you exceeded per day requests limits or your balance is insufficient.",
403: "You are not authorized to perform this operation.",
404: "The requested resource was not found.",
405: "The requested method was not found.",
500: "Ops. Something were wrong.",
503: "Our system is a bit busy at the moment and your request can't be satisfied."
}
# Return error details based on API's status code
return details.get(statusCode, 'Some error occurred')
5 changes: 3 additions & 2 deletions lLyrics/lLyrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import DarklyricsParser
import GeniusParser
import VagalumeParser
import MusixmatchParser
import Util

from lLyrics_rb3compat import ActionGroup
Expand Down Expand Up @@ -94,7 +95,7 @@
LYRICS_ARTIST_REPLACE = [("/", "-"), (" & ", " and ")]

LYRICS_SOURCES = ["Lyricwiki.org", "Letras.terra.com.br", "Metrolyrics.com", "AZLyrics.com", "Lyricsmania.com",
"Vagalume.com.br", "Genius.com", "Darklyrics.com", "Chartlyrics.com"]
"Vagalume.com.br", "Genius.com", "Darklyrics.com", "Chartlyrics.com", "Musixmatch"]


class lLyrics(GObject.Object, Peas.Activatable):
Expand All @@ -117,7 +118,7 @@ def do_activate(self):
"Metrolyrics.com": MetrolyricsParser, "AZLyrics.com": AZLyricsParser,
"Lyricsmania.com": LyricsmaniaParser, "Chartlyrics.com": ChartlyricsParser,
"Darklyrics.com": DarklyricsParser, "Genius.com": GeniusParser,
"Vagalume.com.br": VagalumeParser})
"Vagalume.com.br": VagalumeParser, "Musixmatch": MusixmatchParser})
self.add_builtin_lyrics_sources()

# Get the user preferences
Expand Down
8 changes: 4 additions & 4 deletions org.gnome.rhythmbox.plugins.llyrics.gschema.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@
<schema id="org.gnome.rhythmbox.plugins.llyrics" path="/org/gnome/rhythmbox/plugins/llyrics/">

<key name="active-sources" type="as">
<default>['Lyricwiki.org', 'Letras.terra.com.br', 'Vagalume.com.br', 'Metrolyrics.com', 'AZLyrics.com', 'Lyricsmania.com', 'Darklyrics.com', 'Chartlyrics.com', 'Genius.com']</default>
<default>['Musixmatch', 'Lyricwiki.org', 'Letras.terra.com.br', 'Vagalume.com.br', 'Metrolyrics.com', 'AZLyrics.com', 'Lyricsmania.com', 'Darklyrics.com', 'Chartlyrics.com', 'Genius.com']</default>
<summary>List of lyrics sources to be scanned</summary>
<description>Possible values are: 'Lyricwiki.org', 'Letras.terra.com.br', 'Metrolyrics.com', 'AZLyrics.com', 'Lyricsmania.com', 'Vagalume.com.br', 'Darklyrics.com', 'Chartlyrics.com', 'Genius.com'</description>
<description>Possible values are: 'Musixmatch', 'Lyricwiki.org', 'Letras.terra.com.br', 'Metrolyrics.com', 'AZLyrics.com', 'Lyricsmania.com', 'Vagalume.com.br', 'Darklyrics.com', 'Chartlyrics.com', 'Genius.com'</description>
</key>

<key name="scanning-order" type="as">
<default>['Lyricwiki.org', 'Letras.terra.com.br', 'Vagalume.com.br', 'Metrolyrics.com', 'AZLyrics.com', 'Lyricsmania.com', 'Genius.com', 'Darklyrics.com', 'Chartlyrics.com']</default>
<default>['Musixmatch', 'Lyricwiki.org', 'Letras.terra.com.br', 'Vagalume.com.br', 'Metrolyrics.com', 'AZLyrics.com', 'Lyricsmania.com', 'Genius.com', 'Darklyrics.com', 'Chartlyrics.com']</default>
<summary>Sources are scanned in this order</summary>
<description>Possible values are: 'Lyricwiki.org', 'Letras.terra.com.br', 'Metrolyrics.com', 'AZLyrics.com', 'Lyricsmania.com', 'Vagalume.com.br', 'Genius.com', 'Darklyrics.com', 'Chartlyrics.com'</description>
<description>Possible values are: 'Musixmatch', 'Lyricwiki.org', 'Letras.terra.com.br', 'Metrolyrics.com', 'AZLyrics.com', 'Lyricsmania.com', 'Vagalume.com.br', 'Genius.com', 'Darklyrics.com', 'Chartlyrics.com'</description>
</key>

<key name="show-first" type="b">
Expand Down