The branch, eden has been updated
via 66d7c6e3d22e287ebb2476fe8cc02307b44f1833 (commit)
from 1d33aef430dc2145ce65779411961e4e555062be (commit)
- Log -----------------------------------------------------------------
http://xbmc.git.sourceforge.net/git/gitweb.cgi?p=xbmc/scripts;a=commit;h=66d7c6e3d22e287ebb2476fe8cc02307b44f1833
commit 66d7c6e3d22e287ebb2476fe8cc02307b44f1833
Author: ronie <[email protected]>
Date: Tue Oct 2 00:35:07 2012 +0200
[script.cu.lyrics] -v2.1.0
fix scrapers
diff --git a/script.cu.lyrics/addon.xml b/script.cu.lyrics/addon.xml
index 329fef5..9b0bbdf 100644
--- a/script.cu.lyrics/addon.xml
+++ b/script.cu.lyrics/addon.xml
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<addon id="script.cu.lyrics"
name="CU Lyrics"
- version="2.0.6"
- provider-name="Amet">
+ version="2.1.0"
+ provider-name="Nuka1195,amet,ronie">
<requires>
<import addon="xbmc.python" version="2.0"/>
</requires>
diff --git a/script.cu.lyrics/changelog.txt b/script.cu.lyrics/changelog.txt
index 9864c14..8c6c394 100644
--- a/script.cu.lyrics/changelog.txt
+++ b/script.cu.lyrics/changelog.txt
@@ -1,3 +1,12 @@
+2.1.0
+- fixed: smooth scrolling setting didn't work
+- fixed lyrictime scraper: replace spaces with dashes
+- fixed: don't fetch lyrics we already prefetched
+- fixed: check for next track
+- fixed: check next song data
+- lyricwiki: don't try to fetch lyrics for the next song if there isn't one
+- lyricwiki: don't crash on key errors
+
2.0.6
- Try all enabled scrapers until lyrics are found, thx to Yann Rouillard
- Try to correctly decode the artist/title for a radio stream, thx to Yann
Rouillard
diff --git a/script.cu.lyrics/default.py b/script.cu.lyrics/default.py
index f00fc6c..b35d24e 100644
--- a/script.cu.lyrics/default.py
+++ b/script.cu.lyrics/default.py
@@ -1,23 +1,20 @@
-# main import's
import sys
import os
import xbmc
import xbmcaddon
-# Script constants
-__scriptname__ = "CU Lyrics"
-__author__ = "Amet, ZorMonkey"
-__scriptid__ = "script.cu.lyrics"
-__credits__ = "EnderW,Nuka1195"
-__settings__ = xbmcaddon.Addon()
-__language__ = __settings__.getLocalizedString
-__version__ = __settings__.getAddonInfo('version')
-__cwd__ = __settings__.getAddonInfo('path')
-__profile__ = xbmc.translatePath( __settings__.getAddonInfo('profile') )
-# Shared resources
-BASE_RESOURCE_PATH = xbmc.translatePath( os.path.join( __cwd__, 'resources',
'lib' ) )
+__addon__ = xbmcaddon.Addon()
+__author__ = __addon__.getAddonInfo('author')
+__scriptid__ = __addon__.getAddonInfo('id')
+__scriptname__ = __addon__.getAddonInfo('name')
+__cwd__ = __addon__.getAddonInfo('path')
+__version__ = __addon__.getAddonInfo('version')
+__language__ = __addon__.getLocalizedString
-sys.path.append (BASE_RESOURCE_PATH)
+__profile__ = xbmc.translatePath( __addon__.getAddonInfo('profile') )
+__resource__ = xbmc.translatePath( os.path.join( __cwd__, 'resources', 'lib'
) )
+
+sys.path.append (__resource__)
if ( __name__ == "__main__" ):
import gui
diff --git a/script.cu.lyrics/resources/language/German/strings.xml
b/script.cu.lyrics/resources/language/German/strings.xml
old mode 100755
new mode 100644
diff --git a/script.cu.lyrics/resources/lib/gui.py
b/script.cu.lyrics/resources/lib/gui.py
old mode 100755
new mode 100644
index a4fc80d..fbef34e
--- a/script.cu.lyrics/resources/lib/gui.py
+++ b/script.cu.lyrics/resources/lib/gui.py
@@ -1,23 +1,14 @@
-
+#-*- coding: UTF-8 -*-
import sys
import os
import xbmc
import xbmcgui
-import unicodedata
-import urllib
import traceback
-import inspect
-from song import *
-from lyrics import *
from utilities import *
-__scriptname__ = sys.modules[ "__main__" ].__scriptname__
-__version__ = sys.modules[ "__main__" ].__version__
-__settings__ = sys.modules[ "__main__" ].__settings__
+__addon__ = sys.modules[ "__main__" ].__addon__
__language__ = sys.modules[ "__main__" ].__language__
-__cwd__ = sys.modules[ "__main__" ].__cwd__
-LYRIC_SCRAPER_DIR = os.path.join(__cwd__, "resources", "lib", "scrapers")
class GUI( xbmcgui.WindowXMLDialog ):
def __init__( self, *args, **kwargs ):
@@ -30,7 +21,7 @@ class GUI( xbmcgui.WindowXMLDialog ):
def onInit( self ):
self.setup_all()
-
+
def setup_all( self ):
self.setup_variables()
self.get_scraper_list()
@@ -38,7 +29,7 @@ class GUI( xbmcgui.WindowXMLDialog ):
def get_scraper_list( self ):
for scraper in os.listdir(LYRIC_SCRAPER_DIR):
- if os.path.isdir(os.path.join(LYRIC_SCRAPER_DIR, scraper)) and
__settings__.getSetting( scraper ) == "true":
+ if os.path.isdir(os.path.join(LYRIC_SCRAPER_DIR, scraper)) and
__addon__.getSetting( scraper ) == "true":
exec ( "from scrapers.%s import lyricsScraper as
lyricsScraper_%s" % (scraper, scraper))
exec (
"self.scrapers.append(lyricsScraper_%s.LyricsFetcher())" % scraper)
@@ -64,25 +55,28 @@ class GUI( xbmcgui.WindowXMLDialog ):
def get_lyrics(self, song, next_song = False):
try:
lyrics, error = self.get_lyrics_from_memory( song )
-
+
if (lyrics is None ):
lyrics, error = self.get_lyrics_from_file( song, next_song )
-
+
if ( lyrics is None ):
for scraper in self.scrapers:
- lyrics, error = scraper.get_lyrics_thread( song )
+ lyrics, error, service = scraper.get_lyrics_thread( song )
if lyrics is not None:
+ log('%s: found lyrics' % service)
break
-
+ else:
+ log('%s: no results found' % service)
+
if ( lyrics is not None ):
try:
- self.save_lyrics_to_file(lyrics)
+ self.save_lyrics(lyrics)
except:
pass
-
+
return lyrics, error
except:
- print traceback.format_exc(sys.exc_info()[2])
+ log( traceback.format_exc(sys.exc_info()[2]) )
return None, __language__(30001)
def get_lyrics_from_list( self, item ):
@@ -99,13 +93,13 @@ class GUI( xbmcgui.WindowXMLDialog ):
lyrics = Lyrics()
lyrics.song = song
xbmc.sleep( 60 )
- if ( not next_song ) and ( xbmc.getInfoLabel( "MusicPlayer.Lyrics" )
and (__settings__.getSetting( "show_embeded_lyrics" ) == 'true')):
+ if ( not next_song ) and ( xbmc.getInfoLabel( "MusicPlayer.Lyrics" )
and (__addon__.getSetting( "show_embeded_lyrics" ) == 'true')):
lyrics.lyrics = unicode( xbmc.getInfoLabel( "MusicPlayer.Lyrics"
), "utf-8" )
- if (__settings__.getSetting( "save_embeded_lyrics" ) == 'true'):
+ if (__addon__.getSetting( "save_embeded_lyrics" ) == 'true'):
try:
self.save_lyrics_to_file(lyrics)
except:
- pass
+ pass
return lyrics, None
try:
lyrics_file = open( song.path(), "r" )
@@ -128,7 +122,7 @@ class GUI( xbmcgui.WindowXMLDialog ):
self.fetchedLyrics = self.fetchedLyrics[:10]
def save_lyrics_to_file( self, lyrics ):
- if ( __settings__.getSetting( "save_lyrics" ) == 'true' ):
+ if ( __addon__.getSetting( "save_lyrics" ) == 'true' ):
try:
if ( not os.path.isdir( os.path.dirname( lyrics.song.path() )
) ):
os.makedirs( os.path.dirname( lyrics.song.path() ) )
@@ -138,9 +132,9 @@ class GUI( xbmcgui.WindowXMLDialog ):
return True
except IOError:
return False
-
+
def focus_lyrics(self):
- if ( __settings__.getSetting( "smooth_scrolling" ) ):
+ if ( __addon__.getSetting( "smooth_scrolling" ) ) == 'true':
self.show_control( 110 )
else:
self.show_control( 100 )
@@ -151,7 +145,7 @@ class GUI( xbmcgui.WindowXMLDialog ):
self.show_control( 100 )
except:
pass
-
+
def show_lyrics( self, lyrics):
try:
self.reset_controls()
@@ -167,45 +161,27 @@ class GUI( xbmcgui.WindowXMLDialog ):
splitLyrics = lyricsText.splitlines()
for x in splitLyrics:
self.getControl( 110 ).addItem( x )
-
+
self.getControl( 110 ).selectItem( 0 )
-
+
self.focus_lyrics()
-
+
self.getControl( 200 ).setEnabled( False )
self.getControl( 200 ).setLabel( lyrics.source )
-
+
finally:
pass
- def show_prefetch_message(self, song):
+ def show_prefetch_message(self):
self.reset_controls()
self.getControl( 100 ).setText( __language__(30000) )
self.show_control( 100 )
-
- def show_choices( self, choices ):
- for song in choices:
- self.getControl( 120 ).addItem( song[ 0 ] )
- self.getControl( 120 ).selectItem( 0 )
- self.menu_items = choices
- self.show_control( 120 )
-
+
def reset_controls( self ):
self.getControl( 100 ).reset()
self.getControl( 110 ).reset()
self.getControl( 120 ).reset()
self.getControl( 200 ).setLabel( "" )
-
-
- def get_exception( self ):
- """ user modified exceptions """
- if ( self.scraper_exceptions ):
- artist = self.LyricsScraper._format_param( self.artist, False )
- alt_artist = get_keyboard( artist, "%s: %s" % ( _( 100 ), unicode(
self.artist, "utf-8", "ignore" ), ) )
- if ( alt_artist != artist ):
- exception = ( artist, alt_artist, )
- self.LyricsScraper._set_exceptions( exception )
- self.myPlayerChanged( 2, True )
def exit_script( self, restart=False ):
self.close()
@@ -216,82 +192,65 @@ class GUI( xbmcgui.WindowXMLDialog ):
def onFocus( self, controlId ):
self.controlId = controlId
-
+
def onAction( self, action ):
if ( action.getId() in CANCEL_DIALOG):
- self.close()
-
+ self.exit_script()
+
def getMyPlayer( self ):
self.MyPlayer = MyPlayer( xbmc.PLAYER_CORE_PAPLAYER,
function=self.myPlayerChanged )
self.myPlayerChanged( 2 )
def myPlayerChanged( self, event, force_update=False ):
try:
- LOG( LOG_DEBUG, "%s (rev: %s) GUI::myPlayerChanged [%s]",
__scriptname__, [ "stopped","ended","started" ][ event ] )
+ log("myPlayerChanged [%s]" % [ "stopped","ended","started" ][
event ] )
if ( event < 2 ):
self.exit_script()
else:
- # The logic described below still has holes in it.
- # Mostly, xbmc.Player().getPlayingFile() does NOT
- # always change before we get here. Until I get something
- # better coded, I'm leaving this.
- #
- # If we're here, we know that the song may have changed
- # from what is stored in self.current_song.
- # It is also possible that the current song has NOT changed.
- # Use xbmc.Player().getPlayingFile() to determine
- # if we need to do anything
- self.show_prefetch_message(self.current_song)
+ self.show_prefetch_message()
xbmc.sleep( 750 )
playing_song = xbmc.Player().getMusicInfoTag().getTitle()
if ( self.song_info != playing_song ):
self.song_info = playing_song
-
- # Unfortunately, calls to xbmc.getInfoLabel may return
- # information about the previous song for a while after
- # the song has changed. Loop until it returns something
new.
- # We know that this won't loop forever since we know that
the
- # current file has changed (the previous "if")
song = Song.current()
- print "Current: %s" % (self.current_song)
- print "song: %s" % (song)
i = 0
- while ( song is not None
- and self.current_song is not None
+ while ( song is not None
+ and self.current_song is not None
and self.current_song == song
and i < 50 ):
i += 1
xbmc.sleep( 50 )
song = Song.current()
-
+
if ( song and ( self.current_song != song or force_update
) ):
self.current_song = song
- self.show_prefetch_message(song)
lyrics, error = self.get_lyrics( song )
if ( lyrics is not None ):
self.show_lyrics(lyrics)
else:
self.show_error(error)
-
- next_song = Song.next()
- if ( next_song ):
- self.get_lyrics( next_song, True )
- else:
- print "Missing Artist or Song name in ID3 tag for next
track"
-
+
+ if xbmc.getCondVisibility('MusicPlayer.HasNext'):
+ next_song = Song.next()
+ if next_song:
+ self.get_lyrics( next_song, True )
+ else:
+ log( "Missing Artist or Song name in ID3 tag for
next track" )
+
else:
- lyrics, error = self.get_lyrics(self.current_song)
- if ( lyrics is not None ):
- self.show_lyrics(lyrics)
- else:
- self.show_error(error)
-
- next_song = Song.next()
- if ( next_song ):
- self.get_lyrics( next_song, True )
- else:
- print "Missing Artist or Song name in ID3 tag for next
track"
-
+ lyrics, error = self.get_lyrics(self.current_song)
+ if ( lyrics is not None ):
+ self.show_lyrics(lyrics)
+ else:
+ self.show_error(error)
+
+ if xbmc.getCondVisibility('MusicPlayer.HasNext'):
+ next_song = Song.next()
+ if next_song:
+ self.get_lyrics( next_song, True )
+ else:
+ log( "Missing Artist or Song name in ID3 tag for
next track" )
+
except:
pass
@@ -307,19 +266,15 @@ class MyPlayer( xbmc.Player ):
xbmc.sleep( 300 )
if ( not xbmc.Player().isPlayingAudio() ):
self.function( 0 )
-
+
def onPlayBackEnded( self ):
xbmc.sleep( 300 )
if ( not xbmc.Player().isPlayingAudio() ):
- self.function( 1 )
-
+ self.function( 1 )
+
def onPlayBackStarted( self ):
try:
self.function( 2 )
except:
- print "%s::%s (%d) [%s]" % ( self.__class__.__name__,
sys.exc_info()[ 2 ].tb_frame.f_code.co_name, sys.exc_info()[ 2 ].tb_lineno,
sys.exc_info()[ 1 ])
- print traceback.format_exc(sys.exc_info()[2])
-
-
-
-
+ log( "%s::%s (%d) [%s]" % ( self.__class__.__name__,
sys.exc_info()[ 2 ].tb_frame.f_code.co_name, sys.exc_info()[ 2 ].tb_lineno,
sys.exc_info()[ 1 ]))
+ log( traceback.format_exc(sys.exc_info()[2]))
diff --git
a/script.cu.lyrics/resources/lib/scrapers/lyricsmode/lyricsScraper.py
b/script.cu.lyrics/resources/lib/scrapers/lyricsmode/lyricsScraper.py
index 90d5b97..dc179d9 100644
--- a/script.cu.lyrics/resources/lib/scrapers/lyricsmode/lyricsScraper.py
+++ b/script.cu.lyrics/resources/lib/scrapers/lyricsmode/lyricsScraper.py
@@ -1,138 +1,12 @@
-
+#-*- coding: UTF-8 -*-
import sys
-import os
import urllib
import re
-import xbmc
from utilities import *
-from song import *
-import lyrics
-import re
-
__language__ = sys.modules[ "__main__" ].__language__
__title__ = __language__(30006)
-__allow_exceptions__ = True
-
-
-class WikiaFormat:
- @staticmethod
- def __condense_strings(parseList):
- while(True):
- if ( len(parseList) < 2
- or not isinstance(parseList[-1], basestring)
- or not isinstance(parseList[-2], basestring) ):
- return parseList
- lastStr = parseList[-1]
- parseList.pop()
- for i in range(len(parseList)-1, -1, -1):
- if ( isinstance(parseList[i], basestring) ):
- lastStr = parseList[i] + lastStr
- parseList.pop()
- else:
- parseList.append(lastStr)
- return parseList
- parseList.append(lastStr)
-
- @staticmethod
- def __parse_stack(parseList):
- while(True):
- if ( len(parseList) < 3
- or isinstance(parseList[-1], basestring)
- or not isinstance(parseList[-2], basestring)
- or isinstance(parseList[-3], basestring) ):
- return parseList
-
- beginTags = {2:'[I]', 3:'[B]', 5:'[I][B]'}
- endTags = {2:'[/I]', 3:'[/B]', 5:'[/I][/B]'}
-
- begin = parseList[-3]
- str = parseList[-2]
- end = parseList[-1]
- if ( begin == end ):
- parseList = parseList[:-3]
- if ( str ):
- parseList.append(beginTags[begin] + str + endTags[end])
- elif ( begin == 5 ):
- parseList = parseList[:-3]
- begin = 5-end
- parseList.append(begin)
- if ( str ):
- parseList.append(beginTags[end] + str + endTags[end])
- elif ( end == 5 ):
- parseList = parseList[:-3]
- end = 5-begin
- if ( str ):
- parseList.append(beginTags[begin] + str + endTags[begin])
- parseList.append(end)
- else:
- return parseList
-
- @staticmethod
- def __push_stack(q, str, stack):
- if ( q >= 5 ):
- stack.append(5)
- q -= 5
- elif ( q >= 3 ):
- stack.append(3)
- q -= 3
- elif ( q >= 2 ):
- stack.append(2)
- q -= 2
- stack = WikiaFormat.__parse_stack(stack)
- str = "'"*q + str
- q = 0
- if ( str ):
- stack.append(str)
- WikiaFormat.__condense_strings(stack)
- return stack
-
- @staticmethod
- def to_xbmc_format(s):
- t = s.split("'")
- numQuotes = 0
- stack = []
- for line in t:
- if (line):
- stack = WikiaFormat.__push_stack(numQuotes, line, stack)
- numQuotes = 1
- else:
- numQuotes += 1
- if ( numQuotes > 1 ):
- stack = WikiaFormat.__push_stack(numQuotes, "", stack)
-
- #Take care of any unclosed tags
- if ( not isinstance(stack[-1], basestring) ):
- stack.append("")
- stack = WikiaFormat.__push_stack(5, "", stack)
- if ( not isinstance(stack[-1], basestring) ):
- stack.pop()
- return str.join("", stack)
-
-class XmlUtils :
- def getText (self, nodeParent, childName ):
- # Get child node...
- node = nodeParent.getElementsByTagName( childName )[0]
-
- if node == None :
- return None
-
- # Get child text...
- text = ""
- for child in node.childNodes:
- if child.nodeType == child.TEXT_NODE :
- text = text + child.data
- return text
-
- @staticmethod
- def removeComments(text):
- begin = text.split("<!--")
- if ( len(begin) > 1 ):
- end = str.join("", begin[1:]).split("-->")
- if ( len(end) > 1 ):
- return XmlUtils.removeComments(begin[0] + str.join("",
end[1:]))
- return text
-
+__service__ = 'lyricsmode'
class LyricsFetcher:
def __init__( self ):
@@ -140,54 +14,53 @@ class LyricsFetcher:
self.normalize_lyrics_regex = re.compile( "&#[x]*(?P<name>[0-9]+);*" )
self.clean_br_regex = re.compile( "<br[ /]*>[\s]*", re.IGNORECASE )
self.search_results_regex = re.compile("<a
href=\"[^\"]+\">([^<]+)</a></td>[^<]+<td><a href=\"([^\"]+)\"
class=\"b\">[^<]+</a></td>", re.IGNORECASE)
- self.next_results_regex = re.compile("<A href=\"([^\"]+)\"
class=\"pages\">next .</A>", re.IGNORECASE)
-
- def get_lyrics_start(self, *args):
- lyricThread = threading.Thread(target=self.get_lyrics_thread,
args=args)
- lyricThread.setDaemon(True)
- lyricThread.start()
-
+ self.next_results_regex = re.compile("<A href=\"([^\"]+)\"
class=\"pages\">next .</A>", re.IGNORECASE)
+
def get_lyrics_thread(self, song):
- print "SCRAPER-DEBUG-lyricsmode: LyricsFetcher.get_lyrics_thread %s" %
(song)
- l = lyrics.Lyrics()
+ log( "%s: searching lyrics for %s" % (__service__, song))
+ l = Lyrics()
l.song = song
try: # below is borowed from XBMC Lyrics
- url = "http://www.lyricsmode.com/lyrics/%s/%s/%s.html" %
(song.artist.lower()[:1],song.artist.lower().replace(" ","_"),
song.title.lower().replace(" ","_"), )
+ url = "http://www.lyricsmode.com/lyrics/%s/%s/%s.html" % (
+ song.artist.lower()[:1],
+ song.artist.lower().replace(" ","_"),
+ song.title.lower().replace(" ","_"),
+ )
lyrics_found = False
while True:
- print "Search url: %s" % (url)
+ log( "%s: search url: %s" % (__service__, url))
song_search = urllib.urlopen(url).read()
if song_search.find("<div id='songlyrics_h' class='dn'>") >= 0:
break
-
+
if lyrics_found:
# if we're here, we found the lyrics page but it didn't
# contains the lyrics part (licensing issue or some bug)
return None, "No lyrics found"
-
+
# Let's try to use the research box if we didn't yet
if not 'search' in url:
url = "http://www.lyricsmode.com/search.php?what=songs&s="
+ urllib.quote_plus(song.title.lower())
else:
- # the search gave more than on result, let's try to find
our song
+ # the search gave more than on result, let's try to find
our song
url = ""
start = song_search.find('<!--output-->')
end = song_search.find('<!--/output-->', start)
results = self.search_results_regex.findall(song_search,
start, end)
-
+
for result in results:
if result[0].lower() in song.artist.lower():
url = "http://www.lyricsmode.com" + result[1]
lyrics_found = True
break
-
+
if not url:
# Is there a next page of results ?
match =
self.next_results_regex.search(song_search[end:])
if match:
url = "http://www.lyricsmode.com/search.php" +
match.group(1)
else:
- return None, "No lyrics found"
+ return None, "No lyrics found", __service__
lyr = song_search.split("<div id='songlyrics_h'
class='dn'>")[1].split('<!-- /SONG LYRICS -->')[0]
lyr = self.clean_br_regex.sub( "\n", lyr ).strip()
@@ -198,11 +71,15 @@ class LyricsFetcher:
line.strip()
if line.find("Lyrics from:") < 0:
lir.append(line)
- lyr = u"\n".join( lir )
+ lyr = u"\n".join( lir )
l.lyrics = lyr
l.source = __title__
- return l, None
+ return l, None, __service__
except:
- print "%s::%s (%d) [%s]" % ( self.__class__.__name__,
sys.exc_info()[ 2 ].tb_frame.f_code.co_name, sys.exc_info()[ 2 ].tb_lineno,
sys.exc_info()[ 1 ])
- return None, __language__(30004) % (__title__)
-
+ log( "%s: %s::%s (%d) [%s]" % (
+ __service__, self.__class__.__name__,
+ sys.exc_info()[ 2 ].tb_frame.f_code.co_name,
+ sys.exc_info()[ 2 ].tb_lineno,
+ sys.exc_info()[ 1 ]
+ ))
+ return None, __language__(30004) % (__title__), __service__
diff --git
a/script.cu.lyrics/resources/lib/scrapers/lyricstime/lyricsScraper.py
b/script.cu.lyrics/resources/lib/scrapers/lyricstime/lyricsScraper.py
index 7f05837..8593ca0 100644
--- a/script.cu.lyrics/resources/lib/scrapers/lyricstime/lyricsScraper.py
+++ b/script.cu.lyrics/resources/lib/scrapers/lyricstime/lyricsScraper.py
@@ -1,135 +1,12 @@
#-*- coding: UTF-8 -*-
import sys
-import os
import urllib
import re
-import xbmc
from utilities import *
-from song import *
-import lyrics
__language__ = sys.modules[ "__main__" ].__language__
__title__ = __language__(30007)
-__allow_exceptions__ = True
-
-class WikiaFormat:
- @staticmethod
- def __condense_strings(parseList):
- while(True):
- if ( len(parseList) < 2
- or not isinstance(parseList[-1], basestring)
- or not isinstance(parseList[-2], basestring) ):
- return parseList
- lastStr = parseList[-1]
- parseList.pop()
- for i in range(len(parseList)-1, -1, -1):
- if ( isinstance(parseList[i], basestring) ):
- lastStr = parseList[i] + lastStr
- parseList.pop()
- else:
- parseList.append(lastStr)
- return parseList
- parseList.append(lastStr)
-
- @staticmethod
- def __parse_stack(parseList):
- while(True):
- if ( len(parseList) < 3
- or isinstance(parseList[-1], basestring)
- or not isinstance(parseList[-2], basestring)
- or isinstance(parseList[-3], basestring) ):
- return parseList
-
- beginTags = {2:'[I]', 3:'[B]', 5:'[I][B]'}
- endTags = {2:'[/I]', 3:'[/B]', 5:'[/I][/B]'}
-
- begin = parseList[-3]
- str = parseList[-2]
- end = parseList[-1]
- if ( begin == end ):
- parseList = parseList[:-3]
- if ( str ):
- parseList.append(beginTags[begin] + str + endTags[end])
- elif ( begin == 5 ):
- parseList = parseList[:-3]
- begin = 5-end
- parseList.append(begin)
- if ( str ):
- parseList.append(beginTags[end] + str + endTags[end])
- elif ( end == 5 ):
- parseList = parseList[:-3]
- end = 5-begin
- if ( str ):
- parseList.append(beginTags[begin] + str + endTags[begin])
- parseList.append(end)
- else:
- return parseList
-
- @staticmethod
- def __push_stack(q, str, stack):
- if ( q >= 5 ):
- stack.append(5)
- q -= 5
- elif ( q >= 3 ):
- stack.append(3)
- q -= 3
- elif ( q >= 2 ):
- stack.append(2)
- q -= 2
- stack = WikiaFormat.__parse_stack(stack)
- str = "'"*q + str
- q = 0
- if ( str ):
- stack.append(str)
- WikiaFormat.__condense_strings(stack)
- return stack
-
- @staticmethod
- def to_xbmc_format(s):
- t = s.split("'")
- numQuotes = 0
- stack = []
- for line in t:
- if (line):
- stack = WikiaFormat.__push_stack(numQuotes, line, stack)
- numQuotes = 1
- else:
- numQuotes += 1
- if ( numQuotes > 1 ):
- stack = WikiaFormat.__push_stack(numQuotes, "", stack)
-
- #Take care of any unclosed tags
- if ( not isinstance(stack[-1], basestring) ):
- stack.append("")
- stack = WikiaFormat.__push_stack(5, "", stack)
- if ( not isinstance(stack[-1], basestring) ):
- stack.pop()
- return str.join("", stack)
-
-class XmlUtils :
- def getText (self, nodeParent, childName ):
- # Get child node...
- node = nodeParent.getElementsByTagName( childName )[0]
-
- if node == None :
- return None
-
- # Get child text...
- text = ""
- for child in node.childNodes:
- if child.nodeType == child.TEXT_NODE :
- text = text + child.data
- return text
-
- @staticmethod
- def removeComments(text):
- begin = text.split("<!--")
- if ( len(begin) > 1 ):
- end = str.join("", begin[1:]).split("-->")
- if ( len(end) > 1 ):
- return XmlUtils.removeComments(begin[0] + str.join("",
end[1:]))
- return text
-
+__service__ = 'lyricstime'
class LyricsFetcher:
def __init__( self ):
@@ -137,30 +14,32 @@ class LyricsFetcher:
self.normalize_lyrics_regex = re.compile( "&#[x]*(?P<name>[0-9]+);*" )
self.clean_br_regex = re.compile( "<br[ /]*>[\s]*", re.IGNORECASE )
self.clean_info_regex = re.compile( "\[[a-z]+?:.*\]\s" )
-
- def get_lyrics_start(self, *args):
- lyricThread = threading.Thread(target=self.get_lyrics_thread,
args=args)
- lyricThread.setDaemon(True)
- lyricThread.start()
-
-
+
def get_lyrics_thread(self, song):
- print "SCRAPER-DEBUG-lyricstime: LyricsFetcher.get_lyrics_thread %s" %
(song)
- l = lyrics.Lyrics()
+ log( "%s: searching lyrics for %s" % (__service__, song))
+ l = Lyrics()
l.song = song
try: # ***** parser - changing this changes search string
- url = "http://www.lyricstime.com/%s-%s-lyrics.html" %
(song.artist.lower().replace("
","-").replace(",","-").replace("'","-").replace("&","-").replace("and","-"),
song.title.lower().replace("
","-").replace(",","-").replace("'","-").replace("&","-"), )
- song_search =
urllib.urlopen(url.replace("---","-").replace("--","-")).read()
- print "Search url: %s" % (url)
- lyr = song_search.split('<div id="songlyrics"
>')[1].split('</div>')[0]
+ url = "http://www.lyricstime.com/%s-%s-lyrics.html" % (
+ replace(song.artist.lower().replace("
","-").replace("---","-").replace("--","-")),
+ replace(song.title.lower().replace("
","-").replace("---","-").replace("--","-"))
+ )
+ song_search = urllib.urlopen(url).read()
+ log( "%s: search url: %s" % (__service__, url))
+ lyr = song_search.split('<div id="songlyrics"
>')[1].split('</div>')[0]
lyr = self.clean_br_regex.sub( "\n", lyr ).strip()
lyr = self.clean_lyrics_regex.sub( "", lyr ).strip()
- lyr = self.normalize_lyrics_regex.sub( lambda m: unichr( int(
m.group( 1 ) ) ), lyr.decode("ISO-8859-1") )
+ lyr = self.normalize_lyrics_regex.sub(
+ lambda m: unichr( int( m.group( 1 ) ) ),
lyr.decode("ISO-8859-1") )
lyr = u"\n".join( [ lyric.strip() for lyric in lyr.splitlines() ] )
- lyr = self.clean_info_regex.sub( "", lyr )
+ lyr = self.clean_info_regex.sub( "", lyr )
l.lyrics = lyr
l.source = __title__
- return l, None
+ return l, None, __service__
except:
- print "%s::%s (%d) [%s]" % ( self.__class__.__name__,
sys.exc_info()[ 2 ].tb_frame.f_code.co_name, sys.exc_info()[ 2 ].tb_lineno,
sys.exc_info()[ 1 ])
- return None, __language__(30004) % (__title__)
\ No newline at end of file
+ log( "%s: %s::%s (%d) [%s]" % ( __service__,
self.__class__.__name__,
+ sys.exc_info()[ 2
].tb_frame.f_code.co_name,
+ sys.exc_info()[ 2 ].tb_lineno,
+ sys.exc_info()[ 1 ]
+ ))
+ return None, __language__(30004) % (__title__), __service__
diff --git a/script.cu.lyrics/resources/lib/scrapers/lyricwiki/lyricsScraper.py
b/script.cu.lyrics/resources/lib/scrapers/lyricwiki/lyricsScraper.py
index 20b709c..47188a2 100644
--- a/script.cu.lyrics/resources/lib/scrapers/lyricwiki/lyricsScraper.py
+++ b/script.cu.lyrics/resources/lib/scrapers/lyricwiki/lyricsScraper.py
@@ -1,14 +1,15 @@
+#-*- coding: UTF-8 -*-
import sys, re, urllib2, socket, HTMLParser
import xbmc, xbmcaddon
if sys.version_info < (2, 7):
import simplejson
else:
import json as simplejson
-import lyrics
+from utilities import *
__language__ = sys.modules[ "__main__" ].__language__
__title__ = __language__(30008)
-__allow_exceptions__ = True
+__service__ = 'lyricwiki'
socket.setdefaulttimeout(10)
@@ -16,21 +17,21 @@ class LyricsFetcher:
def __init__( self ):
self.url =
'http://lyrics.wikia.com/api.php?artist=%s&song=%s&fmt=realjson'
- def get_lyrics_start(self, *args):
- lyricThread = threading.Thread(target=self.get_lyrics_thread,
args=args)
- lyricThread.setDaemon(True)
- lyricThread.start()
-
def get_lyrics_thread(self, song):
- xbmc.log(msg='SCRAPER-DEBUG-Lyricwiki: LyricsFetcher.get_lyrics_thread
%s' % (song), level=xbmc.LOGDEBUG)
- l = lyrics.Lyrics()
+ log( "%s: searching lyrics for %s" % (__service__, song))
+ log( "%s: search api url: %s" % (__service__, self.url))
+ l = Lyrics()
l.song = song
req = urllib2.urlopen(self.url % (urllib2.quote(song.artist),
urllib2.quote(song.title)))
response = req.read()
req.close()
data = simplejson.loads(response)
- self.page = data['url']
+ try:
+ self.page = data['url']
+ except:
+ return None, __language__(30002) % (song.title, song.artist),
__service__
if not self.page.endswith('action=edit'):
+ log( "%s: search url: %s" % (__service__, self.page))
req = urllib2.urlopen(self.page)
response = req.read()
req.close()
@@ -40,8 +41,8 @@ class LyricsFetcher:
htmlparser = HTMLParser.HTMLParser()
l.lyrics = htmlparser.unescape(lyricscode).replace('<br />',
'\n')
l.source = __title__
- return l, None
+ return l, None, __service__
except:
- return None, __language__(30004) % __title__
+ return None, __language__(30004) % __title__, __service__
else:
- return None, __language__(30002) % (song.title, song.artist)
+ return None, __language__(30002) % (song.title, song.artist),
__service__
diff --git a/script.cu.lyrics/resources/lib/utilities.py
b/script.cu.lyrics/resources/lib/utilities.py
index 361be85..5454c44 100644
--- a/script.cu.lyrics/resources/lib/utilities.py
+++ b/script.cu.lyrics/resources/lib/utilities.py
@@ -1,54 +1,93 @@
-
-import sys
+#-*- coding: UTF-8 -*-
import os
+import sys
import xbmc
-import xbmcgui
import unicodedata
-DEBUG_MODE = 0
-
-_ = sys.modules[ "__main__" ].__language__
__scriptname__ = sys.modules[ "__main__" ].__scriptname__
-__version__ = sys.modules[ "__main__" ].__version__
+__profile__ = sys.modules[ "__main__" ].__profile__
__cwd__ = sys.modules[ "__main__" ].__cwd__
+LYRIC_SCRAPER_DIR = os.path.join(__cwd__, "resources", "lib", "scrapers")
+CANCEL_DIALOG = ( 9, 10, 92, 216, 247, 257, 275, 61467, 61448, )
-BASE_RESOURCE_PATH = sys.modules[ "__main__" ].BASE_RESOURCE_PATH
-# special button codes
-SELECT_ITEM = ( 11, 256, 61453, )
-EXIT_SCRIPT = ( 247, 275, 61467, )
-CANCEL_DIALOG = ( 9, 10, 92, 216, 247, 257, 275, 61467, 61448, )
-GET_EXCEPTION = ( 216, 260, 61448, )
-SETTINGS_MENU = ( 229, 259, 261, 61533, )
-SHOW_CREDITS = ( 195, 274, 61507, )
-MOVEMENT_UP = ( 166, 270, 61478, )
-MOVEMENT_DOWN = ( 167, 271, 61480, )
-
-# special action codes
-ACTION_SELECT_ITEM = ( 7, )
-ACTION_EXIT_SCRIPT = ( 10, )
-ACTION_CANCEL_DIALOG = ACTION_EXIT_SCRIPT + ( 9, )
-ACTION_GET_EXCEPTION = ( 0, 11 )
-ACTION_SETTINGS_MENU = ( 117, )
-ACTION_SHOW_CREDITS = ( 122, )
-ACTION_MOVEMENT_UP = ( 3, )
-ACTION_MOVEMENT_DOWN = ( 4, )
-
-# Log status codes
-LOG_INFO, LOG_ERROR, LOG_NOTICE, LOG_DEBUG = range( 1, 5 )
-
-def LOG( status, format, *args ):
- if ( DEBUG_MODE >= status ):
- xbmc.log( "%s: %s\n" % ( ( "INFO", "ERROR", "NOTICE", "DEBUG", )[
status - 1 ], format % args, ) )
-
-def unescape(s):
- s = s.replace("<", "<")
- s = s.replace(""", '"')
- s = s.replace("'", "'")
- s = s.replace(">", ">")
- s = s.replace("&", "&")
- return s
+def log(msg):
+ xbmc.log("### [%s] - %s" % (__scriptname__,msg,),level=xbmc.LOGDEBUG )
def deAccent(str):
return unicodedata.normalize('NFKD', unicode(unicode(str,
'utf-8'))).encode('ascii','ignore')
+def replace(string):
+ replace_char = [" ",",","'","&","and"]
+ for char in replace_char:
+ string.replace(char,"-")
+ return string
+
+class Lyrics:
+ def __init__( self ):
+ self.song = Song()
+ self.lyrics = ""
+ self.source = ""
+
+class Song:
+ def __init__( self ):
+ self.artist = ""
+ self.title = ""
+
+ def __str__(self):
+ return "Artist: %s, Title: %s" % ( self.artist, self.title)
+
+ def __cmp__(self, song):
+ if (self.artist != song.artist):
+ return cmp(self.artist, song.artist)
+ else:
+ return cmp(self.title, song.title)
+
+ def sanitize(self, str):
+ return str.replace( "\\", "_" ).replace( "/", "_"
).replace(":","_").replace("?","_").replace("!","_")
+
+ def path(self):
+ return unicode( os.path.join( __profile__, "lyrics",
self.sanitize(self.artist), self.sanitize(self.title) + ".txt" ), "utf-8" )
+
+ @staticmethod
+ def current():
+ song = Song.by_offset(0)
+
+ if not song.artist and not xbmc.getInfoLabel(
"MusicPlayer.TimeRemaining"):
+ # no artist and infinite playing time ? We probably listen to a
radio
+ # which usually set the song title as "Artist - Title" (via ICY
StreamTitle)
+ sep = song.title.find("-")
+ if sep > 1:
+ song.artist = song.title[:sep - 1].strip()
+ song.title = song.title[sep + 1:].strip()
+ # The title in the radio often contains some additional
+ # bracketed information at the end:
+ # Radio version, short version, year of the song...
+ # It often disturbs the lyrics search so we remove it
+ song.title = re.sub(r'\([^\)]*\)$', '', song.title)
+
+ log( "Current Song: %s:%s" % (song.artist, song.title))
+ return song
+
+ @staticmethod
+ def next():
+ song = Song.by_offset(1)
+ log( "Next Song: %s:%s" % (song.artist, song.title))
+ if song.artist != '' and song.title != '':
+ return song
+ else:
+ return None
+
+ @staticmethod
+ def by_offset(offset = 0):
+ song = Song()
+ if offset > 0:
+ offset_str = ".offset(%i)" % offset
+ else:
+ offset_str = ""
+ song.title = xbmc.getInfoLabel( "MusicPlayer%s.Title" % offset_str)
+ song.title = deAccent(song.title)
+ song.artist = xbmc.getInfoLabel( "MusicPlayer%s.Artist" % offset_str)
+ song.artist = deAccent(song.artist)
+
+ return song
diff --git a/script.cu.lyrics/resources/settings.xml
b/script.cu.lyrics/resources/settings.xml
index 12cbab5..220b3e7 100644
--- a/script.cu.lyrics/resources/settings.xml
+++ b/script.cu.lyrics/resources/settings.xml
@@ -9,6 +9,6 @@
<category label="30109">
<setting id="lyricsmode" type="bool" label="Lyrics Mode" default="true"/>
<setting id="lyricstime" type="bool" label="lyrics.time" default="true"/>
- <setting id="lyricwiki" type="bool" label="Lyrics Wiki" default="true"/>
+ <setting id="lyricwiki" type="bool" label="LyricWiki" default="true"/>
</category>
</settings>
diff --git a/script.cu.lyrics/resources/skins/Default/skin.xml
b/script.cu.lyrics/resources/skins/Default/skin.xml
old mode 100755
new mode 100644
-----------------------------------------------------------------------
Summary of changes:
script.cu.lyrics/addon.xml | 4 +-
script.cu.lyrics/changelog.txt | 9 +
script.cu.lyrics/default.py | 25 ++--
script.cu.lyrics/resources/lib/gui.py | 167 +++++++------------
script.cu.lyrics/resources/lib/lyrics.py | 8 -
.../lib/scrapers/lyricsmode/lyricsScraper.py | 177 +++-----------------
.../lib/scrapers/lyricstime/lyricsScraper.py | 163 +++----------------
.../lib/scrapers/lyricwiki/lyricsScraper.py | 27 ++--
script.cu.lyrics/resources/lib/song.py | 69 --------
script.cu.lyrics/resources/lib/utilities.py | 123 +++++++++-----
script.cu.lyrics/resources/settings.xml | 2 +-
11 files changed, 227 insertions(+), 547 deletions(-)
mode change 100755 => 100644
script.cu.lyrics/resources/language/German/strings.xml
mode change 100755 => 100644 script.cu.lyrics/resources/lib/gui.py
delete mode 100644 script.cu.lyrics/resources/lib/lyrics.py
delete mode 100644 script.cu.lyrics/resources/lib/song.py
mode change 100755 => 100644 script.cu.lyrics/resources/skins/Default/skin.xml
hooks/post-receive
--
Scripts
------------------------------------------------------------------------------
Got visibility?
Most devs has no idea what their production app looks like.
Find out how fast your code is with AppDynamics Lite.
http://ad.doubleclick.net/clk;262219671;13503038;y?
http://info.appdynamics.com/FreeJavaPerformanceDownload.html
_______________________________________________
Xbmc-addons mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/xbmc-addons