X-Git-Url: https://git.hcoop.net/clinton/xbmc-groove.git/blobdiff_plain/8817bb2e053406c493509aff02fc4f91db3143b9..4be4235772b9654af30be73b730cb816ae6af3ce:/resources/lib/GrooveAPI.py diff --git a/resources/lib/GrooveAPI.py b/resources/lib/GrooveAPI.py index f4eb865..ed22a24 100644 --- a/resources/lib/GrooveAPI.py +++ b/resources/lib/GrooveAPI.py @@ -1,4 +1,4 @@ -import urllib2, md5, unicodedata, re, os, traceback, sys, pickle, socket +import urllib2, md5, unicodedata, re, os, traceback, sys, pickle, socket, xbmc from operator import itemgetter, attrgetter class LoginTokensExceededError(Exception): @@ -21,28 +21,25 @@ class SessionIDTryAgainError(Exception): class GrooveAPI: def __init__(self, enableDebug = False, isXbox = False): - if isXbox == True: - import simplejson_xbox - self.simplejson = simplejson_xbox - print 'GrooveShark: Initialized as XBOX script' - else: - import simplejson - self.simplejson = simplejson + import simplejson + self.simplejson = simplejson timeout = 40 socket.setdefaulttimeout(timeout) self.enableDebug = enableDebug self.loggedIn = 0 - self.radioEnabled = 0 self.userId = 0 - self.seedArtists = [] - self.frowns = [] - self.songIDsAlreadySeen = [] - self.recentArtists = [] - self.rootDir = os.getcwd() + self.removeDuplicates = False + + self.radioRecentSongs = [] + self.radioRecentArtists = [] + self.radioEnabled = False + + self.dataDir = 'addon_data' + self.confDir = xbmc.translatePath(os.path.join('special://masterprofile/' + self.dataDir, os.path.basename(os.getcwd()))) self.sessionID = self.getSavedSession() self.debug('Saved sessionID: ' + self.sessionID) - self.sessionID = self.getSessionFromAPI() - self.debug('API sessionID: ' + self.sessionID) + #self.sessionID = self.getSessionFromAPI() + #self.debug('API sessionID: ' + self.sessionID) if self.sessionID == '': self.sessionID = self.startSession() self.debug('Start() sessionID: ' + self.sessionID) @@ -64,10 +61,16 @@ class GrooveAPI: def debug(self, msg): if self.enableDebug == True: print msg + + def setRemoveDuplicates(self, enable): + if enable == True or enable == 'true' or enable == 'True': + self.removeDuplicates = True + else: + self.removeDuplicates = False def getSavedSession(self): sessionID = '' - path = os.path.join(self.rootDir, 'data', 'session.txt') + path = os.path.join(self.confDir, 'session', 'session.txt') try: f = open(path, 'rb') @@ -81,10 +84,10 @@ class GrooveAPI: def saveSession(self): try: - dir = os.path.join(self.rootDir, 'data') + dir = os.path.join(self.confDir, 'session') # Create the 'data' directory if it doesn't exist. if not os.path.exists(dir): - os.mkdir(dir) + os.makedirs(dir) path = os.path.join(dir, 'session.txt') f = open(path, 'wb') pickle.dump(self.sessionID, f, protocol=pickle.HIGHEST_PROTOCOL) @@ -98,10 +101,10 @@ class GrooveAPI: def saveSettings(self): try: - dir = os.path.join(self.rootDir, 'data') + dir = os.path.join(self.confDir, 'data') # Create the 'data' directory if it doesn't exist. if not os.path.exists(dir): - os.mkdir(dir) + os.makedirs(dir) path = os.path.join(dir, 'settings1.txt') f = open(path, 'wb') pickle.dump(self.settings, f, protocol=pickle.HIGHEST_PROTOCOL) @@ -115,14 +118,7 @@ class GrooveAPI: def callRemote(self, method, params={}): data = {'header': {'sessionID': self.sessionID}, 'method': method, 'parameters': params} - #data = {'header': {'sessionID': None}, 'method': method, 'parameters': params} data = self.simplejson.dumps(data) - #proxy_support = urllib2.ProxyHandler({"http" : "http://wwwproxy.kom.aau.dk:3128"}) - ## build a new opener with proxy details - #opener = urllib2.build_opener(proxy_support, urllib2.HTTPHandler) - ## install it - #urllib2.install_opener(opener) - #print data req = urllib2.Request("http://api.grooveshark.com/ws/1.0/?json") req.add_header('Host', 'api.grooveshark.com') req.add_header('Content-type', 'text/json') @@ -135,6 +131,15 @@ class GrooveAPI: result = self.simplejson.loads(result) if 'fault' in result: self.debug(result) + if result['fault']['code'] == 8: #Session ID has expired. Get a new and try again if possible. + self.debug(result['fault']['message']) + self.sessionID = self.startSession() + if self.sessionID != '': + self.saveSession() + return self.callRemote(method, params) + else: + self.debug('GrooveShark: SessionID expired, but unable to get new') + return [] return result except: return [] @@ -147,7 +152,7 @@ class GrooveAPI: if 'fault' in result: return '' else: - return result['header']['sessionID'] + return result['result']['sessionID'] def sessionDestroy(self): return self.callRemote("session.destroy") @@ -210,6 +215,7 @@ class GrooveAPI: else: self.loggedIn = 1 return self.userId + def loginExt(self, username, password): if self.loggedIn == 1: @@ -278,6 +284,16 @@ class GrooveAPI: return 0 else: return 0 + + def playlistCreateUnique(self, name, songIds): + if self.loggedIn == 1: + result = self.callRemote("playlist.createunique", {"name": name, "songIDs": songIds}) + if 'result' in result: + return result['result']['playlistID'] + else: + return 0 + else: + return 0 def playlistGetSongs(self, playlistId, limit=25): result = self.callRemote("playlist.getSongs", {"playlistID": playlistId}) @@ -311,6 +327,16 @@ class GrooveAPI: return 1 else: return 0 + + def playlistDeleteSong(self, playlistId, position): + if self.loggedIn == 1: + result = self.callRemote("playlist.removeSong", {"playlistID": playlistId, "position": position}) + if 'fault' in result: + return 0 + else: + return 1 + else: + return 0 def playlistReplace(self, playlistId, songIds): if self.loggedIn == 1: @@ -322,84 +348,122 @@ class GrooveAPI: else: return 0 - def autoplayStartWithArtistIDs(self, artistIds): - result = self.callRemote("autoplay.startWithArtistIDs", {"artistIDs": artistIds}) - if 'fault' in result: - self.radioEnabled = 0 - return 0 - else: - self.radioEnabled = 1 - return 1 - - def autoplayStart(self, songIds): - result = self.callRemote("autoplay.start", {"songIDs": songIds}) - if 'fault' in result: - self.radioEnabled = 0 - return 0 - else: - self.radioEnabled = 1 - return 1 - - def autoplayStop(self): - result = self.callRemote("autoplay.stop", {}) + def radioStartArtists(self): + radio = self.getSavedRadio() + if radio == None: + return False + result = self.callRemote("autoplay.startWithArtistIDs", {"artistIDs": radio['seedArtists']}) if 'fault' in result: - self.radioEnabled = 1 - return 0 + print "Cannot autoplay artists" + self.radioEnabled = False else: - self.radioEnabled = 0 - return 1 + self.radioEnabled = True + return self.radioEnabled - def autoplayGetNextSongEx(self, seedArtists = [], frowns = [], songIDsAlreadySeen = [], recentArtists = []): - result = self.callRemote("autoplay.getNextSongEx", {"seedArtists": seedArtists, "frowns": frowns, "songIDsAlreadySeen": songIDsAlreadySeen, "recentArtists": recentArtists}) + def radioStartSongs(self): + radio = self.getSavedRadio() + if radio == None: + return False + result = self.callRemote("autoplay.start", {"songIDs": radio['seedSongs']}) if 'fault' in result: - return [] + print "Cannot autoplay songs" + self.radioEnabled = False else: - return result + self.radioEnabled = True + return self.radioEnabled - def radioGetNextSong(self): - if self.seedArtists == []: - return [] + def radioNextSong(self): + radio = self.getSavedRadio() + if radio == None: + return None else: - result = self.autoplayGetNextSongEx(self.seedArtists, self.frowns, self.songIDsAlreadySeen, self.recentArtists) -# print result + result = self.callRemote("autoplay.getNextSongEx", {"seedArtists": radio['seedArtists'], "frowns": radio['frowns'], "songIDsAlreadySeen": self.radioRecentSongs, "recentArtists": self.radioRecentArtists}) if 'fault' in result: return [] else: song = self.parseSongs(result) - self.radioAlreadySeen(song[0][1]) + self.radioRecentSongs.append(song[0][1]) + self.radioRecentArtists.append(song[0][7]) return song - def radioFrown(self, songId): - self.frown.append(songId) - - def radioAlreadySeen(self, songId): - self.songIDsAlreadySeen.append(songId) - - def radioAddArtist(self, artistId): - self.seedArtists.append(artistId) - - def radioStart(self, artists = [], frowns = []): - for artist in artists: - self.seedArtists.append(artist) - for artist in frowns: - self.frowns.append(artist) - if self.autoplayStartWithArtistIDs(self.seedArtists) == 1: - self.radioEnabled = 1 - return 1 + def radioFrown(self, songId = None): + radio = self.getSavedRadio() + if radio != None and songId != None: + try: + radio['frowns'].remove(songId) + except: pass + radio['frowns'].append(songId) + return self.saveRadio(radio = radio) else: - self.radioEnabled = 0 - return 0 - - def radioStop(self): - self.seedArtists = [] - self.frowns = [] - self.songIDsAlreadySeen = [] - self.recentArtists = [] - self.radioEnabled = 0 + return False + + def radioArtist(self, artistId = None): + radio = self.getSavedRadio() + if radio != None and artistId != None: + try: + radio['seedArtists'].remove(artistId) + except: pass + radio['seedArtists'].append(artistId) + print "Saved radio" + return self.saveRadio(radio = radio) + else: + print "Failed to get radio" + return False + + def radioSong(self, songId = None): + radio = self.getSavedRadio() + if radio != None and songId != None: + try: + radio['seedSongs'].remove(songId) + except: pass + radio['seedSongs'].append(songId) + print "Saved radio" + return self.saveRadio(radio = radio) + else: + print "Failed to get radio" + return False def radioTurnedOn(self): return self.radioEnabled + def getSavedRadio(self): + path = os.path.join(self.confDir, 'radio', 'radio.dmp') + try: + f = open(path, 'rb') + radio = pickle.load(f) + f.close() + print radio + except: + print "Failed to open " + path + radio = {} + radio['seedSongs'] = [] + radio['seedArtists'] = [] + radio['frowns'] = [] + if self.saveRadio(radio) == False: + return None + return radio + + def saveRadio(self, radio): #blaher + if radio == {}: + print 'Invalid radio' + return False + try: + dir = os.path.join(self.confDir, 'radio') + # Create the 'data' directory if it doesn't exist. + if not os.path.exists(dir): + os.mkdir(dir) + path = os.path.join(dir, 'radio.dmp') + f = open(path, 'wb') + pickle.dump(radio, f, protocol=pickle.HIGHEST_PROTOCOL) + f.close() + return True + except IOError, e: + print 'There was an error while saving the radio pickle (%s)' % e + return False + except: + print "An unknown error occurred during save radio: " + str(sys.exc_info()[0]) + return False + def favoriteSong(self, songID): return self.callRemote("song.favorite", {"songID": songID}) @@ -452,6 +516,10 @@ class GrooveAPI: list = self.parseAlbums(result) return list + def artistAbout(self, artistId): + result = self.callRemote("artist.about", {"artistID": artistId}) + return result + def artistGetAlbums(self, artistId, limit, sortKey=2): result = self.callRemote("artist.getAlbums", {"artistID": artistId, "limit": limit}) list = self.parseAlbums(result) @@ -473,6 +541,19 @@ class GrooveAPI: list = self.parseSongs(result) return list + def artistGetSimilar(self, artistId, limit): + result = self.callRemote("artist.getSimilar", {"artistID": artistId, "limit": limit}) + list = self.parseArtists(result) + return list + + def songAbout(self, songId): + result = self.callRemote("song.about", {"songID": songId}) + return result['result']['song'] + + def getVersion(self): + result = self.callRemote("service.getVersion", {}) + return result + def parseSongs(self, items): try: if 'result' in items: @@ -502,8 +583,9 @@ class GrooveAPI: songName = s['songName'].encode('ascii', 'ignore') albumName = s['albumName'].encode('ascii', 'ignore') artistName = s['artistName'].encode('ascii', 'ignore') - if (entry[0].lower() == songName.lower()) and (entry[3].lower() == albumName.lower()) and (entry[6].lower() == artistName.lower()): - notIn = False + if self.removeDuplicates == True: + if (entry[0].lower() == songName.lower()) and (entry[3].lower() == albumName.lower()) and (entry[6].lower() == artistName.lower()): + notIn = False if notIn == True: list.append([s['songName'].encode('ascii', 'ignore'),\ s['songID'],\ @@ -529,47 +611,74 @@ class GrooveAPI: return [] 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: + try: + if 'result' in items: + i = 0 + list = [] + artists = items['result']['artists'] + while(i < len(artists)): + s = artists[i] + try: + list.append([s['artistName'].encode('ascii', 'ignore'),\ + s['artistID']]) + except: + print 'GrooveShark: Could not parse album number: ' + str(i) + traceback.print_exc() + i = i + 1 + return list + else: + return [] + except: + print 'GrooveShark: Could not parse artists. Got this:' + traceback.print_exc() return [] def parseAlbums(self, items): - if 'result' in items: - i = 0 - list = [] - albums = items['result']['albums'] - while(i < len(albums)): - s = albums[i] - list.append([s['artistName'].encode('ascii', 'ignore'),\ - s['artistID'],\ - s['albumName'].encode('ascii', 'ignore'),\ - s['albumID'],\ - s['image']['tiny'].encode('ascii', 'ignore')]) - i = i + 1 - return list - else: + try: + if 'result' in items: + i = 0 + list = [] + albums = items['result']['albums'] + while(i < len(albums)): + s = albums[i] + try: # Avoid ascii ancoding errors + list.append([s['artistName'].encode('ascii', 'ignore'),\ + s['artistID'],\ + s['albumName'].encode('ascii', 'ignore'),\ + s['albumID'],\ + s['image']['medium'].encode('ascii', 'ignore')]) + except: + print 'GrooveShark: Could not parse album number: ' + str(i) + traceback.print_exc() + i = i + 1 + return list + else: + return [] + except: + print 'GrooveShark: Could not parse albums. Got this' + traceback.print_exc() return [] def parsePlaylists(self, items): - if 'result' in items: - i = 0 - list = [] - playlists = items['result']['playlists'] - while(i < len(playlists)): - s = playlists[i] - list.append([s['playlistID'],\ - s['playlistName'].encode('ascii', 'ignore'),\ - s['username'].encode('ascii', 'ignore')]) - i = i + 1 - return list - else: + try: + if 'result' in items: + i = 0 + list = [] + playlists = items['result']['playlists'] + while(i < len(playlists)): + s = playlists[i] + try: # Avoid ascii ancoding errors + list.append([s['playlistID'],\ + s['playlistName'].encode('ascii', 'ignore'),\ + s['username'].encode('ascii', 'ignore')]) + except: + print 'GrooveShark: Could not parse playlist number: ' + str(i) + traceback.print_exc() + i = i + 1 + return list + else: + return [] + except: + print 'GrooveShark: Could not parse playlists. Got this:' + print items return []