From 943c1b50abf1585744963b0eb3478b5e18141656 Mon Sep 17 00:00:00 2001 From: Lars-Dominik Braun Date: Thu, 3 Jul 2014 18:52:48 +0200 Subject: Initial import --- json/authentication.rst | 179 ++++++++++++++++++++++++++++++ json/bookmarks.rst | 157 ++++++++++++++++++++++++++ json/errorcodes.rst | 54 +++++++++ json/index.rst | 79 +++++++++++++ json/methods.rst | 42 +++++++ json/partners.rst | 71 ++++++++++++ json/play.rst | 209 ++++++++++++++++++++++++++++++++++ json/stations.rst | 289 ++++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 1080 insertions(+) create mode 100644 json/authentication.rst create mode 100644 json/bookmarks.rst create mode 100644 json/errorcodes.rst create mode 100644 json/index.rst create mode 100644 json/methods.rst create mode 100644 json/partners.rst create mode 100644 json/play.rst create mode 100644 json/stations.rst (limited to 'json') diff --git a/json/authentication.rst b/json/authentication.rst new file mode 100644 index 0000000..67f5879 --- /dev/null +++ b/json/authentication.rst @@ -0,0 +1,179 @@ +.. _authentication: + +Authentication +============== + +Authentication is divided into two steps: Partner and user login. + +.. _auth-partnerLogin: + +Partner login +------------- + +:Method: auth.partnerLogin + +This request additionally serves as API version validation, time +synchronization and endpoint detection and *must* be sent over a TLS-encrypted +link. The POST body however is :ref:`not encrypted `. + +.. csv-table:: + :header: Name,Type,Description + + username,string,See :ref:`partners` + password,string,See :ref:`partners` + deviceModel,string,See :ref:`partners` + version,string,"Current version number, “5”." + includeUrls,boolean, + returnDeviceType,boolean, + returnUpdatePromptVersions,boolean, + +.. code:: json + + { + "username": "pandora one", + "password": "TVCKIBGS9AO9TSYLNNFUML0743LH82D", + "deviceModel": "D01", + "version": "5" + } + +syncTime is used to calculate the server time, see :ref:`synctime`. partnerId +and authToken are required to procceed with user authentication. + +================ ======= =========== +Name Type Description +================ ======= =========== +syncTime string Hex-encoded, encrypted server time. Decrypt with password from :ref:`partners` and skip first four bytes of garbage. +partnerAuthToken string +partnerId string +================ ======= =========== + +.. code:: json + + { + "stat": "ok", + "result": { + "syncTime": "6923e263a8c3ac690646146b50065f43", + "deviceProperties": { + "videoAdRefreshInterval": 900, + "videoAdUniqueInterval": 0, + "adRefreshInterval": 5, + "videoAdStartInterval": 180 + }, + "partnerAuthToken": "VAzrFQTtsy3BQ3K+3iqFi0WF5HA63B1nFA", + "partnerId": "42", + "stationSkipUnit": "hour", + "urls": { + "autoComplete": "http://autocomplete.pandora.com/search" + }, + "stationSkipLimit": 6 + } + } + +==== ============ +Code Description +==== ============ +1002 INVALID_PARTNER_LOGIN. Invalid partner credentials. +==== ============ + +.. _auth-userLogin: + +User login +---------- + +:Method: auth.userLogin + +This request *must* be sent over a TLS-encrypted link. It authenticates the +Pandora user by sending his username, usually his email address, and password +as well as the partnerAuthToken obtained by :ref:`auth-partnerLogin`. + +.. TODO: Describe device login. + +Additional response data can be requested by setting flags listed below. + +.. csv-table:: + :header: Name,Type,Description + + loginType ,string ,“user” + username ,string ,Username + password ,string ,User’s password + partnerAuthToken ,string ,Partner token obtained by :ref:`auth-partnerLogin` + returnGenreStations ,boolean ,(optional) + returnCapped ,boolean ,return isCapped parameter (optional) + includePandoraOneInfo,boolean,(optional) + includeDemographics,boolean,(optional) + includeAdAttributes,boolean,(optional) + returnStationList,boolean,"Return station list, see :ref:`user-getStationList` (optional)" + includeStationArtUrl,boolean,(optional) + includeStationSeeds,boolean,(optional) + includeShuffleInsteadOfQuickMix,boolean,(optional) + stationArtSize,string,W130H130(optional) + returnCollectTrackLifetimeStats,boolean,(optional) + returnIsSubscriber,boolean,(optional) + xplatformAdCapable,boolean,(optional) + complimentarySponsorSupported,boolean,(optional) + includeSubscriptionExpiration,boolean,(optional) + returnHasUsedTrial,boolean,(optional) + returnUserstate,boolean,(optional) + includeAccountMessage,boolean,(optional) + includeUserWebname,boolean,(optional) + includeListeningHours,boolean,(optional) + includeFacebook,boolean,(optional) + includeTwitter,boolean,(optional) + includeDailySkipLimit,boolean,(optional) + includeSkipDelay,boolean,(optional) + includeGoogleplay,boolean,(optional) + includeShowUserRecommendations,boolean,(optional) + includeAdvertiserAttributes,boolean,(optional) + + +.. code:: json + + { + "loginType": "user", + "username": "user@example.com", + "password": "example", + "partnerAuthToken": "VAzrFQTtsy3BQ3K+3iqFi0WF5HA63B1nFA", + "includePandoraOneInfo":true, + "includeAdAttributes":true, + "includeSubscriptionExpiration":true, + "includeStationArtUrl":true, + "returnStationList":true, + "returnGenreStations":true, + "syncTime": 1335777573 + } + +The returned userAuthToken is used to authenticate access to other API methods. + +.. csv-table:: + :header: Name ,Type ,Description + + isCapped ,boolean , + userAuthToken,string, + +.. code:: json + + { + "stat": "ok", + "result": { + "stationCreationAdUrl": "http://ad.doubleclick.net/adx/pand.android/prod.createstation;ag=112;gnd=1;zip=23950;genre=0;model=;app=;OS=;dma=560;clean=0;logon=__LOGON__;tile=1;msa=115;st=VA;co=51117;et=0;mc=0;aa=0;hisp=0;hhi=0;u=l*2jedvn446s7ce!ag*112!gnd*1!zip*23950!dma*560!clean*0!logon*__LOGON__!msa*115!st*VA!co*51117!et*0!mc*0!aa*0!hisp*0!hhi*0!genre*0;sz=320x50;ord=__CACHEBUST__", + "hasAudioAds": true, + "splashScreenAdUrl": "http://ad.doubleclick.net/pfadx/pand.android/prod.welcome;ag=112;gnd=1;zip=23950;model=;app=;OS=;dma=560;clean=0;hours=1;msa=115;st=VA;co=51117;et=0;mc=0;aa=0;hisp=0;hhi=0;u=l*op4jfgdxmddjk!ag*112!gnd*1!zip*23950!dma*560!clean*0!msa*115!st*VA!co*51117!et*0!mc*0!aa*0!hisp*0!hhi*0!hours*1;sz=320x50;ord=__CACHEBUST__", + "videoAdUrl": "http://ad.doubleclick.net/pfadx/pand.android/prod.nowplaying;ag=112;gnd=1;zip=23950;dma=560;clean=0;hours=1;app=;index=__INDEX__;msa=115;st=VA;co=51117;et=0;mc=0;aa=0;hisp=0;hhi=0;u=l*2jedvn446s7ce!ag*112!gnd*1!zip*23950!dma*560!clean*0!index*__INDEX__!msa*115!st*VA!co*51117!et*0!mc*0!aa*0!hisp*0!hhi*0!hours*1;sz=442x188;ord=__CACHEBUST__", + "username": "user@example.com", + "canListen": true, + "nowPlayingAdUrl": "http://ad.doubleclick.net/pfadx/pand.android/prod.nowplaying;ag=112;gnd=1;zip=23950;genre=0;station={4};model=;app=;OS=;dma=560;clean=0;hours=1;artist=;interaction=__INTERACTION__;index=__INDEX__;newUser=__AFTERREG__;logon=__LOGON__;msa=115;st=VA;co=51117;et=0;mc=0;aa=0;hisp=0;hhi=0;u=l*op4jfgdxmddjk!ag*112!gnd*1!zip*23950!station*{4}!dma*560!clean*0!index*__INDEX__!newUser*__AFTERREG__!logon*__LOGON__!msa*115!st*VA!co*51117!et*0!mc*0!aa*0!hisp*0!hhi*0!genre*0!interaction*__INTERACTION__!hours*1;sz=320x50;ord=__CACHEBUST__", + "userId": "272772589", + "listeningTimeoutMinutes": "180", + "maxStationsAllowed": 100, + "listeningTimeoutAlertMsgUri": "/mobile/still_listening.vm", + "userProfileUrl": "https://www.pandora.com/login?auth_token=XXX&target=%2Fpeople%2FXXX", + "minimumAdRefreshInterval": 5, + "userAuthToken": "XXX" + } + } + +.. csv-table:: + :header: Code ,Description + + 1002,Wrong user credentials. + diff --git a/json/bookmarks.rst b/json/bookmarks.rst new file mode 100644 index 0000000..1d826bb --- /dev/null +++ b/json/bookmarks.rst @@ -0,0 +1,157 @@ +Bookmarks +========= + +Users can bookmark artists or songs. + +.. _user.getBookmarks: + +Retrieve bookmarks +------------------ + +:Method: user.getBookmarks + +The request has no parameters. + +.. code:: json + + { + "stat":"ok", + "result": { + "artists": [ + { + "musicToken": "R130360", + "artistName": "Cannabich, Christian", + "artUrl": "http://cont-sv5-2.pandora.com/images/public/amz/5/2/9/7/095115137925_500W_488H.jpg", + "bookmarkToken": "80982345262345234", + "dateCreated": { + "nanos": 300000000, + "seconds": 22, + "year": 112, + "month": 4, + "hours": 11, + "time": 1350566223422, + "date": 23, + "minutes": 01, + "day": 2, + "timezoneOffset": 720 + } + } + ], + "songs": [ + { + "sampleUrl": "http://www.pandora.com/favorites/getSample.jsp?token=32458973245b90287345d0234fc34f8b&allowExplicit=true", + "sampleGain": "-7.87", + "albumName": "Symphony In G Major", + "artistName": "Cannabich, Christian", + "musicToken": "S2894329", + "dateCreated": { + "nanos": 300000000, + "seconds": 22, + "year": 112, + "month": 4, + "hours": 11, + "time": 1350566223422, + "date": 23, + "minutes": 01, + "day": 2, + "timezoneOffset": 720 + }, + "artUrl": "http://cont-sv5-2.pandora.com/images/public/amz/5/2/9/7/095115137925_500W_488H.jpg", + "bookmarkToken": "290832123432459854", + "songName": "London Mozart Players, Christian Cannabich: Symphonies" + } + ] + } + + } + +.. _bookmark.addArtistBookmark: + +Add artist bookmark +------------------- + +:Method: bookmark.addArtistBookmark + +.. csv-table:: + :header: Name ,Type ,Description + + trackToken,string, + +.. code:: json + + { + "trackToken": "f17ff6c86c11743fc890808e1a1dd6ff5b1dca1a2e260f7d998ba6e7786dd9941c5dd4b345a1008e86862353da1e6cdc78172b4199240c76", + "userAuthToken": "XXX", + "syncTime": 1338210690 + } + +.. code:: json + + { + "stat": "ok", + "result": { + "artistName": "Wallis Bird", + "dateCreated": { + "date": 2, + "day": 3, + "hours": 7, + "minutes": 6, + "month": 6, + "seconds": 13, + "time": 1404309973468, + "timezoneOffset": 420, + "year": 114 + }, + "bookmarkToken": "49854851068341741", + "artUrl": "http://cont-dc6-2.pandora.com/images/public/amg/portrait/pic200/drP900/P998/P99805K1QKS.jpg", + "musicToken": "R278544" + } + } + +.. _bookmark.addSongBookmark: + +Add song bookmark +----------------- + +:Method: bookmark.addSongBookmark + +.. csv-table:: + :header: Name ,Type ,Description + + trackToken ,string , + +.. code:: json + + { + "trackToken": "f17ff6c86c11743fc890808e1a1dd6ff5b1dca1a2e260f7d998ba6e7786dd9941c5dd4b345a1008e86862353da1e6cdc78172b4199240c76", + "userAuthToken": "XXX", + "syncTime": 1338210690 + } + +.. code:: json + + { + "stat": "ok", + "result": { + "sampleGain": "1.96", + "musicToken": "S1143982", + "bookmarkToken": "200207779061968365", + "sampleUrl": "http://www.pandora.com/favorites/getSample.jsp?token=a74b4f7551e3e174425ba2910f7abf8b&allowExplicit=true", + "albumName": "The 5th Exotic", + "songName": "The 5th Exotic", + "artUrl": "http://cont-sjl-1.pandora.com/images/public/amz/9/4/5/2/800002549_500W_500H.jpg", + "dateCreated": { + "date": 28, + "day": 1, + "hours": 6, + "minutes": 11, + "month": 4, + "seconds": 31, + "time": 1338210691404, + "timezoneOffset": 420, + "year": 112 + }, + "artistName": "Quantic" + } + } + diff --git a/json/errorcodes.rst b/json/errorcodes.rst new file mode 100644 index 0000000..edd14bd --- /dev/null +++ b/json/errorcodes.rst @@ -0,0 +1,54 @@ +List of error codes +=================== + +These error codes can be returned by all methods: + +==== ============ +Code Description +==== ============ +0 Internal error. It can denote that your account has been temporarily blocked due to having too frequent station.getPlaylist calls. +1 MAINTENANCE_MODE +2 URL_PARAM_MISSING_METHOD +3 URL_PARAM_MISSING_AUTH_TOKEN +4 URL_PARAM_MISSING_PARTNER_ID +5 URL_PARAM_MISSING_USER_ID +6 SECURE_PROTOCOL_REQUIRED +7 CERTIFICATE_REQUIRED +8 PARAMETER_TYPE_MISMATCH +9 PARAMETER_MISSING +10 PARAMETER_VALUE_INVALID +11 API_VERSION_NOT_SUPPORTED +12 LICENSING_RESTRICTIONS. Pandora not available in this country. +13 INSUFFICIENT_CONNECTIVITY. Bad sync time? +14 Unknown method name? +15 Wrong protocol (http/https)? +1000 READ_ONLY_MODE +1001 INVALID_AUTH_TOKEN. Occurs once a user auth token expires. +1002 INVALID_PARTNER_LOGIN. auth.partnerLogin auth.userLogin. Can also occur for a user login. +1003 LISTENER_NOT_AUTHORIZED station.getPlaylist Pandora One Subscription or Trial Expired. Possibly account suspended? +1004 USER_NOT_AUTHORIZED User not authorized to perform action +1005 MAX_STATIONS_REACHED Station limit reached +1006 STATION_DOES_NOT_EXIST Station does not exist +1007 COMPLIMENTARY_PERIOD_ALREADY_IN_USE +1008 CALL_NOT_ALLOWED station.addFeedback Returned when attempting to add feedback to shared station +1009 DEVICE_NOT_FOUND +1010 PARTNER_NOT_AUTHORIZED +1011 INVALID_USERNAME +1012 INVALID_PASSWORD +1013 USERNAME_ALREADY_EXISTS +1014 DEVICE_ALREADY_ASSOCIATED_TO_ACCOUNT +1015 UPGRADE_DEVICE_MODEL_INVALID +1018 EXPLICIT_PIN_INCORRECT +1020 EXPLICIT_PIN_MALFORMED +1023 DEVICE_MODEL_INVALID +1024 ZIP_CODE_INVALID +1025 BIRTH_YEAR_INVALID +1026 BIRTH_YEAR_TOO_YOUNG +1027 INVALID_COUNTRY_CODE +1027 INVALID_GENDER +1034 DEVICE_DISABLED +1035 DAILY_TRIAL_LIMIT_REACHED +1036 INVALID_SPONSOR +1037 USER_ALREADY_USED_TRIAL +==== ============ + diff --git a/json/index.rst b/json/index.rst new file mode 100644 index 0000000..48edc1e --- /dev/null +++ b/json/index.rst @@ -0,0 +1,79 @@ +JSON API v5 +=========== + +The current JSON API version is 5. Two different endpoints are available: + +- http://tuner.pandora.com/services/json/ +- https://tuner.pandora.com/services/json/ + +- http://internal-tuner.pandora.com/services/json/ +- https://internal-tuner.pandora.com/services/json/ + +.. _bodyenc: + +Unless noted otherwise JSON-encoded requests sent by the client within the HTTP +POST body are encrypted using Blowfish ECB and converted to hexadecimal +notation. + +These URL parameters must be appended to the endpoint above if available: + +========== =========== +Name Description +========== =========== +method Method name +auth_token User auth token if available, partner auth token or empty if neither is known yet. +partner_id Partner id obtained by :ref:`auth-partnerLogin` or empty +user_id User id as obtained by :ref:`auth-userLogin` or empty +========== =========== + +For instance when calling :ref:`auth-userLogin` two parameters are known: +method and partner_id. The URL in this case would be +``http://tuner.pandora.com/services/json/?method=auth.userLogin&partner_id=123``. +Make sure you URL encode the parameter’s values. + +The following values must be present in every JSON request object (if available): + +.. _synctime: + +============= ====== =========== +Name Type Description +============= ====== =========== +userAuthToken string User auth token, see :ref:`auth-userLogin` +syncTime int Synchonized time. Calculation: current time + (time of :ref:`auth-partnerLogin` request – syncTime from :ref:`auth-partnerLogin` response). This is a protection against replay-attacks. +============= ====== =========== + +Every response includes the key ``stat`` which indicates success (``ok``) or +failure (``fail``) of the resquest. Failed requests contain an error code and +message whereas successful requests carry actual response data in the key +``result``: + +.. code:: json + + { + "stat": "ok", + "result": { + } + } + +.. code:: json + + { + "stat": "fail", + "message": "An unexpected error occurred", + "code": 1008 + } + +.. toctree:: + + authentication + stations + play + bookmarks + methods + errorcodes + +.. toctree:: + :hidden: + + partners + diff --git a/json/methods.rst b/json/methods.rst new file mode 100644 index 0000000..f5b7cf5 --- /dev/null +++ b/json/methods.rst @@ -0,0 +1,42 @@ +.. _methods: + +List of methods +=============== + +- :ref:`auth.getAdMetadata ` +- :ref:`auth.partnerLogin ` +- :ref:`auth.userLogin ` +- :ref:`bookmark.addArtistBookmark ` +- :ref:`bookmark.addSongBookmark ` +- :ref:`bookmark.deleteArtistBookmark ` +- :ref:`bookmark.deleteSongBookmark ` +- :ref:`music.search ` +- :ref:`music.shareMusic ` +- :ref:`station.addFeedback ` +- :ref:`station.addMusic ` +- :ref:`station.createStation ` +- :ref:`station.deleteFeedback ` +- :ref:`station.deleteMusic ` +- :ref:`station.deleteStation ` +- :ref:`station.getGenreStations ` +- :ref:`station.getGenreStationsChecksum ` +- :ref:`station.getPlaylist ` +- :ref:`station.getStation ` +- :ref:`station.shareStation ` +- :ref:`station.renameStation ` +- :ref:`station.transformSharedStation ` +- :ref:`test.echo ` +- :ref:`track.explainTrack ` +- :ref:`user.acknowledgeSubscriptionExpiration ` +- :ref:`user.associateDevice ` +- :ref:`user.canSubscribe ` +- :ref:`user.createUser ` +- :ref:`user.emailPassword ` +- :ref:`user.getBookmarks ` +- :ref:`user.getStationList ` +- :ref:`user.getStationListChecksum ` +- :ref:`user.purchaseItunesSubscription ` +- :ref:`user.setQuickMix ` +- :ref:`user.sleepSong ` +- :ref:`user.startComplimentaryTrial ` + diff --git a/json/partners.rst b/json/partners.rst new file mode 100644 index 0000000..a759d41 --- /dev/null +++ b/json/partners.rst @@ -0,0 +1,71 @@ +.. _partners: + +Partner passwords +================= + +Passwords depend on the API entry point used. + +tuner.pandora.com +----------------- + +Android +^^^^^^^ + +:username: android +:password: ``AC7IBG09A3DTSYM4R41UJWL07VLN8JI7`` +:deviceId: android-generic +:decrpyt password: ``R=U!LH$O2B#`` +:encrypt password: ``6#26FRL$ZWD`` + +iOS +^^^ + +:username: iphone +:password: ``P2E4FC0EAD3*878N92B2CDp34I0B1@388137C`` +:deviceId: IP01 +:Decrypt password: ``20zE1E47BE57$51`` +:Encrypt password: ``721^26xE22776`` + +Palm +^^^^ + +:Username: palm +:Password: ``IUC7IBG09A3JTSYM4N11UJWL07VLH8JP0`` +:deviceId: pre +:decrypt password: ``E#U$MY$O2B=`` +:encrypt password: ``%526CBL$ZU3`` + +Windows Mobile +^^^^^^^^^^^^^^ + +:Username: winmo +:Password: ``ED227E10a628EB0E8Pm825Dw7114AC39`` +:deviceId: VERIZON_MOTOQ9C +:decrypt password: ``7D671jt0C5E5d251`` +:Encrypt password: ``v93C8C2s12E0EBD`` + +internal-tuner.pandora.com +-------------------------- + +Desktop (AIR) Client +^^^^^^^^^^^^^^^^^^^^ + +:Username: pandora one +:Password: ``TVCKIBGS9AO9TSYLNNFUML0743LH82D`` +:deviceId: D01 +:Decrypt password: ``U#IO$RZPAB%VX2`` +:Encrypt password: ``2%3WCL*JU$MP]4`` + +.. note:: + + Requires a Pandora One account. Fails at station.getPlaylist without one. + +Vista Widget +^^^^^^^^^^^^ + +:Username: windowsgadget +:Password: ``EVCCIBGS9AOJTSYMNNFUML07VLH8JYP0`` +:deviceId: WG01 +:Decrypt password: ``E#IO$MYZOAB%FVR2`` +:Encrypt password: ``%22CML*ZU$8YXP[1`` + diff --git a/json/play.rst b/json/play.rst new file mode 100644 index 0000000..4766f2f --- /dev/null +++ b/json/play.rst @@ -0,0 +1,209 @@ +.. _play: + +Play +==== + +.. _station-getPlaylist: + +Retrieve playlist +----------------- + +:Method: station.getPlaylist + +This method *must* be sent over a TLS-encrypted connection. + +.. csv-table:: + :header: Name ,Type ,Description + + stationToken ,string ,station token from :ref:`user-getStationList` + additionalAudioUrl,string,Comma separated list of additional audio formats to return. (optional) + stationIsStarting,boolean,(optional) + includeTrackLength,boolean,(optional) + includeAudioToken,boolean,(optional) + xplatformAdCapable,boolean,(optional) + includeAudioReceiptUrl,boolean,(optional) + includeBackstageAdUrl,boolean,(optional) + includeSharingAdUrl,boolean,(optional) + includeSocialAdUrl,boolean,(optional) + includeCompetitiveSepIndicator,boolean,(optional) + includeCompletePlaylist,boolean,(optional) + includeTrackOptions,boolean,(optional) + audioAdPodCapable,boolean,(optional) + +Valid values for additionalAudioUrl are: + +- HTTP_40_AAC_MONO +- HTTP_64_AAC +- HTTP_32_AACPLUS +- HTTP_64_AACPLUS +- HTTP_24_AACPLUS_ADTS +- HTTP_32_AACPLUS_ADTS +- HTTP_64_AACPLUS_ADTS +- HTTP_128_MP3 +- HTTP_32_WMA + +Usually a playlist contains four tracks. + +.. code:: json + + { + "userAuthToken": "XXX", + "additionalAudioUrl": "HTTP_32_AACPLUS_ADTS,HTTP_64_AACPLUS_ADTS", + "syncTime": 1335841463, + "stationToken": "121193154444133035" + } + +.. csv-table:: + :header: Name ,Type ,Description + + items.additionalAudioUrl ,array/string ,List of additional audio urls in the requested order or single string if only one format was requested + items.songRating ,int , "1 if song was given a thumbs up, 0 if song was not rated yet" + items.audioUrlMap ,object ,Song audio format and bitrates returned differ based on what partner credentials are used. + +.. code:: json + + { + "stat": "ok", + "result": { + "items": [{ + "trackToken": "40b892bc5376e695c2e5c2b347227b85af2761b6aa417f736d9a79319b8f4cb97c9695a5f9a9a32aa2abaed43571235c", + "artistName": "Cannabich, Christian", + "albumName": "London Mozart Players, Christian Cannabich: Symphonies", + "amazonAlbumUrl": "http://www.amazon.com/dp/B000GW8ATU/?tag=wwwpandoracom-20", + "songExplorerUrl": "http://www.pandora.com/xml/music/song/london-mozart-players/christian-cannabich-symphonies/2-andantino?explicit=false", + "albumArtUrl": "http://cont-sv5-2.pandora.com/images/public/amz/5/2/9/7/095115137925_500W_488H.jpg", + "artistDetailUrl": "http://www.pandora.com/christian-cannabich?...", + "audioUrlMap": { + "highQuality": { + "bitrate": "64", + "encoding": "aacplus", + "audioUrl": "http://audio-sjl-t1-2.pandora.com/access/166132182435087962.mp4?...", + "protocol": "http" + }, + "mediumQuality": { + "bitrate": "64", + "encoding": "aacplus", + "audioUrl": "http://t1-2.cdn.pandora.com/access/4127124196771074419.mp4?...", + "protocol": "http" + }, + "lowQuality": { + "bitrate": "32", + "encoding": "aacplus", + "audioUrl": "http://audio-sv5-t1-1.pandora.com/access/3464788359714661029.mp4?...", + "protocol": "http" + } + }, + "itunesSongUrl": "http://click.linksynergy.com/fs-bin/stat?...", + "additionalAudioUrl": [ + "http://t1-2.cdn.pandora.com/access/6705986462049243054.mp4?...", + "http://audio-sjl-t1-1.pandora.com/access/2473529637452270302.mp4?..." + ], + "amazonAlbumAsin": "B000GW8ATU", + "amazonAlbumDigitalAsin": "B003H37NN4", + "artistExplorerUrl": "http://www.pandora.com/xml/music/composer/christian-cannabich?explicit=false", + "songName": "Symphony In G Major", + "albumDetailUrl": "http://www.pandora.com/london-mozart-players/christian-cannabich-symphonies?...", + "songDetailUrl": "http://www.pandora.com/london-mozart-players/christian-cannabich-symphonies/2-andantino?...", + "stationId": "121193154444133035", + "songRating": 0, + "trackGain": "10.09", + "albumExplorerUrl": "http://www.pandora.com/xml/music/album/london-mozart-players/christian-cannabich-symphonies?explicit=false", + "allowFeedback": true, + "amazonSongDigitalAsin": "B003H39AGW", + "nowPlayingStationAdUrl": "http://ad.doubleclick.net/pfadx/pand.android/prod.nowplaying..." + }, { + "adToken": "121193154444133035-none" + }, + ] + } + } + +.. _station-addFeedback: + +Rate track +---------- + +:Method: station.addFeedback + +Songs can be “loved” or “banned”. Both influence the music played on the +station. Banned songs are never played again on this particular station. + +.. csv-table:: + :header: Name,Type,Description + + stationToken,string, + trackToken,string, + isPositive,boolean, + + +.. _user-sleepSong: + +Temporarily ban track +--------------------- + +:Method: user.sleepSong + +A song can be banned *from all stations* temporarily (one month). + +.. csv-table:: + :header: Name ,Type ,Description + + trackToken ,string ,See :ref:`station-getPlaylist` + +.. code:: json + + { + "trackToken": "d6aa37c60833f12150c4e2ba172c46f24590ebc49df948b6fb7117314c41c8e7d4faee3568884468d9509db2ab998dafdbc4093baf8c38ef", + "userAuthToken": "XXX", + "syncTime": 1336386838 + } + +Nothing is returned in the response. + +.. _track-explainTrack: + +Explain track choice +-------------------- + +:Method: track.explainTrack + +Get (incomplete) list of attributes assigned to song by Music Genome Project. + +.. csv-table:: + :header: Name ,Type ,Description + + trackToken ,string ,See :ref:`station-getPlaylist` + +.. code:: json + + { + "trackToken": "94f36e09e341780c2ee7ebbb3581a55c4f2066dbaa60f2ee253ede5bc407fbd3c4f6db7ed00f92312437e020e0bf0e05d2924742c2ccece2", + "userAuthToken": "XXX", + "syncTime": 1336675993 + } + +The request returns a list of attributes. Note that the last item is not an +actual attribute. + +.. csv-table:: + :header: Name ,Type ,Description + + explanations ,array , + +.. code:: json + + { + "stat": "ok", + "result": { + "explanations": [{ + "focusTraitName": "trance roots", + "focusTraitId": "F7524" + }, + { + "focusTraitName": "many other similarities identified in the Music Genome Project", + "focusTraitId": "F4797" + }] + } + } + + diff --git a/json/stations.rst b/json/stations.rst new file mode 100644 index 0000000..b8e7821 --- /dev/null +++ b/json/stations.rst @@ -0,0 +1,289 @@ +.. _stations: + +Stations +======== + +A *station* is a collection of one or more user-supplied *seeds*. Artists or +tracks can be used as seed. Based on the seeds Pandora decides which music to +play. + +.. _user-getStationList: + +Retrieve station list +--------------------- + +:Method: user.getStationList + +.. csv-table:: + :header: Name ,Type ,Description + + includeStationArtUrl ,boolean ,Includes "artUrl" field in result (optional) + stationArtSize,string,“W130H130” + includeAdAttributes,boolean,(optional) + includeStationSeeds,boolean,(optional) + includeShuffleInsteadOfQuickMix,boolean,(optional) + includeRecommendations,boolean,(optional) + includeExplanations,boolean,(optional) + +.. code:: json + + { + "userAuthToken": "XXX", + "syncTime": XXX + } + +Currently stationId and stationToken are the same. + +QuickMix stations additionally include a list of station ids +(quickMixStationIds) that are currently selected for the mix. + +.. csv-table:: + :header: Name ,Type ,Description + + stations.stationId,string, + stations.stationName,string, + checksum,string, + +.. code:: json + + { + "stat":"ok", + "result":{ + "stations":[ + { + "suppressVideoAds":true, + "isQuickMix":true, + "stationId":"3914377363925265", + "stationDetailUrl":"https://www.pandora.com/login?target=%2Fstations%2Fa61985110ea3d6c6c8d8a9c038588b26425ba2910f7abf8b", + "isShared":false, + "dateCreated":{ + "date":8, + "day":4, + "hours":22, + "minutes":44, + "month":10, + "nanos":241000000, + "seconds":46, + "time":1194590686241, + "timezoneOffset":480, + "year":107 + }, + "stationToken":"3914377363925265", + "stationName":"QuickMix", + "stationSharingUrl":"https://www.pandora.com/login?target=%2Fshare%2Fstation%2Fa61985110ea3d6c6c8d8a9c038588b26425ba2910f7abf8b", + "requiresCleanAds":true, + "allowRename":false, + "allowAddMusic":false, + "quickMixStationIds":[ + "339646069607180561", + "339644480469281041" + ], + "allowDelete":false + } + ], + "checksum":"99776ddd31ad798895578593e78e3691" + } + } + +.. _user-getStationListChecksum: + +Check station list for modifications +------------------------------------ + +:Method: user.getStationListChecksum + +To check if the station list was modified by another client the checksum can be +fetched. No parameters are required for this request. + +The response contains the new checksum. + +.. csv-table:: + :header: Name,Type,Description + + checksum,string, + +.. code:: json + + { + "stat":"ok", + "result":{ + "checksum":"99776ddd31ad798895578593e78e3691" + } + } + +Add new station +--------------- + +New stations can be created by searching for an artist/song or using a track +from a playlist. + +.. _music-search: + +Search +^^^^^^ + +:Method: music.search + +This is a free text search that matches artist and track names. + +.. csv-table:: + :header: Name ,Type ,Description + + searchText ,string ,Artist name or track title + +.. code:: json + + { + "searchText": "encore", + "userAuthToken": "XXX", + "syncTime": 1335869287 + } + +Matching songs and artists are returned in two separate list. + +.. csv-table:: + :header: Name ,Type ,Description + + songs.musicToken and artists.musicToken ,string , + +.. code:: json + + { + "stat": "ok", + "result": { + "nearMatchesAvailable": true, + "explanation": "", + "songs": [{ + "artistName": "Jason DeRulo", + "musicToken": "S1508963", + "songName": "Encore", + "score": 100 + }], + "artists": [{ + "artistName": "Encore", + "musicToken": "R175304", + "likelyMatch": false, + "score": 100 + }] + } + } + +.. _station-createStation: + +Create +^^^^^^ + +:Method: station.createStation + +Stations can either be created with a musicToken obtained by +:ref:`music-search` or trackToken from playlists (:ref:`station-getPlaylist`). +The latter needs a musicType to specify whether the track itself or its artist +should be used as seed. + +.. csv-table:: + :header: Name,Type,Description + + trackToken,string,See :ref:`station-getPlaylist` + musicType,string,“song” or “artist” + musicToken,string,See :ref:`music-search` + +.. _station-addMusic: + +Add seed +-------- + +:Method: station.addMusic + +:ref:`music-search` results can be used to add new seeds to an existing +station. + +.. csv-table:: + :header: Name,Type,Description + + stationToken,string,"Existing station, see :ref:`user-getStationList`" + musicToken,string,"See :ref:`music-search`" + +.. _station-renameStation: + +Rename station +-------------- + +:Method: station.renameStation + +.. csv-table:: + :header: Name,Type,Description + + stationToken,string,"Existing station, see :ref:`user-getStationList`" + stationName,string,New station name + +.. _station-deleteStation: + +Delete station +-------------- + +:Method: station.deleteStation + +.. csv-table:: + :header: Name,Type,Description + + stationToken,string,"Existing station, see :ref:`user-getStationList`" + +.. _station-getGenreStations: + +Predefined stations +------------------- + +:Method: station.getGenreStations + +Pandora provides a list of predefined stations (“genre stations”). The request +has no parameters. + +Each station belongs to one category, usually a genre name. stationToken can be +used as musicToken to create a new station with :ref:`station-createStation`. + +.. csv-table:: + :header: Name ,Type ,Description + + categories ,array ,List of categories + categories.stations ,array ,List of stations in category + categories.stations.stationToken,string,"Actually a musicToken, see :ref:`station-createStation`" + catogories.categoryName,string,Category name + +.. code:: json + + { + "stat": "ok", + "result": { + "categories": [{ + "stations": [{ + "stationToken": "G165", + "stationName": "90s Alternative ", + "stationId": "G165" + }], + "categoryName": "Alternative" + }] + } + } + +.. _user-setQuickMix: + +Modify QuickMix +--------------- + +:Method: user.setQuickMix + +.. csv-table:: + :header: Name ,Type ,Description + + quickMixStationIds ,array ,List of station id’s (strings) + +.. code:: json + + { + "quickMixStationIds": ["404958383414849005", "403387202773593581"], + "userAuthToken": "XXX", + "syncTime": 1338211186 + } + +The response contains no data. + -- cgit v1.2.3