X-Git-Url: https://git.hcoop.net/clinton/xbmc-groove.git/blobdiff_plain/44dcc6f4add9cc470a9ee4a82db321ccb257b8be..7ce01be6d1a5a7c89224793d310a4623f362e720:/resources/lib/GroovesharkAPI.py diff --git a/resources/lib/GroovesharkAPI.py b/resources/lib/GroovesharkAPI.py index fbc0389..e36ffc2 100644 --- a/resources/lib/GroovesharkAPI.py +++ b/resources/lib/GroovesharkAPI.py @@ -1,13 +1,13 @@ -import socket, hmac, urllib, urllib2, pprint, md5, uuid, re, hashlib, time, random, os, pickle +import socket, hmac, urllib, urllib2, pprint, md5, re, sha, time, random, os, pickle, uuid, tempfile SESSION_EXPIRY = 518400 # 6 days in seconds # GrooveAPI constants THUMB_URL = 'http://beta.grooveshark.com/static/amazonart/' -THUMB_URL_DEFAULT = 'http://grooveshark.com/webincludes/logo/Grooveshark_Logo_No-Text.png' SONG_LIMIT = 25 ALBUM_LIMIT = 15 ARTIST_LIMIT = 15 +SONG_SUFFIX = '.mp3' # GrooveSong constants DOMAIN = "grooveshark.com" @@ -15,7 +15,6 @@ HOME_URL = "http://listen." + DOMAIN API_URL = "http://cowbell." + DOMAIN + "/more.php" SERVICE_URL = "http://cowbell." + DOMAIN + "/service.php" TOKEN_URL = "http://cowbell." + DOMAIN + "/more.php" -TOKEN_EXPIRY = 1000 CLIENT_NAME = "gslite" CLIENT_VERSION = "20101012.37" @@ -29,13 +28,12 @@ RANDOM_CHARS = "1234567890abcdef" # Get a song class GrooveSong: - def __init__(self, cacheDir): + def __init__(self): import simplejson self.simplejson = simplejson - - self.cacheDir = cacheDir - self._lastTokenTime = 0 + + self.cacheDir = os.path.join(tempfile.gettempdir(), 'groovesong') self._lastSessionTime = 0 self.uuid = self._getUUID() @@ -96,18 +94,16 @@ class GrooveSong: # Make a token ready for a request header def _getMethodToken(self, method): - if (time.time() - self._lastTokenTime) >= TOKEN_EXPIRY: - self._token = self._getCommunicationToken() - if self._token == None: - return None - self._lastTokenTime = time.time() - self._setSavedSession() + self._token = self._getCommunicationToken() + if self._token == None: + return None randomChars = "" while 6 > len(randomChars): randomChars = randomChars + random.choice(RANDOM_CHARS) - token = hashlib.sha1(method + ":" + self._token + ":quitStealinMahShit:" + randomChars).hexdigest() + token = sha.new(method + ":" + self._token + ":quitStealinMahShit:" + randomChars).hexdigest() + return randomChars + token # Generate a communication token @@ -140,7 +136,7 @@ class GrooveSong: # Generate a secret key from a sessionID def _getSecretKey(self, sessionID): - return hashlib.md5(sessionID).hexdigest() + return md5.new(sessionID).hexdigest() # Get a session id from some HTML def _getSession(self, html): @@ -159,14 +155,10 @@ class GrooveSong: session = pickle.load(f) self.sessionID = session['sessionID'] self._lastSessionTime = session['lastSessionTime'] - self._token = session['token'] - self._lastTokenTime = session['lastTokenTime'] f.close() except: self.sessionID = '' self._lastSessionTime = 0 - self._token = '' - self._lastTokenTime = 0 pass def _setSavedSession(self): @@ -176,7 +168,7 @@ class GrooveSong: os.makedirs(self.cacheDir) path = os.path.join(self.cacheDir, 'session.dmp') f = open(path, 'wb') - session = {'sessionID' : self.sessionID, 'lastSessionTime' : self._lastSessionTime, 'token' : self._token, 'lastTokenTime' : self._lastTokenTime} + session = {'sessionID' : self.sessionID, 'lastSessionTime' : self._lastSessionTime} pickle.dump(session, f, protocol=pickle.HIGHEST_PROTOCOL) f.close() except: @@ -192,9 +184,13 @@ class GrooveSong: "country": {"IPR":"1021","ID":"223", "CC1":"0", "CC2":"0", "CC3":"0", "CC4":"2147483648"} } response = self._callRemote("getStreamKeyFromSongIDEx", params) - self._lastStreamKey = response["result"]["streamKey"] - self._lastStreamServer = response["result"]["ip"] - self._lastStreamServerID = response["result"]["streamServerID"] + try: + self._lastStreamKey = response["result"]["streamKey"] + self._lastStreamServer = response["result"]["ip"] + self._lastStreamServerID = response["result"]["streamServerID"] + return True + except: + return False # Tells Grooveshark you have downloaded a song def _markSongDownloaded(self, songID): @@ -206,16 +202,18 @@ class GrooveSong: # Download a song to a temporary file def getSongURL(self, songID): - filename = os.path.join(self.cacheDir, songID + '.mp3') + filename = os.path.join(self.cacheDir, songID + SONG_SUFFIX) + print "Caching song " + songID + " to " + filename if os.path.isfile(filename) == False: - self._getStreamDetails(songID) - postData = {"streamKey": self._lastStreamKey} - postData = urllib.urlencode(postData) - urllib.FancyURLopener().retrieve( "http://" + self._lastStreamServer + "/stream.php", filename, data=postData) - self._markSongDownloaded(songID) + if self._getStreamDetails(songID) == True: + postData = {"streamKey": self._lastStreamKey} + postData = urllib.urlencode(postData) + urllib.FancyURLopener().retrieve( "http://" + self._lastStreamServer + "/stream.php", filename, data=postData) + self._markSongDownloaded(songID) + else: + return '' return filename - # Main API class GrooveAPI: @@ -225,11 +223,17 @@ class GrooveAPI: lastSessionTime = 0 # Constructor - def __init__(self, cacheDir): + def __init__(self): + import simplejson self.simplejson = simplejson socket.setdefaulttimeout(40) - self.cacheDir = cacheDir + + self.cacheDir = os.path.join(tempfile.gettempdir(), 'grooveapi') + if os.path.isdir(self.cacheDir) == False: + os.makedirs(self.cacheDir) + print "Made " + self.cacheDir + self._getSavedSession() # session ids last 1 week if self.sessionID == '' or time.time()- self.lastSessionTime >= SESSION_EXPIRY: @@ -263,6 +267,7 @@ class GrooveAPI: req = urllib2.Request(url) response = urllib2.urlopen(req) result = response.read() + print "Response..." pprint.pprint(result) response.close() try: @@ -279,7 +284,7 @@ class GrooveAPI: return result['result']['sessionID'] def _getSavedSession(self): - path = os.path.join(self.cacheDir, 'grooveapi', 'session.dmp') + path = os.path.join(self.cacheDir, 'session.dmp') try: f = open(path, 'rb') session = pickle.load(f) @@ -295,11 +300,10 @@ class GrooveAPI: def _setSavedSession(self): try: - dir = os.path.join(self.cacheDir, 'grooveapi') - # Create the 'data' directory if it doesn't exist. - if not os.path.exists(dir): - os.makedirs(dir) - path = os.path.join(dir, 'session.dmp') + # Create the directory if it doesn't exist. + if not os.path.exists(self.cacheDir): + os.makedirs(self.cacheDir) + path = os.path.join(self.cacheDir, 'session.dmp') f = open(path, 'wb') session = { 'sessionID' : self.sessionID, 'lastSessionTime' : self.lastSessionTime, 'userID': self.userID} pickle.dump(session, f, protocol=pickle.HIGHEST_PROTOCOL) @@ -362,12 +366,29 @@ class GrooveAPI: return self._parseSongs(result) else: return [] - + + # Get artists albums + def getArtistAlbums(self, artistID, limit=ALBUM_LIMIT): + result = self._callRemote('getArtistAlbums', {'artistID' : artistID}) + if 'result' in result: + return self._parseAlbums(result, limit) + else: + return [] + + # Get album songs + def getAlbumSongs(self, albumID, limit=SONG_LIMIT): + result = self._callRemote('getAlbumSongsEx', {'albumID' : albumID, 'limit' : limit}) + if 'result' in result: + return self._parseSongs(result) + else: + return [] + # Gets the popular songs def getPopularSongsToday(self, limit=SONG_LIMIT): result = self._callRemote('getPopularSongsToday', {'limit' : limit}) if 'result' in result: - return self._parseSongs(result) + # Note limit is broken in the Grooveshark getPopularSongsToday method + return self._parseSongs(result, limit) else: return [] @@ -387,11 +408,10 @@ class GrooveAPI: return False; result = self._callRemote('addUserFavoriteSong', {'sessionID' : self.sessionID, 'songID' : songID}) return result['result']['success'] - + # Get the url to link to a song on Grooveshark def getSongURLFromSongID(self, songID): - cacheDir = os.path.join(self.cacheDir, 'groovesong') - song = GrooveSong(cacheDir) + song = GrooveSong() return song.getSongURL(songID) # Get the url to link to a song on Grooveshark @@ -402,10 +422,10 @@ class GrooveAPI: if 'CoverArtFilename' in info and info['CoverArtFilename'] != None: info['CoverArtFilename'] = THUMB_URL+info['CoverArtFilename'].encode('ascii', 'ignore') else: - info['CoverArtFilename'] = THUMB_URL_DEFAULT + info['CoverArtFilename'] = 'None' return info else: - return '' + return 'None' # Gets the playlists of the logged-in user def getUserPlaylists(self): @@ -421,7 +441,7 @@ class GrooveAPI: def createPlaylist(self, name, songIDs): result = self._callRemote('createPlaylist', {'name' : name, 'songIDs' : songIDs, 'sessionID' : self.sessionID}) if 'result' in result and result['result']['success'] == True: - return result['result']['PlaylistID'] + return result['result']['playlistID'] elif 'errors' in result: return 0 @@ -429,9 +449,9 @@ class GrooveAPI: def setPlaylistSongs(self, playlistID, songIDs): result = self._callRemote('setPlaylistSongs', {'playlistID' : playlistID, 'songIDs' : songIDs, 'sessionID' : self.sessionID}) if 'result' in result and result['result']['success'] == True: - return True; + return True else: - return False; + return False # Gets the songs of a playlist def getPlaylistSongs(self, playlistID): @@ -440,9 +460,17 @@ class GrooveAPI: return self._parseSongs(result) else: return [] + + # Check the service + def pingService(self,): + result = self._callRemote('pingService', {}); + if 'result' in result and result['result'] != '': + return True + else: + return False # Extract song data - def _parseSongs(self, items): + def _parseSongs(self, items, limit=0): if 'result' in items: i = 0 list = [] @@ -455,6 +483,8 @@ class GrooveAPI: else: l = len(items['result']) index = '' + if limit > 0 and l > limit: + l = limit while(i < l): if index == 'songs': s = items['result'][index][i] @@ -468,7 +498,7 @@ class GrooveAPI: elif s['CoverArtFilename'] != None: coverart = THUMB_URL+s['CoverArtFilename'].encode('ascii', 'ignore') else: - coverart = THUMB_URL_DEFAULT + coverart = 'None' list.append([s['SongName'].encode('ascii', 'ignore'),\ s['SongID'],\ s['AlbumName'].encode('ascii', 'ignore'),\ @@ -497,17 +527,24 @@ class GrooveAPI: return [] # Extract album data - def _parseAlbums(self, items): + def _parseAlbums(self, items, limit=0): if 'result' in items: i = 0 list = [] - albums = items['result']['albums'] - while(i < len(albums)): + try: + albums = items['result']['albums'] + except: + res = items['result'][0] + albums = res['albums'] + l = len(albums) + if limit > 0 and l > limit: + l = limit + while(i < l): s = albums[i] if 'CoverArtFilename' in s and s['CoverArtFilename'] != None: coverart = THUMB_URL+s['CoverArtFilename'].encode('ascii', 'ignore') else: - coverart = THUMB_URL_DEFAULT + coverart = 'None' list.append([s['ArtistName'].encode('ascii', 'ignore'),\ s['ArtistID'],\ s['AlbumName'].encode('ascii', 'ignore'),\ @@ -525,24 +562,27 @@ class GrooveAPI: playlists = items['result'] while(i < len(playlists)): s = playlists[i] - list.append([s['PlaylistID'],\ - s['Name'].encode('ascii', 'ignore')]) + list.append([s['Name'].encode('ascii', 'ignore'), s['PlaylistID']]) i = i + 1 return list else: return [] - - # Test -import sys -res = [] -groovesharkApi = GrooveAPI('/tmp') +#import sys +#res = [] +#groovesharkApi = GrooveAPI() +#res = groovesharkApi.pingService() #res = groovesharkApi.login(sys.argv[1], sys.argv[2]) +#songIDs = ['23404546','23401810','23401157'] +#res = groovesharkApi.createPlaylist("Test") +#res = groovesharkApi.setPlaylistSongs(res, songIDs) +#res = groovesharkApi.getPlaylistSongs(42251632) #res = groovesharkApi.getSongSearchResults('jimmy jazz', 3) -#res = groovesharkApi.getPopularSongsToday() -res = groovesharkApi.getSongURLFromSongID('27425375') +#res = groovesharkApi.getPopularSongsToday(3) +#res = groovesharkApi.getSongURLFromSongID('26579347') #res = groovesharkApi.getAlbumSearchResults('london calling', 3) +#res = groovesharkApi.getArtistAlbums('52283') #res = groovesharkApi.getArtistSearchResults('the clash', 3) #res = groovesharkApi.getUserFavoriteSongs() #res = groovesharkApi.getUserPlaylists() @@ -550,8 +590,5 @@ res = groovesharkApi.getSongURLFromSongID('27425375') #res = groovesharkApi.getPlaylistSongs(40902662) #res = groovesharkApi.addUserFavoriteSong('27425375') #res = groovesharkApi.logout() - -pprint.pprint(res) - - - +# +#pprint.pprint(res)