Giter Site home page Giter Site logo

promyloph / pandora-apidoc Goto Github PK

View Code? Open in Web Editor NEW
48.0 48.0 19.0 77 KB

pandora.com API documentation

Home Page: https://6xq.net/pandora-apidoc/

License: Do What The F*ck You Want To Public License

Makefile 30.25% Python 42.20% Batchfile 27.55%
api-documentation documentation pandora

pandora-apidoc's People

Contributors

anonpenguin avatar firecontroller1847 avatar hacker1024 avatar jcass77 avatar mcrute avatar merionkov avatar nlowe avatar promyloph avatar tingping avatar winny- avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pandora-apidoc's Issues

[REST] Question: How to play ads?

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).

[REST] Logging in with an existing auth token

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?

New parameters to https://www.pandora.com/api/v1/auth/login

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?

JSON API reauthentication

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.

Login types

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.

The 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.

The initial Pandora Android login flow

When the Android app launches for the first time, it does the following:

  1. Authenticate the partner with auth.partnerLogin
  2. Retrieve some UI labels with firstintroduction.v2.startFirstIntroduction
    • This method won't be recognised unless there's a slash before the query string, i.e. .../services/json/?method=....
    • The deviceId is sent in this request, but I don't think this matters due to the next response.
  3. Attempt to log in with the deviceId login type
    • This will always fail with error 1009, which is mapped to a string titled deviceNotFound.
  4. Prompt for the username and password, and then authenticate with the user login type

Reauthentication

When 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.

The issue

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.

conversion to hex after encryption

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.

Extra parameter needed not in documentation?

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.

Partner updates

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

Question: musicToken returned from addSeed/getStation

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?

Note that playlist audio is XOR encrypted

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);
    }
},

Unofficial Pandora API Discord

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! ๐Ÿ‘

Join Here
https://discord.gg/VqzGTV8

Many APIs broken

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...

Request: updates to API docs

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.

Reverse engineering the auth token format

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

Question: How to paginate beyond the 100 limit on station feedback.thumbsup list

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.

Toggle Explicit Content Filter

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!!!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.