edfab774f282ab21c4b3f258ee9d35930756148e
[clinton/xbmc-groove.git] / resources / lib / GroovesharkAPI.py
1 import socket, hmac, urllib, urllib2, pprint, md5, re, sha, time, random, os, pickle, uuid, tempfile, pprint
2
3 SESSION_EXPIRY = 518400 # 6 days in seconds
4
5 # GrooveAPI constants
6 THUMB_URL = 'http://beta.grooveshark.com/static/amazonart/m'
7 SONG_LIMIT = 25
8 ALBUM_LIMIT = 15
9 ARTIST_LIMIT = 15
10 SONG_SUFFIX = '.mp3'
11
12 # GrooveSong constants
13 DOMAIN = "grooveshark.com"
14 HOME_URL = "http://listen." + DOMAIN
15 API_URL = "http://cowbell." + DOMAIN + "/more.php"
16 SERVICE_URL = "http://cowbell." + DOMAIN + "/service.php"
17 TOKEN_URL = "http://cowbell." + DOMAIN + "/more.php"
18
19 CLIENT_NAME = "gslite"
20 CLIENT_VERSION = "20101012.37"
21 HEADERS = {"Content-Type": "application/json",
22 "User-Agent": "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12 (.NET CLR 3.5.30729)",
23 "Referer": "http://listen.grooveshark.com/main.swf?cowbell=fe87233106a6cef919a1294fb2c3c05f"}
24
25 RE_SESSION = re.compile('"sessionID":"\s*?([A-z0-9]+)"')
26 RANDOM_CHARS = "1234567890abcdef"
27
28 # Get a song
29 class GrooveSong:
30
31 def __init__(self):
32
33 import simplejson
34 self.simplejson = simplejson
35
36 self.cacheDir = os.path.join(tempfile.gettempdir(), 'groovesong')
37 self._lastSessionTime = 0
38 self.uuid = self._getUUID()
39
40 self._getSavedSession()
41 # session ids last 1 week
42 if self.sessionID == '' or time.time() - self._lastSessionTime >= SESSION_EXPIRY:
43 self.sessionID = self._getSession(HOME_URL)
44 if self.sessionID == '':
45 raise StandardError('Failed to get session id')
46 else:
47 print "New GrooveSong session id: " + self.sessionID
48 self._setSavedSession()
49
50 # The actual call to the API
51 def _callRemote(self, method, params, type="default"):
52 postData = {
53 "header": {
54 "client": CLIENT_NAME,
55 "clientRevision": CLIENT_VERSION,
56 "uuid": self.uuid,
57 "session": self.sessionID},
58 "country": {"IPR":"1021", "ID":"223", "CC1":"0", "CC2":"0", "CC3":"0", "CC4":"2147483648"},
59 "privacy": 1,
60 "parameters": params,
61 "method": method}
62
63 token = self._getMethodToken(method)
64 if token == None:
65 raise StandardError("Cannot get token")
66
67 postData["header"]["token"] = token
68 if type == "service":
69 url = SERVICE_URL + "?" + method
70 else:
71 url = API_URL + "?" + method
72
73 postData = self.simplejson.dumps(postData)
74 print "GrooveSong URL: " + url
75 request = urllib2.Request(url, postData, HEADERS)
76
77 response = urllib2.urlopen(request).read()
78 try:
79 response = self.simplejson.loads(response)
80 print "GrooveSong Response..."
81 pprint.pprint(response)
82 except:
83 raise StandardError("API error: " + response)
84 try:
85 response["fault"]
86 except KeyError:
87 return response
88 else:
89 raise StandardError("API error: " + response["fault"]["message"])
90
91 # Generate a random uuid
92 def _getUUID(self):
93 return str(uuid.uuid4())
94
95 # Make a token ready for a request header
96 def _getMethodToken(self, method):
97 self._token = self._getCommunicationToken()
98 if self._token == None:
99 return None
100
101 randomChars = ""
102 while 6 > len(randomChars):
103 randomChars = randomChars + random.choice(RANDOM_CHARS)
104
105 token = sha.new(method + ":" + self._token + ":quitStealinMahShit:" + randomChars).hexdigest()
106
107 return randomChars + token
108
109 # Generate a communication token
110 def _getCommunicationToken(self):
111 params = {"secretKey": self._getSecretKey(self.sessionID)}
112 postData = {
113 "header": {
114 "client": CLIENT_NAME,
115 "clientRevision": CLIENT_VERSION,
116 "uuid": self.uuid,
117 "session": self.sessionID},
118 "country": {"IPR":"1021", "ID":"223", "CC1":"0", "CC2":"0", "CC3":"0", "CC4":"2147483648"},
119 "privacy": 1,
120 "parameters": params,
121 "method": "getCommunicationToken"}
122
123 postData = self.simplejson.dumps(postData)
124 request = urllib2.Request(TOKEN_URL, postData, HEADERS)
125 response = urllib2.urlopen(request).read()
126 try:
127 response = self.simplejson.loads(response)
128 except:
129 raise StandardError("API error: " + response)
130 try:
131 response["fault"]
132 except KeyError:
133 return response["result"]
134 else:
135 return None
136
137 # Generate a secret key from a sessionID
138 def _getSecretKey(self, sessionID):
139 return md5.new(sessionID).hexdigest()
140
141 # Get a session id from some HTML
142 def _getSession(self, html):
143 html = urllib2.urlopen(HOME_URL).read()
144 session = RE_SESSION.search(html)
145 if session:
146 self._lastSessionTime = time.time()
147 return session.group(1)
148 else:
149 return None
150
151 def _getSavedSession(self):
152 path = os.path.join(self.cacheDir, 'session.dmp')
153 try:
154 f = open(path, 'rb')
155 session = pickle.load(f)
156 self.sessionID = session['sessionID']
157 self._lastSessionTime = session['lastSessionTime']
158 f.close()
159 except:
160 self.sessionID = ''
161 self._lastSessionTime = 0
162 pass
163
164 def _setSavedSession(self):
165 try:
166 # Create the 'data' directory if it doesn't exist.
167 if not os.path.exists(self.cacheDir):
168 os.makedirs(self.cacheDir)
169 path = os.path.join(self.cacheDir, 'session.dmp')
170 f = open(path, 'wb')
171 session = {'sessionID' : self.sessionID, 'lastSessionTime' : self._lastSessionTime}
172 pickle.dump(session, f, protocol=pickle.HIGHEST_PROTOCOL)
173 f.close()
174 except:
175 print "An error occurred during save session"
176 pass
177
178 # Gets a stream key and host to get song content
179 def _getStreamDetails(self, songID):
180 params = {
181 "songID": songID,
182 "prefetch": False,
183 "mobile": False,
184 "country": {"IPR":"1021","ID":"223", "CC1":"0", "CC2":"0", "CC3":"0", "CC4":"2147483648"}
185 }
186 response = self._callRemote("getStreamKeyFromSongIDEx", params)
187 try:
188 self._lastStreamKey = response["result"]["streamKey"]
189 self._lastStreamServer = response["result"]["ip"]
190 self._lastStreamServerID = response["result"]["streamServerID"]
191 return True
192 except:
193 return False
194
195 # Tells Grooveshark you have downloaded a song
196 def _markSongDownloaded(self, songID):
197 params = {
198 "streamKey": self._lastStreamKey,
199 "streamServerID": self._lastStreamServerID,
200 "songID": songID}
201 self._callRemote("markSongDownloaded", params)
202
203 # Get the song URL
204 def getSongURL(self, songID):
205 if self._getStreamDetails(songID) == True:
206 postData = {"streamKey": self._lastStreamKey}
207 postData = urllib.urlencode(postData)
208 return "http://" + self._lastStreamServer + "/stream.php?" + str(postData)
209 else:
210 return ''
211
212 class GrooveAPIv1:
213
214 def __init__(self, sessionID = 0):
215 import simplejson
216 self.simplejson = simplejson
217 timeout = 40
218 socket.setdefaulttimeout(timeout)
219 self.loggedIn = 0
220 self.userId = 0
221 self.sessionID = sessionID
222
223 def callRemote(self, method, params={}):
224 data = {'header': {'sessionID': self.sessionID}, 'method': method, 'parameters': params}
225 data = self.simplejson.dumps(data)
226 req = urllib2.Request("http://api.grooveshark.com/ws/1.0/?json")
227 req.add_header('Host', 'api.grooveshark.com')
228 req.add_header('Content-type', 'text/json')
229 req.add_header('Content-length', str(len(data)))
230 req.add_data(data)
231 response = urllib2.urlopen(req)
232 result = response.read()
233 response.close()
234 try:
235 result = self.simplejson.loads(result)
236 if 'fault' in result:
237 if result['fault']['code'] == 8: #Session ID has expired. Get a new and try again if possible.
238 print 'GrooveShark: SessionID expired'
239 return []
240 return result
241 except:
242 return []
243
244 def login(self, username, password):
245 if self.loggedIn == 1:
246 return self.userId
247 token = md5.new(username.lower() + md5.new(password).hexdigest()).hexdigest()
248 result = self.callRemote("session.loginExt", {"username": username, "token": token})
249 if 'result' in result:
250 if 'userID' in result['result']:
251 self.loggedIn = 1
252 self.userId = result['result']['userID']
253 return result['result']['userID']
254 else:
255 return 0
256
257 def unfavorite(self, songID):
258 return self.callRemote("song.unfavorite", {"songID": songID})
259
260 def playlistCreate(self, name, about):
261 if self.loggedIn == 1:
262 result = self.callRemote("playlist.create", {"name": name, "about": about})
263 if 'result' in result:
264 return result['result']['playlistID']
265 else:
266 return 0
267 else:
268 return 0
269
270 def playlistCreateUnique(self, name, songIds):
271 if self.loggedIn == 1:
272 result = self.callRemote("playlist.createunique", {"name": name, "songIDs": songIds})
273 if 'result' in result:
274 return result['result']['playlistID']
275 else:
276 return 0
277 else:
278 return 0
279
280 def playlistGetSongs(self, playlistId):
281 items = self.callRemote("playlist.getSongs", {"playlistID": playlistId})
282 print items
283 if 'result' in items:
284 i = 0
285 list = []
286 index = ''
287 l = -1
288 try:
289 if 'songs' in items['result'][0]:
290 l = len(items['result'][0]['songs'])
291 index = 'songs[]'
292 except: pass
293 try:
294 if l < 0 and 'songs' in items['result']:
295 l = len(items['result']['songs'])
296 index = 'songs'
297 except: pass
298 try:
299 if l < 0 and 'song' in items['result']:
300 l = 1
301 index = 'song'
302 except: pass
303 try:
304 if l < 0:
305 l = len(items['result'])
306 except: pass
307
308 while(i < l):
309 if index == 'songs[]':
310 s = items['result'][0]['songs'][i]
311 elif index == 'songs':
312 s = items['result'][index][i]
313 elif index == 'song':
314 s = items['result'][index]
315 else:
316 s = items['result'][i]
317 if 'CoverArtFilename' not in s:
318 info = self.getSongInfo(s['SongID'])
319 coverart = info['CoverArtFilename']
320 elif s['CoverArtFilename'] != None:
321 coverart = THUMB_URL+s['CoverArtFilename'].encode('ascii', 'ignore')
322 else:
323 coverart = 'None'
324 list.append([s['SongName'].encode('ascii', 'ignore'),\
325 s['SongID'],\
326 s['AlbumName'].encode('ascii', 'ignore'),\
327 s['AlbumID'],\
328 s['ArtistName'].encode('ascii', 'ignore'),\
329 s['ArtistID'],\
330 coverart])
331 i = i + 1
332 return list
333 else:
334 return []
335
336
337 return list
338
339 def playlistDelete(self, playlistId):
340 if self.loggedIn == 1:
341 result = self.callRemote("playlist.delete", {"playlistID": playlistId})
342 if 'fault' in result:
343 return 0
344 else:
345 return 1
346 else:
347 return 0
348
349 def playlistRename(self, playlistId, name):
350 if self.loggedIn == 1:
351 result = self.callRemote("playlist.rename", {"playlistID": playlistId, "name": name})
352 if 'fault' in result:
353 return 0
354 else:
355 return 1
356 else:
357 return 0
358
359 def playlistClearSongs(self, playlistId):
360 if self.loggedIn == 1:
361 return self.callRemote("playlist.clearSongs", {"playlistID": playlistId})
362
363 def playlistAddSong(self, playlistId, songId, position):
364 if self.loggedIn == 1:
365 result = self.callRemote("playlist.addSong", {"playlistID": playlistId, "songID": songId, "position": position})
366 if 'fault' in result:
367 return 0
368 else:
369 return 1
370 else:
371 return 0
372
373 def playlistDeleteSong(self, playlistId, position):
374 if self.loggedIn == 1:
375 result = self.callRemote("playlist.removeSong", {"playlistID": playlistId, "position": position})
376 if 'fault' in result:
377 return 0
378 else:
379 return 1
380 else:
381 return 0
382
383 def playlistReplace(self, playlistId, songIds):
384 if self.loggedIn == 1:
385 result = self.callRemote("playlist.replace", {"playlistID": playlistId, "songIDs": songIds})
386 if 'fault' in result:
387 return 0
388 else:
389 return 1
390 else:
391 return 0
392
393 def artistGetSimilar(self, artistId, limit):
394 items = self.callRemote("artist.getSimilar", {"artistID": artistId, "limit": limit})
395 if 'result' in items:
396 i = 0
397 list = []
398 artists = items['result']['artists']
399 while(i < len(artists)):
400 s = artists[i]
401 list.append([s['artistName'].encode('ascii', 'ignore'),\
402 s['artistID']])
403 i = i + 1
404 return list
405 else:
406 return []
407
408 # Main API
409 class GrooveAPI:
410
411 sessionID = ''
412 userID = 0
413 host = 'api.grooveshark.com'
414 lastSessionTime = 0
415
416 # Constructor
417 def __init__(self):
418
419 import simplejson
420 self.simplejson = simplejson
421 socket.setdefaulttimeout(40)
422
423 self.cacheDir = os.path.join(tempfile.gettempdir(), 'grooveapi')
424 if os.path.isdir(self.cacheDir) == False:
425 os.makedirs(self.cacheDir)
426 print "Made " + self.cacheDir
427
428 self._getSavedSession()
429 # session ids last 1 week
430 if self.sessionID == '' or time.time()- self.lastSessionTime >= SESSION_EXPIRY:
431 self.sessionID = self._getSessionID()
432 if self.sessionID == '':
433 raise StandardError('Failed to get session id')
434 else:
435 print "New GrooveAPI session id: " + self.sessionID
436 self._setSavedSession()
437
438 # Sort keys
439 def _keySort(self, d):
440 return [(k,d[k]) for k in sorted(d.keys())]
441
442 # Make a message sig
443 def _createMessageSig(self, method, params, secret):
444 args = self._keySort(params);
445 data = '';
446 for arg in args:
447 data += str(arg[0])
448 data += str(arg[1])
449 data = method + data
450
451 h = hmac.new(secret, data)
452 return h.hexdigest()
453
454 # The actual call to the API
455 def _callRemote(self, method, params = {}):
456 url = 'http://%s/ws/2.1/?method=%s&%s&wsKey=wordpress&sig=%s&format=json' % (self.host, method, urllib.urlencode(params), self._createMessageSig(method, params, 'd6c59291620c6eaa5bf94da08fae0ecc'))
457 print url
458 req = urllib2.Request(url)
459 response = urllib2.urlopen(req)
460 result = response.read()
461 print "Response..."
462 pprint.pprint(result)
463 response.close()
464 try:
465 result = self.simplejson.loads(result)
466 return result
467 except:
468 return []
469
470 # Get a session id
471 def _getSessionID(self):
472 params = {}
473 result = self._callRemote('startSession', params)
474 self.lastSessionTime = time.time()
475 return result['result']['sessionID']
476
477 def _getSavedSession(self):
478 path = os.path.join(self.cacheDir, 'session.dmp')
479 try:
480 f = open(path, 'rb')
481 session = pickle.load(f)
482 self.sessionID = session['sessionID']
483 self.lastSessionTime = session['lastSessionTime']
484 self.userID = session['userID']
485 f.close()
486 except:
487 self.sessionID = ''
488 self.lastSessionTime = 0
489 self.userID = 0
490 pass
491
492 def _setSavedSession(self):
493 try:
494 # Create the directory if it doesn't exist.
495 if not os.path.exists(self.cacheDir):
496 os.makedirs(self.cacheDir)
497 path = os.path.join(self.cacheDir, 'session.dmp')
498 f = open(path, 'wb')
499 session = { 'sessionID' : self.sessionID, 'lastSessionTime' : self.lastSessionTime, 'userID': self.userID}
500 pickle.dump(session, f, protocol=pickle.HIGHEST_PROTOCOL)
501 f.close()
502 except:
503 print "An error occurred during save session"
504 pass
505
506 # Make user authentication token
507 def _getUserToken(self, username, password):
508 return md5.new(username.lower() + md5.new(password).hexdigest()).hexdigest()
509
510 # Authenticates the user for current API session
511 def _authenticateUser(self, username, token):
512 params = {'sessionID': self.sessionID, 'username': username, 'token': token}
513 result = self._callRemote('authenticateUser', params)
514 return result['result']['UserID']
515
516 # Login
517 def login(self, username, password):
518 if self.userID <= 0:
519 # Check cache
520 self._getSavedSession()
521 if self.userID <= 0:
522 token = self._getUserToken(username, password)
523 self.userID = self._authenticateUser(username, token)
524 if self.userID > 0:
525 self._setSavedSession()
526 return self.userID
527
528 # Logs the user out
529 def logout(self):
530 result = self._callRemote('logout', {'sessionID' : self.sessionID})
531 if 'result' in result and result['result']['success'] == True:
532 self.userID = 0
533 self._setSavedSession()
534 return True
535 return False
536
537 # Search for albums
538 def getArtistSearchResults(self, query, limit=ARTIST_LIMIT):
539 result = self._callRemote('getArtistSearchResults', {'query' : query,'limit' : limit})
540 if 'result' in result:
541 return self._parseArtists(result)
542 else:
543 return []
544
545 # Search for albums
546 def getAlbumSearchResults(self, query, limit=ALBUM_LIMIT):
547 result = self._callRemote('getAlbumSearchResults', {'query' : query,'limit' : limit})
548 if 'result' in result:
549 return self._parseAlbums(result)
550 else:
551 return []
552
553 # Search for songs
554 def getSongSearchResults(self, query, limit=SONG_LIMIT):
555 result = self._callRemote('getSongSearchResultsEx', {'query' : query, 'limit' : limit})
556 if 'result' in result:
557 return self._parseSongs(result)
558 else:
559 return []
560
561 # Get artists albums
562 def getArtistAlbums(self, artistID, limit=ALBUM_LIMIT):
563 result = self._callRemote('getArtistAlbums', {'artistID' : artistID})
564 if 'result' in result:
565 return self._parseAlbums(result, limit)
566 else:
567 return []
568
569 # Get album songs
570 def getAlbumSongs(self, albumID, limit=SONG_LIMIT):
571 result = self._callRemote('getAlbumSongsEx', {'albumID' : albumID, 'limit' : limit})
572 if 'result' in result:
573 return self._parseSongs(result)
574 else:
575 return []
576
577 # Get artist's popular songs
578 def getArtistPopularSongs(self, artistID, limit = SONG_LIMIT):
579 result = self._callRemote('getArtistPopularSongs', {'artistID' : artistID})
580 if 'result' in result:
581 return self._parseSongs(result, limit)
582 else:
583 return []
584
585 # Gets the popular songs
586 def getPopularSongsToday(self, limit=SONG_LIMIT):
587 result = self._callRemote('getPopularSongsToday', {'limit' : limit})
588 if 'result' in result:
589 # Note limit is broken in the Grooveshark getPopularSongsToday method
590 return self._parseSongs(result, limit)
591 else:
592 return []
593
594 # Gets the favorite songs of the logged-in user
595 def getUserFavoriteSongs(self):
596 if (self.userID == 0):
597 return [];
598 result = self._callRemote('getUserFavoriteSongs', {'sessionID' : self.sessionID})
599 if 'result' in result:
600 return self._parseSongs(result)
601 else:
602 return []
603
604 # Add song to user favorites
605 def addUserFavoriteSong(self, songID):
606 if (self.userID == 0):
607 return False;
608 result = self._callRemote('addUserFavoriteSong', {'sessionID' : self.sessionID, 'songID' : songID})
609 return result['result']['success']
610
611 # Get the url to link to a song on Grooveshark
612 def getSongURLFromSongID(self, songID):
613 song = GrooveSong()
614 url = song.getSongURL(songID)
615 print "Got song URL " + url
616 return url
617
618 # Get the url to link to a song on Grooveshark
619 def getSongInfo(self, songID):
620 result = self._callRemote('getSongInfoEx', {'songID' : songID})
621 if 'result' in result and 'SongID' in result['result']:
622 info = result['result']
623 if 'CoverArtFilename' in info and info['CoverArtFilename'] != None:
624 info['CoverArtFilename'] = THUMB_URL+info['CoverArtFilename'].encode('ascii', 'ignore')
625 else:
626 info['CoverArtFilename'] = 'None'
627 return info
628 else:
629 return 'None'
630
631 # Gets the playlists of the logged-in user
632 def getUserPlaylists(self):
633 if (self.userID == 0):
634 return [];
635 result = self._callRemote('getUserPlaylists', {'sessionID' : self.sessionID})
636 if 'result' in result:
637 return self._parsePlaylists(result)
638 else:
639 return []
640
641 # Get userid from name
642 def _getUserIDFromUsername(self, username):
643 result = self._callRemote('getUserIDFromUsername', {'username' : username})
644 if 'result' in result and result['result']['UserID'] > 0:
645 return result['result']['UserID']
646 else:
647 return 0
648
649 # Gets the playlists of the logged-in user
650 def getUserPlaylistsEx(self, username):
651 userID = self._getUserIDFromUsername(username)
652 if (userID > 0):
653 result = self._callRemote('getUserPlaylistsEx', {'userID' : userID})
654 if 'result' in result and result['result']['playlists'] != None:
655 playlists = result['result']['playlists']
656 return self._parsePlaylists(playlists)
657 else:
658 return []
659
660 # Creates a playlist with songs
661 def createPlaylist(self, name, songIDs):
662 result = self._callRemote('createPlaylist', {'name' : name, 'songIDs' : songIDs, 'sessionID' : self.sessionID})
663 if 'result' in result and result['result']['success'] == True:
664 return result['result']['playlistID']
665 elif 'errors' in result:
666 return 0
667
668 # Sets the songs for a playlist
669 def setPlaylistSongs(self, playlistID, songIDs):
670 result = self._callRemote('setPlaylistSongs', {'playlistID' : playlistID, 'songIDs' : songIDs, 'sessionID' : self.sessionID})
671 if 'result' in result and result['result']['success'] == True:
672 return True
673 else:
674 return False
675
676 # Gets the songs of a playlist
677 def getPlaylistSongs(self, playlistID):
678 result = self._callRemote('getPlaylistSongs', {'playlistID' : playlistID});
679 if 'result' in result:
680 return self._parseSongs(result)
681 else:
682 return []
683
684 # Check the service
685 def pingService(self,):
686 result = self._callRemote('pingService', {});
687 if 'result' in result and result['result'] != '':
688 return True
689 else:
690 return False
691
692 # Extract song data
693 def _parseSongs(self, items, limit=0):
694 if 'result' in items:
695 i = 0
696 list = []
697 index = ''
698 l = -1
699 try:
700 if 'songs' in items['result'][0]:
701 l = len(items['result'][0]['songs'])
702 index = 'songs[]'
703 except: pass
704 try:
705 if l < 0 and 'songs' in items['result']:
706 l = len(items['result']['songs'])
707 index = 'songs'
708 except: pass
709 try:
710 if l < 0 and 'song' in items['result']:
711 l = 1
712 index = 'song'
713 except: pass
714 try:
715 if l < 0:
716 l = len(items['result'])
717 except: pass
718
719 if limit > 0 and l > limit:
720 l = limit
721 while(i < l):
722 if index == 'songs[]':
723 s = items['result'][0]['songs'][i]
724 elif index == 'songs':
725 s = items['result'][index][i]
726 elif index == 'song':
727 s = items['result'][index]
728 else:
729 s = items['result'][i]
730 if 'CoverArtFilename' not in s:
731 info = self.getSongInfo(s['SongID'])
732 coverart = info['CoverArtFilename']
733 elif s['CoverArtFilename'] != None:
734 coverart = THUMB_URL+s['CoverArtFilename'].encode('ascii', 'ignore')
735 else:
736 coverart = 'None'
737 list.append([s['SongName'].encode('ascii', 'ignore'),\
738 s['SongID'],\
739 s['AlbumName'].encode('ascii', 'ignore'),\
740 s['AlbumID'],\
741 s['ArtistName'].encode('ascii', 'ignore'),\
742 s['ArtistID'],\
743 coverart])
744 i = i + 1
745 return list
746 else:
747 return []
748
749 # Extract artist data
750 def _parseArtists(self, items):
751 if 'result' in items:
752 i = 0
753 list = []
754 artists = items['result']['artists']
755 while(i < len(artists)):
756 s = artists[i]
757 list.append([s['ArtistName'].encode('ascii', 'ignore'),\
758 s['ArtistID']])
759 i = i + 1
760 return list
761 else:
762 return []
763
764 # Extract album data
765 def _parseAlbums(self, items, limit=0):
766 if 'result' in items:
767 i = 0
768 list = []
769 try:
770 albums = items['result']['albums']
771 except:
772 res = items['result'][0]
773 albums = res['albums']
774 l = len(albums)
775 if limit > 0 and l > limit:
776 l = limit
777 while(i < l):
778 s = albums[i]
779 if 'CoverArtFilename' in s and s['CoverArtFilename'] != None:
780 coverart = THUMB_URL+s['CoverArtFilename'].encode('ascii', 'ignore')
781 else:
782 coverart = 'None'
783 list.append([s['ArtistName'].encode('ascii', 'ignore'),\
784 s['ArtistID'],\
785 s['AlbumName'].encode('ascii', 'ignore'),\
786 s['AlbumID'],\
787 coverart])
788 i = i + 1
789 return list
790 else:
791 return []
792
793 def _parsePlaylists(self, items):
794 i = 0
795 list = []
796 if 'result' in items:
797 playlists = items['result']
798 elif len(items) > 0:
799 playlists = items
800 else:
801 return []
802
803 while (i < len(playlists)):
804 s = playlists[i]
805 list.append([s['Name'].encode('ascii', 'ignore'), s['PlaylistID']])
806 i = i + 1
807 return list
808
809 # Test
810 #import sys
811 #res = []
812 #groovesharkApi = GrooveAPI()
813 #res = groovesharkApi.pingService()
814 #res = groovesharkApi.login(sys.argv[1], sys.argv[2])
815 #songIDs = ['23404546','23401810','23401157']
816 #res = groovesharkApi.createPlaylist("Test")
817 #res = groovesharkApi.setPlaylistSongs(res, songIDs)
818 #res = groovesharkApi.getPlaylistSongs(42251632)
819 #res = groovesharkApi.getSongSearchResults('jimmy jazz', 3)
820 #res = groovesharkApi.getPopularSongsToday(3)
821 #res = groovesharkApi.getSongURLFromSongID('26579347')
822 #res = groovesharkApi.getAlbumSearchResults('london calling', 3)
823 #res = groovesharkApi.getArtistAlbums('52283')
824 #res = groovesharkApi.getArtistSearchResults('the clash', 3)
825 #res = groovesharkApi.getUserFavoriteSongs()
826 #res = groovesharkApi.getUserPlaylists()
827 #res = groovesharkApi.getSongInfo('27425375')
828 #res = groovesharkApi.getPlaylistSongs(40902662)
829 #res = groovesharkApi.addUserFavoriteSong('27425375')
830 #res = groovesharkApi.logout()
831 #res = groovesharkApi.getUserPlaylistsEx('stephendenham')
832 #res = groovesharkApi.getArtistPopularSongs('3707')
833 #
834 #pprint.pprint(res)