promyloph / pandora-apidoc Goto Github PK
View Code? Open in Web Editor NEWpandora.com API documentation
Home Page: https://6xq.net/pandora-apidoc/
License: Do What The F*ck You Want To Public License
pandora.com API documentation
Home Page: https://6xq.net/pandora-apidoc/
License: Do What The F*ck You Want To Public License
I've currently got getFragment to work as well as requesting and getting songs to work, but I can't seem to find any way to play ads provided. I've been watching the Pandora website request multiple times to /v1/ad/getAdList, and only once has it responded with adType: "AUDIO_AD". Even then, it didn't provide any helpful URLs other than some XML and the adRequestMetaData
as well as lineId
and creativeId
. I can't provide users with visual ads due to the way I'm building my app, which means I fully rely on audio ads. To do so, I need to know how to do that. Does anyone know how to get an audioURL for ads using the REST api?
Also, oddly enough in my testing of playing about ~1 hour of music on Pandora (the actual website, just listening in the background on a brand new test account), I have yet to hear ONE audio ad, which doesn't help (and no, I don't have an ad blocker enabled. To ensure, I even switched from using Opera to Edge for my testing).
When opening the Pandora Web client, after having signed in already, it seems to log In with a request like the following, with an empty password string and a populated existingAuthToken
field:
POST https://www.pandora.com/api/v1/auth/login
{
"existingAuthToken": "<token>",
"username": "[email protected]",
"password": "",
"keepLoggedIn":true
}
The existing auth token is always the one that was received when logging in previously.
Upon replicating this request, however, I get the standard invalid credential error:
{
"message": "Invalid username and/or password",
"errorCode": 0,
"errorString": "AUTH_INVALID_USERNAME_PASSWORD"
}
Does anyone know what's going on here?
Up until yesterday, both the pandora.com web site and my own code were using the REST API to login with no problem, sending 4 parameters (existingAuthToken, username, password, keepLoggedIn). But now the web site is sending three more parameters named OZ_TC, OZ_DT, OZ_SG. The contents are encoded or encrypted. Without those 3 parameters, my code is now getting back: {"message":"Invalid username and/or password","errorCode":0,"errorString":"AUTH_INVALID_USERNAME_PASSWORD"}
Anyone know what those parameters are?
The official Android app can reauthenticate without storing the username and password, but I'm unable to do so myself.
It's be great if we could work this out, and add it to the documentation.
Below are my findings after exploring the login system.
There are four loginType
values that can be used with auth.userLogin
: user
, deviceId
, accessToken
, and firstIntroToken
.
user
logs in with a username and password. An example request, with all the common user response parameters removed, looks like this:
{
"username": "<username>",
"password": "<password>",
"appSignature": "0735356f37ee31a95dcbe016fcc8c5b2a6a4ac93",
"loginType": "user"
}
This login type is used by the Pandora Android app when a user first logs in, but not for subsequent logins.
To reauthenticate expired sessions, and log in from storage, the app uses the deviceId
type, which looks like this:
{
"loginType": "deviceId"
}
As you can see, no loginType-specific user-specific information is required with this login type. Instead, the backend uses the deviceId
value sent in every type of login request to authenticate the user.
deviceId
The deviceId
used is generated with UUID.randomUUID()
and stored upon first access. The same value is then used for all relevant API requests.
When the Android app launches for the first time, it does the following:
auth.partnerLogin
firstintroduction.v2.startFirstIntroduction
.../services/json/?method=...
.deviceId
is sent in this request, but I don't think this matters due to the next response.deviceId
login type
deviceNotFound
.user
login typeWhen an authentication token expires, subsequent API requests will fail with error 1001 (invalidAuthToken
). When this happens, the official Android app will reauthenticate with the deviceId
login type.
Additionally, the deviceId
login type is used on startup when the user is signed in. The username and password aren't stored.
When I try to reauthenticate with the deviceId
login type, it always fails with an error 1009 - even after I log in with user
and provide the same deviceId
.
It looks like the Android app is somehow registering the device with Pandora, so reauthentication can be done. This must be happening somewhere in between step 3 of the login flow and reauthentication, but I can't work out how it works.
As in topic. Tested in PAW.
I have had some trouble posting with uppercase letter hex. These issues went away when i saw all incoming in was lowercase hex. I switched mine to always send lowercase hex and the errors went poof. I think this should be documented as hex strings are supposed to be uppercase.
When using method auth.userLogin I am getting an error code 4 URL_PARAM_MISSING_PARTNER_ID. The documentation says that you only need 5 parameters, the method name, the login type, username, password, and partnerAuthToken. But when I send
{ "loginType" : "user", "username" : "uname", "password" : "passwd", "partnerAuthToken" : "token"}
to http://tuner.pandora.com/services/json/?method=auth.userLogin it still says I am missing a parameter.
I've tried to send to http://tuner.pandora.com/services/json/?method=auth.userLogin&partnerId=id as well but this also fails.
At some point, the android app seems to have switched to android-tuner.pandora.com
, though the old subdomain still works. Everything else remains the same.
Additionally, I have extracted the following partner details from version 8.7.1 of the Android app. Perhaps they can be added to the documentation for the sake of completeness? It still works. I tried making a PR, but I can't seem to get the RST tables to play nicely with my additions.
Username | android-gtv |
Password | ^bs2*tzZAM47tvmAvV1GZS^TH1SBW?8o |
Device ID | gtv2-foster |
Encrypt key | MCf5Ljj*V?Fr4cF4 |
Decrypt key | 2lSj00N1fKYfOk8x |
I noticed that music.addSeed
/ station.getStation
in the Stations API return a hex-encrypted musicToken
:
{
"stat": "ok",
"result": {
"artistName": "Foo Fighters",
"musicToken": "3bcf3f314419f974",
"seedId": "2123197691273031149",
"artUrl": "http://cont-dc6-1.pandora.com/images/public/amg/portrait/pic200/drP900/P972/P97242B3S6P.jpg"
}
}
This doesn't seem to be the same musicToken
as the one returned from music.search
, i.e. when you try to use it toe create a new station you get an error. I tried decrypting it with the passwords from Partner passwords, but it looks like it's returning mostly junk bytes.
Any idea what this could be/how to decrypt it?
I'm unsure as to why I would be continually receiving a fail response on user authentication with the error code 3.
I don't have time to write this up properly now, but I will later. Making this issue to record my findings in the meantime, as this isn't documented.
Pandora playlist audio is encrypted with a base64 encoded string, assigned to the key
key in the response JSON.
Audio can be decrypted for testing using this tool.
For reference, Pandora's implementation in their web app can be found in the Javascript code for the Sirius XM music player, at webpack:///src/domains/playback/audio/libs/AudioPlayback/harnesses/SXMHarness/SXMAudioPlayer.js
in the browser debugger.
Specifically, this code snippet revealed the secrets:
startLoading: function (url, key) {
this._url = url;
this._load = new ProgressiveDownload(url);
//TODO : IF we have key initiate the XORCipher to decrypt the buffer data usign the key
if(key)
{
this.key = key;
this._cipher = new XORCipher(Cipher.ALGORITHM.XOR_MASK, ["decrypt"]);
this._cipher.importKey(key);
}
},
Hello! ๐
๐ I'm going around all of the Pandora Libraries's as well as their products, and telling users about a Discord server I've been making to allow us all to communicate easily and quickly. All library creators will be given their own role and their own support channel to (optionally) help users. All product creators will be given their own role, and their own support channels as well. Please join! We're looking to get as many Unofficial Pandora API dev's to come together, and allow for easy communication.
๐ Some more info about me: A simple Discord user. I'm looking to create Node.js API, but noticed there was no way to contact anyone nor a simple community behind it that I could talk to, so I've made this guild to try to make the community visible as one giant group.
๐ We think you'd be an awesome addition to the community, please, join! Let's bring this Unofficial API all into one place for easy support and documentation, as well as product listings and library listings. Hope to see you there! ๐
It looks like a ton of APIs just changed or broke. None of the JSON-based clients I used seem to be able to log in (I was using one as this happened, and it failed to fetch the playlist, so looks like that's broken also).
My own REST-based app can't load the station list anymore (looks like getShuffle
, is just, gone, as well as other things changing).
Hopefully, things have just changed and we won't lose any functionality long-term. I hope this isn't a sign that the Pandora devs have finally learnt to build secure APIs...
It will act as if includeExtendedAttributes
is false.
It's not possible to get the feedback ID in this way anymore.
I was just wondering if this was just a typo or if the correct codes where not known?
I had a look at the ads branch of pianobar for examples of how to implement ad-handling support in pydora and Mopidy-Pandora.
It's working fairly well and I was wondering if you have any other insights that are not reflected in the API documentation yet?
PromyLOPh/pianobar@fbfc5f1 lists a bunch of additional parameters to the JSON calls that I have not heard of before, and don't know how to use.
Examples include includeAdvertiserAttributes
, xplatformAdCapable
, includeShuffleInsteadOfQuickMix
, and includeCompletePlaylist
, among others.
I'm trying this, and I've tried various other usernames and passwords as well, but they all end in Code: 9. I can't figure out what value I'm missing, I have EVERYTHING listed in the docs.
It has come to my attention that the REST API authentication token is actually base64 encoded data.
When a token expires, Pandora sends the following message back, implying that the token stores some sort of state.
ListenerState in auth token does not match state in radio db
It's possible that this token may include useful information like when the token will expire. I intend to look into this further, and I'll document any findings here before collating anything meaningful into a page in a PR.
An example (expired) authentication token:
BIQ3pFmHssCsDO8nEYuyojSfYKUus0LpEOsueZ3Zk0vQtUNfywnxI4cA==
04 84 37 a4 59 87 b2 c0 ac 0c ef 27 11 8b b2 a2
34 9f 60 a5 2e b3 42 e9 10 eb 2e 79 9d d9 93 4b
d0 b5 43 5f cb 09 f1 23 87 00
This is not supported by the current library, but I patched the models just to return the dict of feedback as per documentation https://6xq.net/pandora-apidoc/json/stations/
so I can do:
from pandora import clientbuilder
p = clientbuilder.PydoraConfigFileBuilder()
client = p.build()
s = client.get_station('1316180904578479950')
so I can get the songs if I iterate through, single example
s.feedback['thumbsUp'][0]['songName']
u'Stray Cat Strut'
my issue is that I can not get them all
len(s.feedback['thumbsUp'])
100
s.feedback['totalThumbsUp']
132
I cross checked my results with node implementation https://www.npmjs.com/package/anesidora
and the results are the same so its an API limit.
There must be a way to paginate and get a list of the remaining 32 items (and several hundreds on other stations where the likes are 300+ total)
Any suggestions? I probably need to reverse engineer the UI traffic otherwise.
The Explicit Content Filter can be toggled with:
Method:
user.setExplicitContentFilter
arg:
isExplicitContentFilterEnabled : boolean
It returns nothing and has no effect if the Explicit Content Filter is PIN Protected. The state of the filter and PIN protection can ofc be checked with user.getSettings. It doesn't take effect until the next playlist.(i.e. any prior uncensored playlist does not magically become censored and vice-versa)
I added the feature to Pithos a while ago.
pithos/pithos@50aa536
I'd do a direct pull request for this but I barely know what I'm doing on git/github,lol!!!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.