3 Scraper for http://lrcct2.ttplayer.com/
12 from urllib.request
import urlopen
18 from optparse
import OptionParser
19 from common
import utilities
21 __author__ =
"Paul Harrison and 'taxigps'"
22 __title__ =
"TTPlayer"
23 __description__ =
"Search http://lrcct2.ttplayer.com for lyrics"
26 __syncronized__ =
True
30 socket.setdefaulttimeout(10)
32 LYRIC_TITLE_STRIP=[
r"\(live[^\)]*\)",
r"\(acoustic[^\)]*\)",
33 r"\([^\)]*mix\)",
r"\([^\)]*version\)",
34 r"\([^\)]*edit\)",
r"\(feat[^\)]*\)"]
35 LYRIC_TITLE_REPLACE=[(
"/",
"-"),(
" & ",
" and ")]
36 LYRIC_ARTIST_REPLACE=[(
"/",
"-"),(
" & ",
" and ")]
40 privide ttplayer specific function, such as encoding artist and title,
41 generate a Id code for server authorizition.
42 (see http://ttplyrics.googlecode.com/svn/trunk/crack)
48 These code may be ugly coz it is translated
49 from C code which is translated from asm code
50 grabed by ollydbg from ttp_lrcs.dll.
51 (see http://ttplyrics.googlecode.com/svn/trunk/crack)
58 tmp1 = (Id & 0x0000FF00) >> 8
61 if ( (Id & 0x00FF0000) == 0 ):
62 tmp3 = 0x000000FF & ~tmp1
64 tmp3 = 0x000000FF & ((Id & 0x00FF0000) >> 16)
66 tmp3 = tmp3 | ((0x000000FF & Id) << 8)
68 tmp3 = tmp3 | (0x000000FF & tmp1)
70 if ( (Id & 0xFF000000) == 0 ) :
71 tmp3 = tmp3 | (0x000000FF & (~Id))
73 tmp3 = tmp3 | (0x000000FF & (Id >> 24))
82 tmp1 = (char + tmp2) & 0x00000000FFFFFFFF
83 tmp2 = (tmp2 << (i%2 + 4)) & 0x00000000FFFFFFFF
84 tmp2 = (tmp1 + tmp2) & 0x00000000FFFFFFFF
95 tmp7 = (char + tmp1) & 0x00000000FFFFFFFF
96 tmp1 = (tmp1 << (i%2 + 3)) & 0x00000000FFFFFFFF
97 tmp1 = (tmp1 + tmp7) & 0x00000000FFFFFFFF
105 tmp1 = (((((tmp2 ^ tmp3) & 0x00000000FFFFFFFF) + (tmp1 | Id)) & 0x00000000FFFFFFFF) * (tmp1 | tmp3)) & 0x00000000FFFFFFFF
106 tmp1 = (tmp1 * (tmp2 ^ Id)) & 0x00000000FFFFFFFF
108 if tmp1 > 0x80000000:
109 tmp1 = tmp1 - 0x100000000
116 mystr = uni.encode(
'UTF-16')[2:]
117 for i
in range(len(mystr)):
118 rtn +=
'%02x' % (mystr[i])
124 self.
LIST_URL =
'http://ttlrccnc.qianqian.com/dll/lyricsvr.dll?sh?Artist=%s&Title=%s&Flags=0'
125 self.
LYRIC_URL =
'http://ttlrccnc.qianqian.com/dll/lyricsvr.dll?dl?Id=%d&Code=%d&uid=01&mac=%012x'
128 utilities.log(debug,
"%s: searching lyrics for %s - %s - %s" % (__title__, lyrics.artist, lyrics.album, lyrics.title))
131 for exp
in LYRIC_ARTIST_REPLACE:
132 p = re.compile(exp[0])
133 artist = p.sub(exp[1], lyrics.artist)
134 for exp
in LYRIC_TITLE_REPLACE:
135 p = re.compile(exp[0])
136 title = p.sub(exp[1], lyrics.title)
139 for exp
in LYRIC_TITLE_STRIP:
141 title = p.sub(
'', title)
144 title = title.strip().replace(
'`',
'').replace(
'/',
'')
145 artist = artist.strip().replace(
'`',
'').replace(
'/',
'')
148 url = self.
LIST_URL %(ttpClient.EncodeArtTit(artist.replace(
' ',
'').lower()), ttpClient.EncodeArtTit(title.replace(
' ',
'').lower()))
150 Page = f.read().
decode(
'utf-8')
152 utilities.log(
True,
"%s: %s::%s (%d) [%s]" % (
153 __title__, self.__class__.__name__,
154 sys.exc_info()[ 2 ].tb_frame.f_code.co_name,
155 sys.exc_info()[ 2 ].tb_lineno,
160 links_query = re.compile(
'<lrc id=\"(.*?)\" artist=\"(.*?)\" title=\"(.*?)\"></lrc>')
161 urls = re.findall(links_query, Page)
164 if (difflib.SequenceMatcher(
None, artist.lower(), x[1].lower()).ratio() > 0.8)
and (difflib.SequenceMatcher(
None, title.lower(), x[2].lower()).ratio() > 0.8):
165 links.append( ( x[1] +
' - ' + x[2], x[0], x[1], x[2] ) )
172 if lyr
and lyr.startswith(b
'['):
173 enc = chardet.detect(lyr)
174 lyr = lyr.decode(enc[
'encoding'],
'ignore')
180 title,Id,artist,song = link
181 utilities.log(debug,
'%s %s %s' %(Id, artist, song))
183 url = self.
LYRIC_URL %(int(Id),ttpClient.CodeFunc(int(Id), artist + song), random.randint(0,0xFFFFFFFFFFFF))
187 utilities.log(
True,
"%s: %s::%s (%d) [%s]" % (
188 __title__, self.__class__.__name__,
189 sys.exc_info()[ 2 ].tb_frame.f_code.co_name,
190 sys.exc_info()[ 2 ].tb_lineno,
194 if Page.startswith(b
'['):
200 lyrics = utilities.Lyrics()
201 lyrics.source = __title__
202 lyrics.syncronized = __syncronized__
203 lyrics.artist =
'Dire Straits'
204 lyrics.album =
'Brothers In Arms'
205 lyrics.title =
'Money For Nothing'
208 found = fetcher.get_lyrics(lyrics)
211 utilities.log(
True,
"Everything appears in order.")
215 utilities.log(
True,
"The lyrics for the test search failed!")
219 from lxml
import etree
220 xml = etree.XML(
u'<lyrics></lyrics>')
221 etree.SubElement(xml,
"artist").text = lyrics.artist
222 etree.SubElement(xml,
"album").text = lyrics.album
223 etree.SubElement(xml,
"title").text = lyrics.title
224 etree.SubElement(xml,
"syncronized").text =
'True' if __syncronized__
else 'False'
225 etree.SubElement(xml,
"grabber").text = lyrics.source
227 lines = lyrics.lyrics.splitlines()
229 etree.SubElement(xml,
"lyric").text = line
231 utilities.log(
True, utilities.convert_etree(etree.tostring(xml, encoding=
'UTF-8',
232 pretty_print=
True, xml_declaration=
True)))
236 from lxml
import etree
237 version = etree.XML(
u'<grabber></grabber>')
238 etree.SubElement(version,
"name").text = __title__
239 etree.SubElement(version,
"author").text = __author__
240 etree.SubElement(version,
"command").text =
'ttplayer.py'
241 etree.SubElement(version,
"type").text =
'lyrics'
242 etree.SubElement(version,
"description").text = __description__
243 etree.SubElement(version,
"version").text = __version__
244 etree.SubElement(version,
"priority").text = __priority__
245 etree.SubElement(version,
"syncronized").text =
'True' if __syncronized__
else 'False'
247 utilities.log(
True, utilities.convert_etree(etree.tostring(version, encoding=
'UTF-8',
248 pretty_print=
True, xml_declaration=
True)))
254 parser = OptionParser()
256 parser.add_option(
'-v',
"--version", action=
"store_true", default=
False,
257 dest=
"version", help=
"Display version and author")
258 parser.add_option(
'-t',
"--test", action=
"store_true", default=
False,
259 dest=
"test", help=
"Test grabber with a know good search")
260 parser.add_option(
'-s',
"--search", action=
"store_true", default=
False,
261 dest=
"search", help=
"Search for lyrics.")
262 parser.add_option(
'-a',
"--artist", metavar=
"ARTIST", default=
None,
263 dest=
"artist", help=
"Artist of track.")
264 parser.add_option(
'-b',
"--album", metavar=
"ALBUM", default=
None,
265 dest=
"album", help=
"Album of track.")
266 parser.add_option(
'-n',
"--title", metavar=
"TITLE", default=
None,
267 dest=
"title", help=
"Title of track.")
268 parser.add_option(
'-f',
"--filename", metavar=
"FILENAME", default=
None,
269 dest=
"filename", help=
"Filename of track.")
270 parser.add_option(
'-d',
'--debug', action=
"store_true", default=
False,
271 dest=
"debug", help=(
"Show debug messages"))
273 opts, args = parser.parse_args()
275 lyrics = utilities.Lyrics()
276 lyrics.source = __title__
277 lyrics.syncronized = __syncronized__
289 lyrics.artist = opts.artist
291 lyrics.album = opts.album
293 lyrics.title = opts.title
295 lyrics.filename = opts.filename
298 if fetcher.get_lyrics(lyrics):
302 utilities.log(
True,
"No lyrics found for this track")
305 if __name__ ==
'__main__':