Skip to content

Commit

Permalink
- Restructuring classes to be more suited for server use
Browse files Browse the repository at this point in the history
- Decoupling user account with general pandora connection
- Modified all getters to require user information
- Fixed test runs
  • Loading branch information
frgorp committed Jun 29, 2012
1 parent 09bb713 commit 3d1a7a9
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 57 deletions.
66 changes: 38 additions & 28 deletions pandora/connection.py
Expand Up @@ -13,9 +13,6 @@ class PandoraConnection(object):
partner_id = None
partner_auth_token = None

user_id = None
user_auth_token = None

time_offset = None

PROTOCOL_VERSION = '5'
Expand All @@ -29,52 +26,60 @@ class PandoraConnection(object):
def __init__(self):
self.rid = "%07i" % (time.time() % 1e7)
self.timedelta = 0
self.authenticate_connection()

def authenticate(self, user, pwd):
def authenticate_connection(self):
try:
# partner login
partner = self.do_request('auth.partnerLogin', True, False, deviceModel=self.DEVICE_MODEL, username=self.PARTNER_USERNAME, password=self.PARTNER_PASSWORD, version=self.PROTOCOL_VERSION)
partner = self.do_request('auth.partnerLogin', True, False, None, deviceModel=self.DEVICE_MODEL, username=self.PARTNER_USERNAME, password=self.PARTNER_PASSWORD, version=self.PROTOCOL_VERSION)
self.partner_id = partner['partnerId']
self.partner_auth_token = partner['partnerAuthToken']

# sync
pandora_time = int(crypt.pandora_decrypt(partner['syncTime'])[4:14])
self.time_offset = pandora_time - time.time()

# user login
user = self.do_request('auth.userLogin', True, True, username=user, password=pwd, loginType="user")
self.user_id = user['userId']
self.user_auth_token = user['userAuthToken']
#
## user login
#user = self.do_request('auth.userLogin', True, True, username=user, password=pwd, loginType="user")
#self.user_id = user['userId']
#self.user_auth_token = user['userAuthToken']

return True
except:
self.partner_id = None
self.partner_auth_token = None
self.user_id = None
self.user_auth_token = None
self.time_offset = None
#self.user_id = None
#self.user_auth_token = None
#self.time_offset = None

return False

def get_user_authentication(self, user, password):
try:
user = self.do_request('auth.userLogin', True, True, None, username = user, password = password, loginType = "user")
return {'userId': user['userId'], 'userAuthToken': user['userAuthToken']}
except:
return None

def get_stations(self, user):
return self.do_request('user.getStationList', False, True, user)['stations']

def get_stations(self):
return self.do_request('user.getStationList', False, True)['stations']

def get_fragment(self, stationId=None, additional_format="mp3"):
songlist = self.do_request('station.getPlaylist', True, True, stationToken=stationId, additionalAudioUrl=self.AUDIO_FORMAT_MAP[additional_format])['items']
def get_fragment(self, user, stationId=None, additional_format="mp3"):
songlist = self.do_request('station.getPlaylist', True, True, user, stationToken=stationId, additionalAudioUrl=self.AUDIO_FORMAT_MAP[additional_format])['items']

self.curStation = stationId
self.curFormat = format

return songlist

def do_request(self, method, secure, crypted, **kwargs):
def do_request(self, method, secure, crypted, user, **kwargs):
url_arg_strings = []
if self.partner_id:
url_arg_strings.append('partner_id=%s' % self.partner_id)
if self.user_id:
url_arg_strings.append('user_id=%s' % self.user_id)
if self.user_auth_token:
url_arg_strings.append('auth_token=%s'%urllib.quote_plus(self.user_auth_token))
if user:
url_arg_strings.append('user_id=%s' % user['userId'])
if user:
url_arg_strings.append('auth_token=%s'%urllib.quote_plus(user['userAuthToken']))
elif self.partner_auth_token:
url_arg_strings.append('auth_token=%s' % urllib.quote_plus(self.partner_auth_token))

Expand All @@ -83,8 +88,8 @@ def do_request(self, method, secure, crypted, **kwargs):

