# vim: ts=4 ### # # Listen is the legal property of mehdi abaakouk # Copyright (c) 2006 Mehdi Abaakouk # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as # published by the Free Software Foundation # # 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, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # ### import gtk, gobject from xml.dom import minidom import urllib, re, gnomevfs, traceback import utils, config from song import sType from helper import helper from web_threading import WebFetchThread from widget.webinfo.webtemplate import get_template from widget.mozembed_wrap import MozClient LEOLYRICS_AUTH = "listen" class LyricsBox(gtk.VBox): def __init__(self,player): gtk.VBox.__init__(self,False,6) self.song = None self.embed = MozClient() self.embed.connect("open-uri",self.link_uri_cb) self.text = gtk.TextView(gtk.TextBuffer()) self.text.set_editable(False) padding = 5 self.text.set_property("pixels-above-lines",padding) self.text.set_property("pixels-below-lines",padding) self.text.set_property("right_margin",padding) self.text.set_property("left_margin",padding) self.auto_update = gtk.CheckButton("Auto-updating") self.auto_update.set_property("active",True) self.entry_artist = gtk.Entry() self.entry_title = gtk.Entry() self.entry_artist.connect("activate",self.on_search_changed) self.entry_title.connect("activate",self.on_search_changed) self.entry_artist.set_sensitive(False) self.entry_title.set_sensitive(False) model = gtk.ListStore(gobject.TYPE_STRING) self.dropdown_server = gtk.combo_box_new_text() servers = ["lyrc.com.ar","leoslyrics.com","music.search.naver.com"] for server in servers: if server == config.get("lyrics","server"): active = servers.index(server) self.server=server self.dropdown_server.append_text(server) self.dropdown_server.set_active(active) self.dropdown_server.connect("changed",self.on_change_lyrics_server) utils.set_tip(self.dropdown_server,_("Change Lyrics Server")) self.box_search = gtk.HBox(False,6) """self.box_search.pack_start(gtk.Label(_("Artist")),False,False) self.box_search.pack_start(self.entry_artist,True,True) self.box_search.pack_start(gtk.Label(_("Title")),False,False) self.box_search.pack_start(self.entry_title,True,True)""" l = gtk.Label(_("Lyrics server")) l.set_alignment(0,0.5) self.box_search.pack_start(l,False,False) self.box_search.pack_start(self.dropdown_server,False,False) self.box_search.pack_end(self.auto_update,False,False) self.pack_start(self.box_search,False,False) f = gtk.Frame() f.add(self.embed) self.pack_start(f,True,True) helper.connect("show-lyrics",self.new_media_cb) player.connect("new-song",self.new_media_cb) self.download_thread = WebFetchThread(1024,self.fail_fetch) self.is_realize = False self.current_html = None def on_change_lyrics_server(self,*arg): self.server = self.dropdown_server.get_active_text() config.set("lyrics","server",self.server) self.on_search_changed(True) def fail_fetch(self): self.render_data(get_template()%(_("Server did not respond."))) def set_text(self,text): buffer = self.text.get_buffer() buffer.set_text(text) def link_uri_cb(self,w,uri): return True def new_media_cb(self,widget,song): if config.get("source", "lyrics")!="1": return if not self.auto_update.get_property("active"): return if not song or song.get_type() not in sType.lyrics: self.songs = None self.entry_artist.set_sensitive(False) self.entry_title.set_sensitive(False) self.render_data(get_template()%(""+_("Lyrics not available for this media type")+"")) return self.song = song if config.get("setting","offline") == "true" : self.entry_artist.set_sensitive(False) self.entry_title.set_sensitive(False) HTML = get_template()%("

"+_("Offline mode")+"

