diff --git a/README.md b/README.md index 2fe0d51..52b28de 100755 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ To install lLyrics from source you will need the package `gettext`. #### Dependencies #### -lLyrics can be run without the need of any additional packages, but it is recommended to install the python module **"chardet"** for better handling of different encodings. +lLyrics can be run without the need of any additional packages, but it is recommended to install the python module **"chardet"** for better handling of different encodings. The mutagen module is also required to read from the song's metadata. diff --git a/lLyrics/LocalParser.py b/lLyrics/LocalParser.py new file mode 100644 index 0000000..5ca7bdf --- /dev/null +++ b/lLyrics/LocalParser.py @@ -0,0 +1,109 @@ +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +Parses lyrics from a .lyric or .lrc file or from the tags of the track. +""" + +import urllib +import os.path as path +from mutagen.oggvorbis import OggVorbis +from mutagen.oggopus import OggOpus +from mutagen.flac import FLAC +from mutagen.id3 import ID3 + + +class Parser(object): + def __init__(self, artist, title, track_path): + self.artist = artist + self.title = title + self.track_path = track_path + + def parse(self): + # convert the song url to a usable path + path = self.track_path + path = urllib.parse.unquote(path) + path = path.replace("file://", "") + dir = path[0:((path.rfind("/")) + 1)] + file_name = path[((path.rfind("/")) + 1):path.rfind(".")] + out = "" + if path.endswith("mp3"): + out = self.get_id3_lyrics(path) + elif path.endswith("ogg"): + out = self.get_ogg_lyrics(path) + elif path.endswith("opus"): + out = self.get_opus_lyrics(path) + elif path.endswith("flac"): + out = self.get_flac_lyrics(path) + if out is None: + file_path = self.check_for_file(dir, file_name) + if file_path is None: + return "" + with open(file_path) as file: + return file.read() + return out + + def check_for_file(self, dir, file_name): + """ + This only checks for .lrc or .lyric files with the same name as the track or with the same "cleaned" name as + the track. If you have files in any other format, please add it to this function. + """ + if path.isfile(dir + file_name + ".lrc"): + return dir + file_name + ".lrc" + elif path.isfile(dir + file_name + ".lyric"): + return dir + file_name + ".lyric" + elif path.isfile(dir + self.title + ".lrc"): + return dir + self.title + ".lrc" + elif path.isfile(dir + self.title + ".lyric"): + return dir + self.title + ".lyric" + else: + return None + + def get_id3_lyrics(self, path): + try: + file = ID3(path) + except: + return None + if len(file.getall("USLT")) > 0: + out = file.getall("USLT")[0] + return out.text + else: + return None + + def get_opus_lyrics(self, path): + file = OggOpus(path) + return self.get_vorbis_style_lyrics(file) + + def get_ogg_lyrics(self, path): + file = OggVorbis(path) + return self.get_vorbis_style_lyrics(file) + + def get_flac_lyrics(self, path): + file = FLAC(path) + return self.get_vorbis_style_lyrics(file) + + def get_vorbis_style_lyrics(self, file_tags): + """ + Returns lyrics from a mutagen file object that uses vorbis-like tags (FLAC, Vorbis and opus) + """ + out = "" + try: + out = file_tags["LYRICS"] + except: + try: + out = file_tags["UNSYNCEDLYRICS"] + except: + pass + if out != "": + return out[0] + return None diff --git a/lLyrics/lLyrics.py b/lLyrics/lLyrics.py old mode 100755 new mode 100644 index 2bec352..eefcda7 --- a/lLyrics/lLyrics.py +++ b/lLyrics/lLyrics.py @@ -29,6 +29,7 @@ from gi.repository import GdkPixbuf from gi.repository import GLib +import LocalParser import ChartlyricsParser import LyricwikiParser import MetrolyricsParser @@ -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", "Local File"] class lLyrics(GObject.Object, Peas.Activatable): @@ -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, "Local File": LocalParser}) self.add_builtin_lyrics_sources() # Get the user preferences @@ -198,6 +199,7 @@ def do_deactivate(self): self.lyrics_before_edit = None self.edit_event = None self.path_before_edit = None + self.song_url = None self.sources = None self.cache = None self.lyrics_folder = None @@ -472,6 +474,7 @@ def search_lyrics(self, player, entry): # get the song data self.artist = entry.get_string(RB.RhythmDBPropType.ARTIST) self.title = entry.get_string(RB.RhythmDBPropType.TITLE) + self.song_url = entry.get_string(RB.RhythmDBPropType.LOCATION) print("search lyrics for " + self.artist + " - " + self.title) @@ -812,8 +815,10 @@ def get_lyrics_from_source(self, source, artist, title): print("source: " + source) self.current_source = source - - parser = self.dict[source].Parser(artist, title) + if source == "Local File": + parser = self.dict[source].Parser(artist, title, self.song_url) + else: + parser = self.dict[source].Parser(artist, title) try: lyrics = parser.parse() except Exception as e: