X-Git-Url: https://git.hcoop.net/clinton/xbmc-groove.git/blobdiff_plain/1413d3577010bf704112da29456be81a9427c237..c50484564d64db190f22875d73750e824951dcdf:/resources/lib/GroovesharkAPI.py diff --git a/resources/lib/GroovesharkAPI.py b/resources/lib/GroovesharkAPI.py dissimilarity index 67% index 18dd631..9a91245 100644 --- a/resources/lib/GroovesharkAPI.py +++ b/resources/lib/GroovesharkAPI.py @@ -1,488 +1,526 @@ -import socket, hmac, urllib, urllib2, pprint, md5, uuid, re, hashlib, time, random, os, pickle - -# 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 - -# GrooveSong constants -DOMAIN = "grooveshark.com" -HOME_URL = "http://listen." + DOMAIN -TOKEN_URL = "http://cowbell." + DOMAIN + "/more.php" -API_URL = "http://cowbell." + DOMAIN + "/more.php" -SERVICE_URL = "http://cowbell." + DOMAIN + "/service.php" - -CLIENT_NAME = "gslite" #htmlshark #jsqueue -CLIENT_VERSION = "20101012.37" #"20100831.25" -HEADERS = {"Content-Type": "application/json", - "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)", - "Referer": "http://listen.grooveshark.com/main.swf?cowbell=fe87233106a6cef919a1294fb2c3c05f"} - -RE_SESSION = re.compile('"sessionID":"\s*?([A-z0-9]+)"') #re.compile('sessionID:\s*?\'([A-z0-9]+)\',') -RANDOM_CHARS = "1234567890abcdef" - -# Get a song -class GrooveSong: - - def __init__(self, cacheDir): - - import simplejson - self.simplejson = simplejson - - self.cacheDir = cacheDir - self._lastTokenTime = 0 - self.uuid = self._getUUID() - self.sessionID = self._getSession(HOME_URL) - if self.sessionID == None: - raise StandardError("Cannot get session id") - - # The actual call to the API - def _callRemote(self, method, params, type="default"): - postData = { - "header": { - "client": CLIENT_NAME, - "clientRevision": CLIENT_VERSION, - "uuid": self.uuid, - "session": self.sessionID}, - "country": {"IPR":"1021", "ID":"223", "CC1":"0", "CC2":"0", "CC3":"0", "CC4":"2147483648"}, - "privacy": 1, - "parameters": params, - "method": method} - - token = self._getMethodToken(method) - if token == None: - raise StandardError("Cannot get token") - - postData["header"]["token"] = token - if type == "service": - url = SERVICE_URL + "?" + method - else: - url = API_URL + "?" + method - - postData = self.simplejson.dumps(postData) - print "GrooveSong URL: " + url - request = urllib2.Request(url, postData, HEADERS) - - response = urllib2.urlopen(request).read() - try: - response = self.simplejson.loads(response) - print "GrooveSong Response..." - pprint.pprint(response) - except: - raise StandardError("API error: " + response) - try: - response["fault"] - except KeyError: - return response - else: - raise StandardError("API error: " + response["fault"]["message"]) - - # Generate a random uuid - def _getUUID(self): - return str(uuid.uuid4()) - - # Make a token ready for a request header - def _getMethodToken(self, method): - if (time.time() - self._lastTokenTime) >= 1000: - self._token = self._getCommunicationToken() - if self._token == None: - return None - self._lastTokenTime = time.time() - - randomChars = "" - while 6 > len(randomChars): - randomChars = randomChars + random.choice(RANDOM_CHARS) - - token = hashlib.sha1(method + ":" + self._token + ":quitStealinMahShit:" + randomChars).hexdigest() - return randomChars + token - - # Generate a communication token - def _getCommunicationToken(self): - params = {"secretKey": self._getSecretKey(self.sessionID)} - postData = { - "header": { - "client": CLIENT_NAME, - "clientRevision": CLIENT_VERSION, - "uuid": self.uuid, - "session": self.sessionID}, - "country": {"IPR":"1021", "ID":"223", "CC1":"0", "CC2":"0", "CC3":"0", "CC4":"2147483648"}, - "privacy": 1, - "parameters": params, - "method": "getCommunicationToken"} - - postData = self.simplejson.dumps(postData) - request = urllib2.Request(TOKEN_URL, postData, HEADERS) - response = urllib2.urlopen(request).read() - try: - response = self.simplejson.loads(response) - except: - raise StandardError("API error: " + response) - try: - response["fault"] - except KeyError: - return response["result"] - else: - return None - - # Generate a secret key from a sessionID - def _getSecretKey(self, sessionID): - return hashlib.md5(sessionID).hexdigest() - - # Get a session id from some HTML - def _getSession(self, html): - html = urllib2.urlopen(HOME_URL).read() - session = RE_SESSION.search(html) - if session: - return session.group(1) - else: - return None - - # Gets a stream key and host to get song content - def _getStreamDetails(self, songID): - params = { - "songID": songID, - "prefetch": False, - "mobile": False, - "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"] - - # Tells Grooveshark you have downloaded a song - def _markSongDownloaded(self, songID): - params = { - "streamKey": self._lastStreamKey, - "streamServerID": self._lastStreamServerID, - "songID": songID} - self._callRemote("markSongDownloaded", params) - - # Download a song to a temporary file - def getSongURL(self, songID): - filename = os.path.join(self.cacheDir, songID + '.mp3') - 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) - return filename - - -# Main API -class GrooveAPI: - - sessionID = '' - userID = 0 - host = 'api.grooveshark.com' - - # Constructor - def __init__(self, cacheDir): - import simplejson - self.simplejson = simplejson - socket.setdefaulttimeout(40) - self.cacheDir = cacheDir - self.sessionID = self._getSavedSessionID() - if self.sessionID == '': - self.sessionID = self._getSessionID() - if self.sessionID == '': - raise StandardError('Failed to get session id') - else: - self._setSavedSessionID() - # Sort keys - def _keySort(self, d): - return [(k,d[k]) for k in sorted(d.keys())] - - # Make a message sig - def _createMessageSig(self, method, params, secret): - args = self._keySort(params); - data = ''; - for arg in args: - data += str(arg[0]) - data += str(arg[1]) - data = method + data - - h = hmac.new(secret, data) - return h.hexdigest() - - # The actual call to the API - def _callRemote(self, method, params = {}): - 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')) - print url - req = urllib2.Request(url) - response = urllib2.urlopen(req) - result = response.read() - pprint.pprint(result) - response.close() - try: - result = self.simplejson.loads(result) - return result - except: - return [] - - # Get a session id - def _getSessionID(self): - params = {} - result = self._callRemote('startSession', params) - return result['result']['sessionID'] - - def _getSavedSessionID(self): - sessionID = '' - path = os.path.join(self.cacheDir, 'session', 'session.txt') - try: - f = open(path, 'rb') - sessionID = pickle.load(f) - f.close() - except: - sessionID = '' - pass - - return sessionID - - def _setSavedSessionID(self): - try: - dir = os.path.join(self.cacheDir, 'session') - # Create the 'data' directory if it doesn't exist. - if not os.path.exists(dir): - os.makedirs(dir) - path = os.path.join(dir, 'session.txt') - f = open(path, 'wb') - pickle.dump(self.sessionID, f, protocol=pickle.HIGHEST_PROTOCOL) - f.close() - except: - print "An error occured during save session" - pass - - # Make user authentication token - def _getUserToken(self, username, password): - return md5.new(username.lower() + md5.new(password).hexdigest()).hexdigest() - - # Authenticates the user for current API session - def _authenticateUser(self, username, token): - params = {'sessionID': self.sessionID, 'username': username, 'token': token} - result = self._callRemote('authenticateUser', params) - return result['result']['UserID'] - - # Login - def login(self, username, password): - token = self._getUserToken(username, password) - self.userID = self._authenticateUser(username, token) - return self.userID - - # Logs the user out - def logout(self): - self._callRemote('logout', {'sessionID' : self.sessionID}) - - # Return user id - def getUserID(self): - return self.userID - - # Search for albums - def getArtistSearchResults(self, query, limit=ARTIST_LIMIT): - result = self._callRemote('getArtistSearchResults', {'query' : query,'limit' : limit}) - if 'result' in result: - return self._parseArtists(result) - else: - return [] - - # Search for albums - def getAlbumSearchResults(self, query, limit=ALBUM_LIMIT): - result = self._callRemote('getAlbumSearchResults', {'query' : query,'limit' : limit}) - if 'result' in result: - return self._parseAlbums(result) - else: - return [] - - # Search for songs - def getSongSearchResults(self, query, limit=SONG_LIMIT): - result = self._callRemote('getSongSearchResultsEx', {'query' : query, '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) - else: - return [] - - # Gets the favorite songs of the logged-in user - def getUserFavoriteSongs(self): - if (self.userID == 0): - return []; - result = self._callRemote('getUserFavoriteSongs', {'sessionID' : self.sessionID}) - if 'result' in result: - return self._parseSongs(result) - else: - return [] - - # Get the url to link to a song on Grooveshark - def getSongURLFromSongID(self, songID): - song = GrooveSong(self.cacheDir) - return song.getSongURL(songID) - - # Get the url to link to a song on Grooveshark - def getSongInfo(self, songID): - result = self._callRemote('getSongInfoEx', {'songID' : songID}) - if 'result' in result and 'SongID' in result['result']: - info = result['result'] - if 'CoverArtFilename' in info and info['CoverArtFilename'] != None: - info['CoverArtFilename'] = THUMB_URL+info['CoverArtFilename'].encode('ascii', 'ignore') - else: - info['CoverArtFilename'] = THUMB_URL_DEFAULT - return info - else: - return '' - - # Gets the playlists of the logged-in user - def getUserPlaylists(self): - if (self.userID == 0): - return []; - result = self._callRemote('getUserPlaylists', {'sessionID' : self.sessionID}) - if 'result' in result: - return self._parsePlaylists(result) - else: - return [] - - # Creates a playlist with songs - 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'] - elif 'errors' in result: - return 0 - - # Sets the songs for a playlist - 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; - else: - return False; - - # Gets the songs of a playlist - def getPlaylistSongs(self, playlistID): - result = self._callRemote('getPlaylistSongs', {'playlistID' : playlistID}); - if 'result' in result: - return self._parseSongs(result) - else: - return [] - - # Extract song data - def _parseSongs(self, items): - if 'result' in items: - i = 0 - list = [] - if 'songs' in items['result']: - l = len(items['result']['songs']) - index = 'songs' - elif 'song' in items['result']: - l = 1 - index = 'song' - else: - l = len(items['result']) - index = '' - while(i < l): - if index == 'songs': - s = items['result'][index][i] - elif index == 'song': - s = items['result'][index] - else: - s = items['result'][i] - if 'CoverArtFilename' not in s: - info = self.getSongInfo(s['SongID']) - coverart = info['CoverArtFilename'] - elif s['CoverArtFilename'] != None: - coverart = THUMB_URL+s['CoverArtFilename'].encode('ascii', 'ignore') - else: - coverart = THUMB_URL_DEFAULT - list.append([s['SongName'].encode('ascii', 'ignore'),\ - s['SongID'],\ - s['AlbumName'].encode('ascii', 'ignore'),\ - s['AlbumID'],\ - s['ArtistName'].encode('ascii', 'ignore'),\ - s['ArtistID'],\ - coverart]) - i = i + 1 - return list - else: - return [] - - # Extract artist data - def _parseArtists(self, items): - if 'result' in items: - i = 0 - list = [] - artists = items['result']['artists'] - while(i < len(artists)): - s = artists[i] - list.append([s['ArtistName'].encode('ascii', 'ignore'),\ - s['ArtistID']]) - i = i + 1 - return list - else: - return [] - - # Extract album data - def _parseAlbums(self, items): - if 'result' in items: - i = 0 - list = [] - albums = items['result']['albums'] - while(i < len(albums)): - s = albums[i] - if 'CoverArtFilename' in s and s['CoverArtFilename'] != None: - coverart = THUMB_URL+s['CoverArtFilename'].encode('ascii', 'ignore') - else: - coverart = THUMB_URL_DEFAULT - list.append([s['ArtistName'].encode('ascii', 'ignore'),\ - s['ArtistID'],\ - s['AlbumName'].encode('ascii', 'ignore'),\ - s['AlbumID'],\ - coverart]) - i = i + 1 - return list - else: - return [] - - def _parsePlaylists(self, items): - if 'result' in items: - i = 0 - list = [] - playlists = items['result'] - while(i < len(playlists)): - s = playlists[i] - list.append([s['PlaylistID'],\ - s['Name'].encode('ascii', 'ignore')]) - i = i + 1 - return list - else: - return [] - - - -# Test - -#res = [] -#groovesharkApi = GrooveAPI('/tmp') -#res = groovesharkApi.login('stephendenham', '*******') -#res = groovesharkApi.getSongSearchResults('jimmy jazz', 3) -#res = groovesharkApi.getPopularSongsToday() -#res = groovesharkApi.getSongURLFromSongID('27425375') -#res = groovesharkApi.getAlbumSearchResults('london calling', 3) -#res = groovesharkApi.getArtistSearchResults('the clash', 3) -#res = groovesharkApi.getUserFavoriteSongs() -#res = groovesharkApi.getUserPlaylists() -#res = groovesharkApi.getSongInfo('27425375') -#res = groovesharkApi.getPlaylistSongs(40902662) - -#pprint.pprint(res) - - - +import socket, urllib, urllib2, pprint, md5, os, pickle, tempfile, time, re, simplejson, base64 +from blowfish import Blowfish + +SESSION_EXPIRY = 1209600 # 2 weeks + +# Web app +WEB_APP_URL = "http://xbmc-groove.appspot.com/" + +# GrooveAPI constants +THUMB_URL = 'http://beta.grooveshark.com/static/amazonart/m' +SONG_LIMIT = 25 +ALBUM_LIMIT = 15 +ARTIST_LIMIT = 15 +SONG_SUFFIX = '.mp3' + +# Main API +class GrooveAPI: + + _ip = '0.0.0.0' + _country = '' + _sessionID = '' + _userID = 0 + _lastSessionTime = 0 + _lastStreamKey = '' + _lastStreamServerID = '' + _key = md5.new(os.path.basename("GroovesharkAPI.py")).hexdigest() + + # Constructor + def __init__(self): + + self.simplejson = simplejson + self.cacheDir = os.path.join(tempfile.gettempdir(), 'groovesharkapi') + if os.path.isdir(self.cacheDir) == False: + os.makedirs(self.cacheDir) + print "Made " + self.cacheDir + self._getSavedSession() + # session ids last 2 weeks + if self._sessionID == '' or time.time()- self._lastSessionTime >= SESSION_EXPIRY: + self._sessionID = self._getSessionID() + if self._sessionID == '': + raise StandardError('Failed to get session id') + else: + print "New GrooveAPI session id: " + self._sessionID + self._ip = self._getIP() + self._country = self._getCountry() + self._setSavedSession() + + # Call to API + def _callRemote(self, method, params): + try: + res = self._getRemote(method, params) + url = res['url'] + postData = res['postData'] + except: + print "Failed to get request URL and post data" + return [] + try: + req = urllib2.Request(url, postData) + response = urllib2.urlopen(req) + result = response.read() + print "Response..." + pprint.pprint(result) + response.close() + result = simplejson.loads(result) + return result + except urllib2.HTTPError, e: + print "HTTP error " + e.code + except urllib2.URLError, e: + print "URL error " + e.reason + except: + print "Request to Grooveshark API failed" + return [] + + + # Get the API call + def _getRemote(self, method, params = {}): + postData = { "method": method, "sessionid": self._sessionID, "parameters": params } + postData = simplejson.dumps(postData) + + cipher = Blowfish(self._key) + cipher.initCTR() + encryptedPostData = cipher.encryptCTR(postData) + encryptedPostData = base64.urlsafe_b64encode(encryptedPostData) + url = WEB_APP_URL + "?postData=" + encryptedPostData + req = urllib2.Request(url) + response = urllib2.urlopen(req) + result = response.read() + print "Request..." + pprint.pprint(result) + response.close() + try: + result = simplejson.loads(result) + return result + except: + return [] + + # Get a session id + def _getSessionID(self): + params = {} + result = self._callRemote('startSession', params) + if 'result' in result: + self._lastSessionTime = time.time() + return result['result']['sessionID'] + else: + return '' + + def _getSavedSession(self): + path = os.path.join(self.cacheDir, 'session.dmp') + try: + f = open(path, 'rb') + session = pickle.load(f) + self._sessionID = session['sessionID'] + self._lastSessionTime = session['lastSessionTime'] + self._userID = session['userID'] + self._ip = session['ip'] + self._country = session['country'] + f.close() + except: + self._sessionID = '' + self._lastSessionTime = 0 + self._userID = 0 + self._ip = '0.0.0.0' + self._country = '' + pass + + def _setSavedSession(self): + try: + # 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, 'ip' : self._ip, 'country' : self._country } + pickle.dump(session, f, protocol=pickle.HIGHEST_PROTOCOL) + f.close() + except: + print "An error occurred during save session" + pass + + def _setParams(self, params): + try: + # 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, 'params.dmp') + f = open(path, 'wb') + pickle.dump(params, f, protocol=pickle.HIGHEST_PROTOCOL) + f.close() + except: + print "An error occurred during save params" + pass + + # Get IP + def _getIP(self): + try: + myip = urllib2.urlopen('http://whatismyip.org').read() + 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): + print "IP is " + myip + return myip + except: + return '0.0.0.0' + + # Get country + def _getCountry(self): + params = { 'ip' : self._ip } + response = self._callRemote("getCountry", params) + return response['result'] + + # Get userid from name + def _getUserIDFromUsername(self, username): + result = self._callRemote('getUserIDFromUsername', {'username' : username}) + if 'result' in result and result['result']['UserID'] > 0: + return result['result']['UserID'] + else: + return 0 + + # Authenticates the user for current API session + def _authenticate(self, login, password): + md5pwd = md5.new(password).hexdigest() + params = {'login': login, 'password': md5pwd} + + result = self._callRemote('authenticate', params) + try: + uid = result['result']['UserID'] + except: + uid = 0 + if (uid > 0): + return uid + else: + return 0 + + # Check the service + def pingService(self,): + result = self._callRemote('pingService', {}); + if 'result' in result and result['result'] != '': + return True + else: + return False + + # Login + def login(self, username, password): + if self._userID <= 0: + # Check cache + self._getSavedSession() + if self._userID <= 0: + self._userID = self._authenticate(username, password) + if self._userID > 0: + self._setSavedSession() + return self._userID + + # Logs the user out + def logout(self): + result = self._callRemote('logout', {'sessionID' : self._sessionID}) + if 'result' in result and result['result']['success'] == True: + self._userID = 0 + self._setSavedSession() + return True + return False + + # Gets a stream key and host to get song content + def getSubscriberStreamKey(self, songID): + params = { "songID": songID, "country": self._country } + response = self._callRemote("getSubscriberStreamKey", params) + try: + self._lastStreamKey = response["result"]["StreamKey"] + self._lastStreamServerID = response["result"]["StreamServerID"] + res = response["result"] + return res + except: + return False + + # Search for albums + def getArtistSearchResults(self, query, limit=ARTIST_LIMIT): + result = self._callRemote('getArtistSearchResults', {'query' : query,'limit' : limit}) + if 'result' in result: + return self._parseArtists(result) + else: + return [] + + # Search for albums + def getAlbumSearchResults(self, query, limit=ALBUM_LIMIT): + result = self._callRemote('getAlbumSearchResults', {'query' : query,'limit' : limit}) + if 'result' in result: + return self._parseAlbums(result) + else: + return [] + + # Search for songs + def getSongSearchResults(self, query, limit=SONG_LIMIT): + result = self._callRemote('getSongSearchResults', {'query' : query, 'country' : self._country, 'limit' : limit}) + if 'result' in result: + 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('getAlbumSongs', {'albumID' : albumID, 'limit' : limit}) + if 'result' in result: + return self._parseSongs(result) + else: + return [] + + # Get artist's popular songs + def getArtistPopularSongs(self, artistID, limit = SONG_LIMIT): + result = self._callRemote('getArtistPopularSongs', {'artistID' : artistID}) + if 'result' in result: + return self._parseSongs(result, limit) + else: + return [] + + # Gets the popular songs + def getPopularSongsToday(self, limit=SONG_LIMIT): + result = self._callRemote('getPopularSongsToday', {'limit' : limit}) + if 'result' in result: + # Note limit is broken in the Grooveshark getPopularSongsToday method + return self._parseSongs(result, limit) + else: + return [] + + # Gets the favorite songs of the logged-in user + def getUserFavoriteSongs(self): + if (self._userID == 0): + return []; + result = self._callRemote('getUserFavoriteSongs', {}) + if 'result' in result: + return self._parseSongs(result) + else: + return [] + + # Get song info + def getSongsInfo(self, songIDs): + result = self._callRemote('getSongsInfo', {'songIDs' : songIDs}) + if 'result' in result and 'SongID' in result['result']: + info = result['result'] + if 'CoverArtFilename' in info and info['CoverArtFilename'] != None: + info['CoverArtFilename'] = THUMB_URL+info['CoverArtFilename'].encode('ascii', 'ignore') + else: + info['CoverArtFilename'] = 'None' + return info + else: + return 'None' + + # Add song to user favorites + def addUserFavoriteSong(self, songID): + if (self._userID == 0): + return False; + result = self._callRemote('addUserFavoriteSong', {'songID' : songID}) + return result['result']['success'] + + # Remove songs from user favorites + def removeUserFavoriteSongs(self, songIDs): + if (self._userID == 0): + return False; + result = self._callRemote('removeUserFavoriteSongs', {'songIDs' : songIDs}) + return result['result']['success'] + + # Gets the playlists of the logged-in user + def getUserPlaylists(self): + if (self._userID == 0): + return []; + result = self._callRemote('getUserPlaylists', {}) + if 'result' in result: + return self._parsePlaylists(result) + else: + return [] + + # Gets the playlists of the logged-in user + def getUserPlaylistsByUsername(self, username): + userID = self._getUserIDFromUsername(username) + if (userID > 0): + result = self._callRemote('getUserPlaylistsByUserID', {'userID' : userID}) + if 'result' in result and result['result']['playlists'] != None: + playlists = result['result']['playlists'] + return self._parsePlaylists(playlists) + else: + return [] + + # Creates a playlist with songs + def createPlaylist(self, name, songIDs): + result = self._callRemote('createPlaylist', {'name' : name, 'songIDs' : songIDs}) + if 'result' in result and result['result']['success'] == True: + return result['result']['playlistID'] + elif 'errors' in result: + return 0 + + # Sets the songs for a playlist + def setPlaylistSongs(self, playlistID, songIDs): + result = self._callRemote('setPlaylistSongs', {'playlistID' : playlistID, 'songIDs' : songIDs}) + if 'result' in result and result['result']['success'] == True: + return True + else: + return False + + # Gets the songs of a playlist + def getPlaylistSongs(self, playlistID): + result = self._callRemote('getPlaylistSongs', {'playlistID' : playlistID}); + if 'result' in result: + return self._parseSongs(result) + else: + return [] + + + def playlistDelete(self, playlistId): + result = self._callRemote("deletePlaylist", {"playlistID": playlistId}) + if 'fault' in result: + return 0 + else: + return 1 + + def playlistRename(self, playlistId, name): + result = self._callRemote("renamePlaylist", {"playlistID": playlistId, "name": name}) + if 'fault' in result: + return 0 + else: + return 1 + + def getSimilarArtists(self, artistId, limit): + items = self._callRemote("getSimilarArtists", {"artistID": artistId, "limit": limit}) + if 'result' in items: + i = 0 + list = [] + artists = items['result']['artists'] + while(i < len(artists)): + s = artists[i] + list.append([s['artistName'].encode('ascii', 'ignore'),\ + s['artistID']]) + i = i + 1 + return list + else: + return [] + + # After 30s play time + def markStreamKeyOver30Secs(self): + params = { "streamKey" : self._lastStreamKey, "streamServerID" : self._lastStreamServerID } + self._callRemote("markStreamKeyOver30Secs", params) + + # Song complete + def markSongComplete(self, songid): + params = { "songID" : songid, "streamKey" : self._lastStreamKey, "streamServerID" : self._lastStreamServerID } + self._callRemote("markSongComplete", params) + + # Extract song data + def _parseSongs(self, items, limit=0): + if 'result' in items: + i = 0 + list = [] + index = '' + l = -1 + try: + if 'songs' in items['result'][0]: + l = len(items['result'][0]['songs']) + index = 'songs[]' + except: pass + try: + if l < 0 and 'songs' in items['result']: + l = len(items['result']['songs']) + index = 'songs' + except: pass + try: + if l < 0 and 'song' in items['result']: + l = 1 + index = 'song' + except: pass + try: + if l < 0: + l = len(items['result']) + except: pass + + if limit > 0 and l > limit: + l = limit + while(i < l): + if index == 'songs[]': + s = items['result'][0]['songs'][i] + elif index == 'songs': + s = items['result'][index][i] + elif index == 'song': + s = items['result'][index] + else: + s = items['result'][i] + if 'CoverArtFilename' not in s: + info = self.getSongsInfo(s['SongID']) + coverart = info['CoverArtFilename'] + elif s['CoverArtFilename'] != None: + coverart = THUMB_URL+s['CoverArtFilename'].encode('ascii', 'ignore') + else: + coverart = 'None' + list.append([s['SongName'].encode('ascii', 'ignore'),\ + s['SongID'],\ + s['AlbumName'].encode('ascii', 'ignore'),\ + s['AlbumID'],\ + s['ArtistName'].encode('ascii', 'ignore'),\ + s['ArtistID'],\ + coverart]) + i = i + 1 + return list + else: + return [] + + # Extract artist data + def _parseArtists(self, items): + if 'result' in items: + i = 0 + list = [] + artists = items['result']['artists'] + while(i < len(artists)): + s = artists[i] + list.append([s['ArtistName'].encode('ascii', 'ignore'),\ + s['ArtistID']]) + i = i + 1 + return list + else: + return [] + + # Extract album data + def _parseAlbums(self, items, limit=0): + if 'result' in items: + i = 0 + list = [] + 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 = 'None' + list.append([s['ArtistName'].encode('ascii', 'ignore'),\ + s['ArtistID'],\ + s['AlbumName'].encode('ascii', 'ignore'),\ + s['AlbumID'],\ + coverart]) + i = i + 1 + return list + else: + return [] + + def _parsePlaylists(self, items): + i = 0 + list = [] + if 'result' in items: + playlists = items['result']['playlists'] + elif len(items) > 0: + playlists = items + else: + return [] + + while (i < len(playlists)): + s = playlists[i] + list.append([str(s['PlaylistName']).encode('ascii', 'ignore'), s['PlaylistID']]) + i = i + 1 + return list