") self.render_data(HTML) return self.entry_artist.set_sensitive(True) self.entry_title.set_sensitive(True) self.entry_artist.set_text(self.song.get_str("artist")) self.entry_title.set_text(self.song.get_str("title")) self.on_search_changed() def on_search_changed(self,w=None): if not self.song: return if w==None and gnomevfs.exists(self.song.lyric_uri): text = gnomevfs.read_entire_file(self.song.lyric_uri) self.render_data(text.replace("\n","
"),False,True) else: self.render_data(get_template()%(_("Fetching lyrics for")+" \""+self.entry_artist.get_text()+ " - " +self.entry_title.get_text()+"\"
"+_("From")+" \""+self.server+"\"...")) artist = utils.filter_info_song(self.entry_artist.get_text()) title = utils.filter_info_song(self.entry_title.get_text()) if config.get("lyrics","server")=="leoslyrics.com": url = "http://api.leoslyrics.com/api_search.php?auth=%s&artist=%s&songtitle=%s"%( LEOLYRICS_AUTH, urllib.quote(artist.encode('utf-8')), urllib.quote(title.encode('utf-8'))) self.download_thread.fetch_url(url,self.fetch_lyrics_leolyrics,self.song) elif config.get("lyrics","server")=="lyrc.com.ar": url = "http://lyrc.com.ar/en/tema1en.php?artist=%s&songname=%s"%( urllib.quote(artist.encode('utf-8')), urllib.quote(title.encode('utf-8'))) self.download_thread.fetch_url(url,self.fetch_lyrics_lyrccomar,self.song) elif config.get("lyrics","server")=="music.search.naver.com": url = "http://music.search.naver.com/search.naver?where=music_lyric&query=%s+%s"%( urllib.quote(artist.encode('utf-8')), urllib.quote(title.encode('utf-8'))) self.download_thread.fetch_url(url,self.fetch_lyrics_naver,self.song) def render_data(self,html,song_save=False,prepare_data=False): if prepare_data: html = html.replace("\n","") html = html.replace("\r","") if html.find("")] html = re.sub("class=\"(.[^>]*)\"","",html) html = re.sub("id=\"(.[^>]*)\"","",html) html = re.sub("style=\"(.[^>]*)\"","",html) html = re.sub(".*?","",html,re.S) html = re.sub(".*?","",html,re.S) html = re.sub(".*?","",html,re.S) html = html.replace("
","\n") html = re.sub('<(.*)>', "", html) if song_save and len(html)>0: if gnomevfs.exists(song_save.lyric_uri): gnomevfs.unlink(song_save.lyric_uri) print song_save.lyric_uri try: perm = gnomevfs.PERM_USER_ALL|gnomevfs.PERM_GROUP_ALL|gnomevfs.PERM_OTHER_ALL utils.makedirs(song_save.lyric_uri[:song_save.lyric_uri.rfind("/")],perm) except:pass try: f = gnomevfs.create(song_save.lyric_uri,gnomevfs.OPEN_WRITE) except:pass else: f.write(html) f.close() if prepare_data: html = html.replace("\n","
") #Scrappy way to detect latin-1 string title = "

"+self.song.get_str("title",True)+ " - " + self.song.get_str("artist",True)+'

' try:html = html.encode( "utf-8" ) except: for codec in ['iso-8859-1','iso-8559-15','utf-8']: try: html = html.decode(codec) except (UnicodeError, LookupError): pass else: html = title+html break else: html = title+html html = get_template()%html self.embed.set_data("file://",html) def fetch_lyrics_lyrccomar(self,html_buffer,song): self.render_data(html_buffer.read(),song,True) def fetch_lyrics_leolyrics(self,html_buffer,song): # Leolyrics API reader grab on lyrics.py from quodlibet Copyright 2005 Eduardo Gonzalez, Joe Wreschnig self.songlist = [] try: xml = minidom.parse(html_buffer) except Exception, e: print "W:LyricsBox:Failed fetch_lyrics_part1 xml (traceback):" print traceback.format_exc() gobject.idle_add(self.render_data,get_template()%(_("Server did not respond."))) return xmldoc = xml.documentElement result_code = xmldoc.getElementsByTagName('response')[0].getAttribute('code') #print "Result code: ", result_code if result_code == '0': #success # This is 0 even if there are no matches. # We don't really need the top 100 matches, so I'm limiting it to ten matches = xmldoc.getElementsByTagName('result')[:10] songs = map(lambda x: x.getElementsByTagName('name')[0].firstChild.nodeValue + " - " + x.getElementsByTagName('title')[0].firstChild.nodeValue, matches) hids = map(lambda x: x.getAttribute('hid'), matches) exacts = map(lambda x: x.getAttribute('exactMatch'), matches) #print "->>" #print hids #print exacts if len(hids) == 0: #FIXME show other matches gobject.idle_add(self.render_data,get_template()%(_("Unable to find any matches for this song."))) return for i in range(len(hids)): self.songlist.append((songs[i], hids[i], exacts[i])) xmldoc.unlink() url = "http://api.leoslyrics.com/api_lyrics.php?auth=%s&hid=%s"%( LEOLYRICS_AUTH, urllib.quote(self.songlist[0][1].encode('utf-8'))) self.download_thread.fetch_url(url,self.fetch_lyrics_leolyrics_part2,song) else: gobject.idle_add(self.render_data,get_template()%(_("Unable to find any matches for this song."))) def fetch_lyrics_leolyrics_part2(self,html_buffer,song): try: xml = minidom.parse(html_buffer) except Exception, e: print "W:LyricsBox:Failed fetch_lyrics_part1 xml (traceback):" print traceback.format_exc() self.render_data(_("Server did not respond.")) return xmldoc = xml.documentElement """ text = "

"+self.decode(xmldoc.getElementsByTagName('title')[0].firstChild.nodeValue) text += ' - ' + self.decode(xmldoc.getElementsByTagName('artist')[0].getElementsByTagName('name')[0].firstChild.nodeValue) +"

" text += "

 

"+self.decode(xmldoc.getElementsByTagName('text')[0].firstChild.nodeValue).replace("\n","

")+"

" """ text = xmldoc.getElementsByTagName('text')[0].firstChild.nodeValue self.render_data(text.replace("\n","
"),song) xmldoc.unlink() def fetch_lyrics_naver(self,html_buffer,song): try: url = re.search("window.open\('([a-z0-9:/\.?=&_]+)',",html_buffer.read()).group(1) except Exception, e: self.fail_fetch() return self.download_thread.fetch_url(url,self.fetch_lyrics_naver_part2,song) def fetch_lyrics_naver_part2(self,html_buffer,song): try: text = re.search("]*>([^<]*)<\/textarea>",html_buffer.read()).group(1) except Exception, e: self.fail_fetch() return self.render_data(text.replace("\n","
").decode("euc-kr").encode("utf-8"),song, True)