-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 <http://www.gnu.org/licenses/>.
+
+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
_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 ''
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'
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:
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:
# 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:
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
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:
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 []
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 []
def _parseAlbums(self, items, limit=0):
if 'result' in items:
i = 0
- list = []
+ itemList = []
try:
albums = items['result']['albums']
except:
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:
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