0c09e2513d0e024bb2e835def83a1e1201a27484
1 import socket
, hmac
, urllib
, urllib2
, pprint
, md5
, os
, pickle
, tempfile
, time
, re
, simplejson
3 SESSION_EXPIRY
= 1209600 # 2 weeks
6 WEB_APP_URL
= "http://xbmc-groove.appspot.com/"
9 THUMB_URL
= 'http://beta.grooveshark.com/static/amazonart/m'
24 _lastStreamServerID
= ''
29 self
.simplejson
= simplejson
30 socket
.setdefaulttimeout(40)
31 self
.cacheDir
= os
.path
.join(tempfile
.gettempdir(), 'groovesharkapi')
32 if os
.path
.isdir(self
.cacheDir
) == False:
33 os
.makedirs(self
.cacheDir
)
34 print "Made " + self
.cacheDir
35 self
._getSavedSession
()
36 # session ids last 2 weeks
37 if self
._sessionID
== '' or time
.time()- self
._lastSessionTime
>= SESSION_EXPIRY
:
38 self
._sessionID
= self
._getSessionID
()
39 self
._ip
= self
._getIP
()
40 self
._country
= self
._getCountry
()
41 if self
._sessionID
== '':
42 raise StandardError('Failed to get session id')
44 print "New GrooveAPI session id: " + self
._sessionID
45 self
._setSavedSession
()
48 def _callRemote(self
, method
, params
):
50 res
= self
._getRemote
(method
, params
)
52 postData
= res
['postData']
53 req
= urllib2
.Request(url
, postData
)
54 response
= urllib2
.urlopen(req
)
55 result
= response
.read()
59 result
= simplejson
.loads(result
)
65 def _getRemote(self
, method
, params
= {}):
66 postData
= { "method": method
, "sessionid": self
._sessionID
, "parameters": params
}
67 postData
= simplejson
.dumps(postData
)
68 url
= WEB_APP_URL
+ "?postData=" + urllib
.quote_plus(postData
)
69 req
= urllib2
.Request(url
)
70 response
= urllib2
.urlopen(req
)
71 result
= response
.read()
76 result
= simplejson
.loads(result
)
82 def _getSessionID(self
):
84 result
= self
._callRemote
('startSession', params
)
85 self
._lastSessionTime
= time
.time()
86 if 'result' in result
:
87 return result
['result']['sessionID']
91 def _getSavedSession(self
):
92 path
= os
.path
.join(self
.cacheDir
, 'session.dmp')
95 session
= pickle
.load(f
)
96 self
._sessionID
= session
['sessionID']
97 self
._lastSessionTime
= session
['lastSessionTime']
98 self
._userID
= session
['userID']
99 self
._ip
= session
['ip']
100 self
._country
= session
['country']
104 self
._lastSessionTime
= 0
110 def _setSavedSession(self
):
112 # Create the directory if it doesn't exist.
113 if not os
.path
.exists(self
.cacheDir
):
114 os
.makedirs(self
.cacheDir
)
115 path
= os
.path
.join(self
.cacheDir
, 'session.dmp')
117 session
= { 'sessionID' : self
._sessionID
, 'lastSessionTime' : self
._lastSessionTime
, 'userID': self
._userID
, 'ip' : self
._ip
, 'country' : self
._country
}
118 pickle
.dump(session
, f
, protocol
=pickle
.HIGHEST_PROTOCOL
)
121 print "An error occurred during save session"
124 def _setParams(self
, params
):
126 # Create the directory if it doesn't exist.
127 if not os
.path
.exists(self
.cacheDir
):
128 os
.makedirs(self
.cacheDir
)
129 path
= os
.path
.join(self
.cacheDir
, 'params.dmp')
131 pickle
.dump(params
, f
, protocol
=pickle
.HIGHEST_PROTOCOL
)
134 print "An error occurred during save params"
140 myip
= urllib2
.urlopen('http://whatismyip.org').read()
141 if re
.match("^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$", myip
):
142 print "IP is " + myip
148 def _getCountry(self
):
149 params
= { 'ip' : self
._ip
}
150 response
= self
._callRemote
("getCountry", params
)
151 return response
['result']
153 # Get userid from name
154 def _getUserIDFromUsername(self
, username
):
155 result
= self
._callRemote
('getUserIDFromUsername', {'username' : username
})
156 if 'result' in result
and result
['result']['UserID'] > 0:
157 return result
['result']['UserID']
161 # Authenticates the user for current API session
162 def _authenticate(self
, login
, password
):
163 md5pwd
= md5
.new(password
).hexdigest()
164 params
= {'login': login
, 'password': md5pwd
}
166 result
= self
._callRemote
('authenticate', params
)
168 uid
= result
['result']['UserID']
177 def pingService(self
,):
178 result
= self
._callRemote
('pingService', {});
179 if 'result' in result
and result
['result'] != '':
185 def login(self
, username
, password
):
186 if self
._userID
<= 0:
188 self
._getSavedSession
()
189 if self
._userID
<= 0:
190 self
._userID
= self
._authenticate
(username
, password
)
192 self
._setSavedSession
()
197 result
= self
._callRemote
('logout', {'sessionID' : self
._sessionID
})
198 if 'result' in result
and result
['result']['success'] == True:
200 self
._setSavedSession
()
204 # Gets a stream key and host to get song content
205 def getSubscriberStreamKey(self
, songID
):
206 params
= { "songID": songID
, "country": self
._country
}
207 response
= self
._callRemote
("getSubscriberStreamKey", params
)
209 self
._lastStreamKey
= response
["result"]["StreamKey"]
210 self
._lastStreamServerID
= response
["result"]["StreamServerID"]
211 res
= response
["result"]
217 def getArtistSearchResults(self
, query
, limit
=ARTIST_LIMIT
):
218 result
= self
._callRemote
('getArtistSearchResults', {'query' : query
,'limit' : limit
})
219 if 'result' in result
:
220 return self
._parseArtists
(result
)
225 def getAlbumSearchResults(self
, query
, limit
=ALBUM_LIMIT
):
226 result
= self
._callRemote
('getAlbumSearchResults', {'query' : query
,'limit' : limit
})
227 if 'result' in result
:
228 return self
._parseAlbums
(result
)
233 def getSongSearchResults(self
, query
, limit
=SONG_LIMIT
):
234 result
= self
._callRemote
('getSongSearchResults', {'query' : query
, 'country' : self
._country
, 'limit' : limit
})
235 if 'result' in result
:
236 return self
._parseSongs
(result
)
241 def getArtistAlbums(self
, artistID
, limit
=ALBUM_LIMIT
):
242 result
= self
._callRemote
('getArtistAlbums', {'artistID' : artistID
})
243 if 'result' in result
:
244 return self
._parseAlbums
(result
, limit
)
249 def getAlbumSongs(self
, albumID
, limit
=SONG_LIMIT
):
250 result
= self
._callRemote
('getAlbumSongs', {'albumID' : albumID
, 'limit' : limit
})
251 if 'result' in result
:
252 return self
._parseSongs
(result
)
256 # Get artist's popular songs
257 def getArtistPopularSongs(self
, artistID
, limit
= SONG_LIMIT
):
258 result
= self
._callRemote
('getArtistPopularSongs', {'artistID' : artistID
})
259 if 'result' in result
:
260 return self
._parseSongs
(result
, limit
)
264 # Gets the popular songs
265 def getPopularSongsToday(self
, limit
=SONG_LIMIT
):
266 result
= self
._callRemote
('getPopularSongsToday', {'limit' : limit
})
267 if 'result' in result
:
268 # Note limit is broken in the Grooveshark getPopularSongsToday method
269 return self
._parseSongs
(result
, limit
)
273 # Gets the favorite songs of the logged-in user
274 def getUserFavoriteSongs(self
):
275 if (self
._userID
== 0):
277 result
= self
._callRemote
('getUserFavoriteSongs', {})
278 if 'result' in result
:
279 return self
._parseSongs
(result
)
284 def getSongsInfo(self
, songIDs
):
285 result
= self
._callRemote
('getSongsInfo', {'songIDs' : songIDs
})
286 if 'result' in result
and 'SongID' in result
['result']:
287 info
= result
['result']
288 if 'CoverArtFilename' in info
and info
['CoverArtFilename'] != None:
289 info
['CoverArtFilename'] = THUMB_URL
+info
['CoverArtFilename'].encode('ascii', 'ignore')
291 info
['CoverArtFilename'] = 'None'
296 # Add song to user favorites
297 def addUserFavoriteSong(self
, songID
):
298 if (self
._userID
== 0):
300 result
= self
._callRemote
('addUserFavoriteSong', {'songID' : songID
})
301 return result
['result']['success']
303 # Remove songs from user favorites
304 def removeUserFavoriteSongs(self
, songIDs
):
305 if (self
._userID
== 0):
307 result
= self
._callRemote
('removeUserFavoriteSongs', {'songIDs' : songIDs
})
308 return result
['result']['success']
310 # Gets the playlists of the logged-in user
311 def getUserPlaylists(self
):
312 if (self
._userID
== 0):
314 result
= self
._callRemote
('getUserPlaylists', {})
315 if 'result' in result
:
316 return self
._parsePlaylists
(result
)
320 # Gets the playlists of the logged-in user
321 def getUserPlaylistsByUsername(self
, username
):
322 userID
= self
._getUserIDFromUsername
(username
)
324 result
= self
._callRemote
('getUserPlaylistsByUserID', {'userID' : userID
})
325 if 'result' in result
and result
['result']['playlists'] != None:
326 playlists
= result
['result']['playlists']
327 return self
._parsePlaylists
(playlists
)
331 # Creates a playlist with songs
332 def createPlaylist(self
, name
, songIDs
):
333 result
= self
._callRemote
('createPlaylist', {'name' : name
, 'songIDs' : songIDs
})
334 if 'result' in result
and result
['result']['success'] == True:
335 return result
['result']['playlistID']
336 elif 'errors' in result
:
339 # Sets the songs for a playlist
340 def setPlaylistSongs(self
, playlistID
, songIDs
):
341 result
= self
._callRemote
('setPlaylistSongs', {'playlistID' : playlistID
, 'songIDs' : songIDs
})
342 if 'result' in result
and result
['result']['success'] == True:
347 # Gets the songs of a playlist
348 def getPlaylistSongs(self
, playlistID
):
349 result
= self
._callRemote
('getPlaylistSongs', {'playlistID' : playlistID
});
350 if 'result' in result
:
351 return self
._parseSongs
(result
)
356 def playlistDelete(self
, playlistId
):
357 result
= self
._callRemote
("deletePlaylist", {"playlistID": playlistId
})
358 if 'fault' in result
:
363 def playlistRename(self
, playlistId
, name
):
364 result
= self
._callRemote
("renamePlaylist", {"playlistID": playlistId
, "name": name
})
365 if 'fault' in result
:
370 def getSimilarArtists(self
, artistId
, limit
):
371 items
= self
._callRemote
("getSimilarArtists", {"artistID": artistId
, "limit": limit
})
372 if 'result' in items
:
375 artists
= items
['result']['artists']
376 while(i
< len(artists
)):
378 list.append([s
['artistName'].encode('ascii', 'ignore'),\
385 # After 30s play time
386 def markStreamKeyOver30Secs(self
):
387 params
= { "streamKey" : self
._lastStreamKey
, "streamServerID" : self
._lastStreamServerID
}
388 self
._callRemote
("markStreamKeyOver30Secs", params
)
391 def markSongComplete(self
, songid
):
392 params
= { "songID" : songid
, "streamKey" : self
._lastStreamKey
, "streamServerID" : self
._lastStreamServerID
}
393 self
._callRemote
("markSongComplete", params
)
396 def _parseSongs(self
, items
, limit
=0):
397 if 'result' in items
:
403 if 'songs' in items
['result'][0]:
404 l
= len(items
['result'][0]['songs'])
408 if l
< 0 and 'songs' in items
['result']:
409 l
= len(items
['result']['songs'])
413 if l
< 0 and 'song' in items
['result']:
419 l
= len(items
['result'])
422 if limit
> 0 and l
> limit
:
425 if index
== 'songs[]':
426 s
= items
['result'][0]['songs'][i
]
427 elif index
== 'songs':
428 s
= items
['result'][index
][i
]
429 elif index
== 'song':
430 s
= items
['result'][index
]
432 s
= items
['result'][i
]
433 if 'CoverArtFilename' not in s
:
434 info
= self
.getSongsInfo(s
['SongID'])
435 coverart
= info
['CoverArtFilename']
436 elif s
['CoverArtFilename'] != None:
437 coverart
= THUMB_URL
+s
['CoverArtFilename'].encode('ascii', 'ignore')
440 list.append([s
['SongName'].encode('ascii', 'ignore'),\
442 s
['AlbumName'].encode('ascii', 'ignore'),\
444 s
['ArtistName'].encode('ascii', 'ignore'),\
452 # Extract artist data
453 def _parseArtists(self
, items
):
454 if 'result' in items
:
457 artists
= items
['result']['artists']
458 while(i
< len(artists
)):
460 list.append([s
['ArtistName'].encode('ascii', 'ignore'),\
468 def _parseAlbums(self
, items
, limit
=0):
469 if 'result' in items
:
473 albums
= items
['result']['albums']
475 res
= items
['result'][0]
476 albums
= res
['albums']
478 if limit
> 0 and l
> limit
:
482 if 'CoverArtFilename' in s
and s
['CoverArtFilename'] != None:
483 coverart
= THUMB_URL
+s
['CoverArtFilename'].encode('ascii', 'ignore')
486 list.append([s
['ArtistName'].encode('ascii', 'ignore'),\
488 s
['AlbumName'].encode('ascii', 'ignore'),\
496 def _parsePlaylists(self
, items
):
499 if 'result' in items
:
500 playlists
= items
['result']['playlists']
506 while (i
< len(playlists
)):
508 list.append([str(s
['PlaylistName']).encode('ascii', 'ignore'), s
['PlaylistID']])