4 # Copyright (C) 2009 by Silviu Grijincu <silviu.grijincu@gmail.com>.
5 # Published under the terms of the GNU General Public License (GPL).
8 # lyrics.py fetches lyrics from http://lyricwiki.org/.
9 # The script is triggered by a key that is not already
10 # in use by shell-fm and must be set. (See bellow)
13 # Save lyrics.py in the ~/.shell-fm/scripts/ directory.
14 # (if the directories do not exist please create them)
15 # To enable the plugin you must have a configuration file.
16 # 1.Create a file named shell-fm.rc in the ~/.shell-fm/ directory.
17 # 2.Put the following line in shell-fm.rc file :
18 # key0x?? = /usr/bin/python ~/.shell-fm/scripts/lyrics.py %a %t
19 # 4.Replace ?? with the ASCII hex code of the triggering key you wold like to use.
20 # for example, to use ` (backquote) as a trigger replace ?? with 60 as bellow:
21 # key0x60 = /usr/bin/python ~/.shell-fm/scripts/lyrics.py %a %t
32 def __init__(self
, artist
, title
):
38 return (False, "this is a dummy lyric source, no lyric can be found")
40 class DummyLyricSource(LyricSource
):
41 def __init__(self
, artist
, title
):
42 LyricSource
.__init
__(self
, artist
, title
)
44 return (False, "dummy error message from DummyLyricSource")
46 class LyricWiki(LyricSource
):
47 def __init__(self
, artist
, title
):
48 LyricSource
.__init
__(self
, artist
, title
)
49 self
.URL
= 'http://lyricwiki.org/'
51 def canonical(self
, str):
52 # capitalize every word after an ' ' and
53 # replace ' ' with '_'
54 return "_".join(map((lambda x
: x
.capitalize()), str.split(' ')))
57 return self
.URL
+ self
.canonical(self
.artist
) + ':' + self
.canonical(self
.title
)
59 def get_html(self
, url
):
61 html
= urlopen(url
).read()
64 errmsg
= 'The server couldn\'t fulfill the request for ' + url
65 errmsg
+= 'Error code: ' + str(e
.code
)
66 return (False, errmsg
)
68 errmsg
= 'We failed to reach the server ' + url
69 errmsg
+= 'Reason: ' + str(e
.reason
)
70 return (False, errmsg
)
72 return (False, "unexpected path reached in LyricWiki.get_html")
74 def filter_html_markers(self
, html
):
75 rules
= ( ('<br />', '\n '),
81 html
= html
.replace(x
, y
)
84 def parse_lyrics(self
, html
, url
):
85 instrumental
= html
.find('This song is an instrumental.')
86 if instrumental
<> -1:
87 return (True, 'This song is instrumental.')
89 start_marker
= '<div class=\'lyricbox\' >'
90 found
= html
.find(start_marker
)
92 return (False, 'Lyrics not found at ' + url
+ '.')
94 start
= found
+ len(start_marker
)
95 end
= html
.find('\n', start
)
96 lyrics
= self
.filter_html_markers(html
[start
:end
])
101 (success
, msg
) = self
.get_html(url
)
105 return self
.parse_lyrics(html
, url
)
112 # TODO: after adding a new LyricSouce class, append
113 # an object of that class here
114 lyric_sources
= (LyricWiki(artist
, title
), DummyLyricSource(artist
, title
))
117 lyrics
= map( (lambda x
: x
.get_lyrics()), lyric_sources
)
119 # print the first lyrics found
120 for (success
, lyric
) in lyrics
:
126 # if no lyrics found, print all error messages
127 for (success
, errmsg
) in lyrics
:
130 print 'Lyrics not found.'
132 if __name__
== "__main__":