X-Git-Url: https://git.hcoop.net/clinton/xbmc-groove.git/blobdiff_plain/f95afae7836df7119990caf9bf2285a18eba8b18..72f3ef3c3b2e66d20ba0440057ca96a7e30e4c29:/resources/lib/GroovesharkAPI.py diff --git a/resources/lib/GroovesharkAPI.py b/resources/lib/GroovesharkAPI.py index 2f8f340..9b8feda 100644 --- a/resources/lib/GroovesharkAPI.py +++ b/resources/lib/GroovesharkAPI.py @@ -1,7 +1,28 @@ -import socket, hmac, urllib2, pprint, md5, os, pickle, tempfile, time, re, groovesharkAccess +# Copyright 2011 Stephen Denham + +# This file is part of xbmc-groove. +# +# xbmc-groove is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# xbmc-groove is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with xbmc-groove. If not, see . + +import urllib2, pprint, md5, os, pickle, tempfile, time, re, simplejson, base64, sys, socket +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 @@ -17,42 +38,92 @@ class GrooveAPI: _sessionID = '' _userID = 0 _lastSessionTime = 0 - _lastStreamKey = '' - _lastStreamServerID = '' + _key = md5.new(os.path.basename("GroovesharkAPI.py")).hexdigest() + _debugging = False # Constructor - def __init__(self): + def __init__(self, debug): - import simplejson + self._debugging = debug self.simplejson = simplejson - socket.setdefaulttimeout(40) + if "linux" in sys.platform.lower(): + socket.setdefaulttimeout(30) + self.cacheDir = os.path.join(tempfile.gettempdir(), 'groovesharkapi') if os.path.isdir(self.cacheDir) == False: os.makedirs(self.cacheDir) - print "Made " + self.cacheDir + if self._debugging: + 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() - self._ip = self._getIP() - self._country = self._getCountry() if self._sessionID == '': raise StandardError('Failed to get session id') else: - print "New GrooveAPI session id: " + self._sessionID + if self._debugging: + 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): - self._setParams(params) - return groovesharkAccess.callRemote(method, self._sessionID) + 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() + if self._debugging: + 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() + if self._debugging: + 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) - self._lastSessionTime = time.time() if 'result' in result: + self._lastSessionTime = time.time() return result['result']['sessionID'] else: return '' @@ -89,26 +160,14 @@ class GrooveAPI: 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() + myip = urllib2.urlopen('http://ipecho.net/plain').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 + if self._debugging: + print "IP is " + myip return myip except: return '0.0.0.0' @@ -133,7 +192,10 @@ class GrooveAPI: params = {'login': login, 'password': md5pwd} result = self._callRemote('authenticate', params) - uid = result['result']['UserID'] + try: + uid = result['result']['UserID'] + except: + uid = 0 if (uid > 0): return uid else: @@ -172,8 +234,6 @@ class GrooveAPI: 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: @@ -205,7 +265,7 @@ class GrooveAPI: # Get artists albums def getArtistAlbums(self, artistID, limit=ALBUM_LIMIT): - result = self._callRemote('getArtistAlbums', {'artistID' : artistID}) + result = self._callRemote('getArtistVerifiedAlbums', {'artistID' : artistID}) if 'result' in result: return self._parseAlbums(result, limit) else: @@ -252,7 +312,7 @@ class GrooveAPI: 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') + info['CoverArtFilename'] = THUMB_URL+info['CoverArtFilename'].encode('utf8', 'ignore') else: info['CoverArtFilename'] = 'None' return info @@ -337,32 +397,53 @@ class GrooveAPI: items = self._callRemote("getSimilarArtists", {"artistID": artistId, "limit": limit}) if 'result' in items: i = 0 - list = [] + itemList = [] artists = items['result']['artists'] while(i < len(artists)): s = artists[i] - list.append([s['artistName'].encode('ascii', 'ignore'),\ + itemList.append([s['artistName'].encode('utf8', 'ignore'),\ s['artistID']]) i = i + 1 - return list + return itemList else: return [] + def getDoesArtistExist(self, artistId): + response = self._callRemote("getDoesArtistExist", {"artistID": artistId}) + if 'result' in response and response['result'] == True: + return True + else: + return False + + def getDoesAlbumExist(self, albumId): + response = self._callRemote("getDoesAlbumExist", {"albumID": albumId}) + if 'result' in response and response['result'] == True: + return True + else: + return False + + def getDoesSongExist(self, songId): + response = self._callRemote("getDoesSongExist", {"songID": songId}) + if 'result' in response and response['result'] == True: + return True + else: + return False + # After 30s play time - def markStreamKeyOver30Secs(self): - params = { "streamKey" : self._lastStreamKey, "streamServerID" : self._lastStreamServerID } + def markStreamKeyOver30Secs(self, streamKey, streamServerID): + params = { "streamKey" : streamKey, "streamServerID" : streamServerID } self._callRemote("markStreamKeyOver30Secs", params) # Song complete - def markSongComplete(self, songid): - params = { "songID" : songid, "streamKey" : self._lastStreamKey, "streamServerID" : self._lastStreamServerID } + def markSongComplete(self, songid, streamKey, streamServerID): + params = { "songID" : songid, "streamKey" : streamKey, "streamServerID" : streamServerID } self._callRemote("markSongComplete", params) - + # Extract song data def _parseSongs(self, items, limit=0): if 'result' in items: i = 0 - list = [] + itemList = [] index = '' l = -1 try: @@ -400,18 +481,26 @@ class GrooveAPI: info = self.getSongsInfo(s['SongID']) coverart = info['CoverArtFilename'] elif s['CoverArtFilename'] != None: - coverart = THUMB_URL+s['CoverArtFilename'].encode('ascii', 'ignore') + coverart = THUMB_URL+s['CoverArtFilename'].encode('utf8', 'ignore') else: coverart = 'None' - list.append([s['SongName'].encode('ascii', 'ignore'),\ + if 'Name' in s: + name = s['Name'] + else: + name = s['SongName'] + if 'AlbumName' in s: + albumName = s['AlbumName'] + else: + albumName = "" + itemList.append([name.encode('utf8', 'ignore'),\ s['SongID'],\ - s['AlbumName'].encode('ascii', 'ignore'),\ + albumName.encode('utf8', 'ignore'),\ s['AlbumID'],\ - s['ArtistName'].encode('ascii', 'ignore'),\ + s['ArtistName'].encode('utf8', 'ignore'),\ s['ArtistID'],\ coverart]) i = i + 1 - return list + return itemList else: return [] @@ -419,14 +508,14 @@ class GrooveAPI: def _parseArtists(self, items): if 'result' in items: i = 0 - list = [] + itemList = [] artists = items['result']['artists'] while(i < len(artists)): s = artists[i] - list.append([s['ArtistName'].encode('ascii', 'ignore'),\ + itemList.append([s['ArtistName'].encode('utf8', 'ignore'),\ s['ArtistID']]) i = i + 1 - return list + return itemList else: return [] @@ -434,7 +523,7 @@ class GrooveAPI: def _parseAlbums(self, items, limit=0): if 'result' in items: i = 0 - list = [] + itemList = [] try: albums = items['result']['albums'] except: @@ -445,23 +534,27 @@ class GrooveAPI: l = limit while(i < l): s = albums[i] + if 'Name' in s: + name = s['Name'].encode('utf8', 'ignore') + else: + name = s['AlbumName'].encode('utf8', 'ignore') if 'CoverArtFilename' in s and s['CoverArtFilename'] != None: - coverart = THUMB_URL+s['CoverArtFilename'].encode('ascii', 'ignore') + coverart = THUMB_URL+s['CoverArtFilename'].encode('utf8', 'ignore') else: coverart = 'None' - list.append([s['ArtistName'].encode('ascii', 'ignore'),\ + itemList.append([s['ArtistName'].encode('utf8', 'ignore'),\ s['ArtistID'],\ - s['AlbumName'].encode('ascii', 'ignore'),\ + name,\ s['AlbumID'],\ coverart]) i = i + 1 - return list + return itemList else: return [] def _parsePlaylists(self, items): i = 0 - list = [] + itemList = [] if 'result' in items: playlists = items['result']['playlists'] elif len(items) > 0: @@ -471,37 +564,6 @@ class GrooveAPI: while (i < len(playlists)): s = playlists[i] - list.append([str(s['PlaylistName']).encode('ascii', 'ignore'), s['PlaylistID']]) + itemList.append([unicode(s['PlaylistName']).encode('utf8', 'ignore'), s['PlaylistID']]) i = i + 1 - return list - -# Test -#import sys -#res = [] -#groovesharkApi = GrooveAPI() -#res = groovesharkApi.pingService() -#res = groovesharkApi.login(sys.argv[1], sys.argv[2]) -#songIds = [] -#songIds.append('28645456') -#songIds.append('26579347') -#res=groovesharkApi.playlistRename(58197714, 'renamed playlist2') -#res = groovesharkApi.createPlaylist("Test", songIDs) -#res = groovesharkApi.setPlaylistSongs('58197714',songIds) -#pprint.pprint(res) -#res = groovesharkApi.getPlaylistSongs('58197714') -#res = groovesharkApi.getSongSearchResults('jimmy jazz', 3) -#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() -#res = groovesharkApi.getSongInfos('27425375') -#res = groovesharkApi.getPlaylistSongs(40902662) -#res = groovesharkApi.addUserFavoriteSong('27425375') -#res = groovesharkApi.logout() -#res = groovesharkApi.getUserPlaylistsByUsername('stephendenham') -#res = groovesharkApi.getArtistPopularSongs('3707') -# -#pprint.pprint(res) + return itemList