if self.time_offset:
kwargs['syncTime'] = int(time.time()+self.time_offset)
if self.user_auth_token:
kwargs['userAuthToken'] = self.user_auth_token
if user:
kwargs['userAuthToken'] = user['userAuthToken']
elif self.partner_auth_token:
kwargs['partnerAuthToken'] = self.partner_auth_token
data = json.dumps(kwargs)
Expand All @@ -99,6 +104,7 @@ def do_request(self, method, secure, crypted, **kwargs):

# parse result
tree = json.loads(text)
print tree
if tree['stat'] == 'fail':
code = tree['code']
msg = tree['message']
Expand All @@ -122,11 +128,15 @@ def do_request(self, method, secure, crypted, **kwargs):
password = raw_input()

# authenticate
print "Authenthicated: " + str(pandora.authenticate(username, password))
pandora.authenticate_connection
user = pandora.get_user_authentication(username, password)
print "Authenthicated: " + str(user)
if not user:
raise Exception("Not authenticated")

# output stations (without QuickMix)
print "users stations:"
for station in pandora.getStations():
for station in pandora.get_stations(user):
if station['isQuickMix']:
quickmix = station
print "\t" + station['stationName'] + "*"
Expand All @@ -144,4 +154,4 @@ def do_request(self, method, secure, crypted, **kwargs):
#f = open('test.mp3', 'wb')
#f.write(u.read())
#f.close()
#u.close()
#u.close()
50 changes: 21 additions & 29 deletions pandora/pandora.py
Expand Up @@ -3,44 +3,33 @@
from connection import PandoraConnection

class Pandora(object):
station_id = None
authenticated = False
backlog = []

def __init__(self):
self.connection = PandoraConnection()
def __init__(self, connection):
self.connection = connection

def authenticate(self, username, password):
self.authenticated = self.connection.authenticate(username, password)
return self.authenticated
return self.connection.get_user_authentication(username, password)

def get_station_list(self):
return self.connection.get_stations()
def get_station_list(self, user):
return self.connection.get_stations(user)

def switch_station(self, station_id):
if type(station_id) is dict:
station_id = station_id['stationId']

if not self.authenticated: raise ValueError("User not yet authenticated")

def switch_station(self, user, station_id):
self.backlog = []
self.station_id = station_id
self.backlog = self.connection.get_fragment(station_id) + self.backlog
self.backlog = self.connection.get_fragment(user, station_id) + self.backlog

def get_next_song(self):
if not self.authenticated: raise ValueError("User not yet authenticated")
if not self.station_id: raise ValueError("No station selected")

def get_next_song(self, user, stationId):
# get more songs
if len(self.backlog) < 2:
self.backlog = self.connection.get_fragment(self.station_id) + self.backlog
self.backlog = self.connection.get_fragment(user, station_id) + self.backlog

# get next song
return self.backlog.pop()


if __name__ == "__main__":
pandora = Pandora()
connection = PandoraConnection()
pandora = Pandora(connection)

# read username
print "Username: "
Expand All @@ -59,29 +48,32 @@ def get_next_song(self):
urllib2.install_opener(opener)

# authenticate
print "Authenthicated: " + str(pandora.authenticate(username, password))
user = pandora.authenticate(username, password)
print "Authenthicated: " + str(user)

# output stations (without QuickMix)
print "users stations:"
for station in pandora.getStationList():
for station in pandora.get_station_list(user):
if station['isQuickMix']:
quickmix = station
print "\t" + station['stationName'] + "*"
else:
print "\t" + station['stationName']

print "\n\n\n"
quickmix = quickmix['stationId'] if type(quickmix) is dict else quickmix
# switch to quickmix station
pandora.switchStation(quickmix)
pandora.switch_station(user, quickmix)

# get one song from quickmix
print "next song from quickmix:"
next = pandora.getNextSong()
print next['artistName'] + ': ' + next['songName']
print next['audioUrlMap']['highQuality']['audioUrl']
n = pandora.get_next_song(user, quickmix)
print n['artistName'] + ': ' + n['songName']
print n['audioUrlMap']['highQuality']['audioUrl']

# download it
#u = urllib2.urlopen(next['audioUrlMap']['highQuality']['audioUrl'])
#f = open('test.mp3', 'wb')
#f.write(u.read())
#f.close()
#u.close()
#u.close()

0 comments on commit 3d1a7a9

Please sign in to comment.