Update protobuf definitions and endpoints to use current official client ones. #734
Replies: 18 comments 56 replies
-
One note: The best gRPC library in Rust is probably tonic (from the tokio stack). It uses prost instead of protobuf, so it might be better to switch. |
Beta Was this translation helpful? Give feedback.
-
Never done that so I can't promise I can help, but I might give it a try, it sounds interesting! Is there a place where you (and others) will be uploading your findings? |
Beta Was this translation helpful? Give feedback.
-
Ok, so what I'm going to do is dedicate a comment to each endpoint that I reverse. I'll attach screenshots of the decoded protobufs (request/response) where it may be helpful, and reference the endpoint, along with the proto definitions. The proto files I'm using I extracted earlier, available here. The proto descriptor is useful for anyone looking to do their own poking around, uploaded here. Alternatively, you can compile if from the proto definitions above using a variant of the command:
|
Beta Was this translation helpful? Give feedback.
-
Extended Metadata Endpoint (Protobuf)Endpoint: Proto definitions (refer to
Decoded Request ScreenshotDecoded Response Screenshot |
Beta Was this translation helpful? Give feedback.
-
User Customisation Endpoint (Protobuf)Endpoint: Proto definitions (refer to
NotesI didn't think much of ths endpoint initially, it seemed to just be a bunch of A/B test flags, but on closer inspection, it appears to carry a bunch of possibly useful information. Besides feature flags (one of which is Spotify HiFi), it has buffer parameters, prefetch configuration, account status and permissions, api base urls, etc. Instead of a screenshot, I've posted the request/response json below (converted from protobuf) Request Payload
Response Payload
|
Beta Was this translation helpful? Give feedback.
-
Connect State EndpointEndpoint: Proto definitions (
NotesTo implement the repeat single/context functonality on the client, one needs to look at the
Also, there are some other fields within the device message such as The device-state endpoint needs quite a bit more exploration, and probably warrants a thread of its own, as it seems to be the bucket into which Spotify is dumping most of the player state used when syncing up devices. |
Beta Was this translation helpful? Give feedback.
-
The comma-separated values probably map to Spotify's loudness levels. This is old documentation from the net:
Currently Spotify only documents the LUFS value and no longer the dB gain. Where dB is assumed to be dBFS and LUFS is k-weighted. So the documentation above is indicative but not necessarily normative. If you add 3 dB to the comma-separated you're more-or-less meeting the indicative documented values. I'd have to think harder what the first "1" and last "-2.0" indicate. Taking a guess: "1" for the scheme version number and "-2.0" for the -2 dB true peak that Spotify targets. @sashahilton00 general question: so I understand |
Beta Was this translation helpful? Give feedback.
-
Ping me if you need any help. |
Beta Was this translation helpful? Give feedback.
-
@roderickvd that's a good question. From the issue emails I've been getting from librespot-java, it looks like @devgianlu and co. have put quite a bit of work into reverse engineering chunks of the new API, hence in some cases the stuff I post here has likely been reverse engineered in part or fully over at librespot-java. @devgianlu would be best placed to answer the question of what has been reverse engineered that we can use, something of note is the dealer endpoint, which if we want to support group listening at some point, will need to be added, as thisis where group listening context seems to be published to. Other than that, it just sends pingpong requests unless I am missing something. My reverse engineering is simply me capturing and examining the network traffic between desktop <-> Spotify, so what I post should be useful enough as a reference, but in terms of what we focus on, we should probably look to discussions and their upvotes, along with features that we thnk are going to be increasingly important when working out what to prioritise. In my mind, there are a few things that are must haves before the library hits
Besides the above, there are other things that would be 'nice to have', but are by no means essential. Things like extended metadata can be added in later versions, the above is just some of the stuff which I think is required for it to be released as stable. If people have a different view, I'm open to changing my mind. In the meantime, I will keep documenting the protocols when I have a moment and adding them here, since it's just grunt work that I can do when I have an hour or two spare. Anyone else feel free to do the same. |
Beta Was this translation helpful? Give feedback.
-
Looking back, the above is a bit of a roaming response, but hopefully it provides some clarification on why I'm spending the time to examine the latest protocols and the overall direction that I'm working to as a basis. |
Beta Was this translation helpful? Give feedback.
-
Client Token Endpoint (Protobuf)Endpoint: Proto Definitions missing. NotesThis endpoint is where the client token is retrieved from, which is subsequently used in a multitude of requests. The request/response are shown below. Further investigation is required to determne the proto definitions, which will be updated accordingly in the request/response once discovered.
Request
Response
|
Beta Was this translation helpful? Give feedback.
-
I thought it already was, just realised it's still in issues. Will move it. |
Beta Was this translation helpful? Give feedback.
-
Just FYI, many endpoints do not like getting gzipped content and will return 400. |
Beta Was this translation helpful? Give feedback.
-
OK guys I'm eager to take this on but am going to need a bit of initiation. I looked at librespot-org/librespot-java#105 but from where I'm at it's overwhelming. Where do I start without turning this into an endless break-fest? Really please set me up with some clear and bounded tasks, I'm happy to take them on. I'll likely become more self-sufficient fast but for now I just don't know where to start. |
Beta Was this translation helpful? Give feedback.
-
@devgianlu I'm dipping my toes porting the new Spotify API from |
Beta Was this translation helpful? Give feedback.
-
For reference this is today's <?xml version='1.0' encoding='utf-8'?>
<products>
<product>
<type>premium</type>
<ab-ad-player-targeting>1</ab-ad-player-targeting>
<ab-android-push-notifications>1</ab-android-push-notifications>
<ab-browse-music-tuesday>1</ab-browse-music-tuesday>
<ab-collection-bookmark-model>1</ab-collection-bookmark-model>
<ab-collection-followed-artists-only>0</ab-collection-followed-artists-only>
<ab-collection-hide-unavailable-albums>0</ab-collection-hide-unavailable-albums>
<ab-collection-offline-mode>0</ab-collection-offline-mode>
<ab-collection-union>1</ab-collection-union>
<ab-desktop-hide-follow>0</ab-desktop-hide-follow>
<ab-mobile-discover>0</ab-mobile-discover>
<ab-mobile-running-onlymanualmode>only-manual</ab-mobile-running-onlymanualmode>
<ab-mobile-running-tempo-detection>Control</ab-mobile-running-tempo-detection>
<ab-mobile-social-feed>1</ab-mobile-social-feed>
<ab-mobile-startpage>0</ab-mobile-startpage>
<ab-moments-experience>0</ab-moments-experience>
<ab-new-share-flow>0</ab-new-share-flow>
<ab-play-history>0</ab-play-history>
<ab-sugarpills-sanity-check>0</ab-sugarpills-sanity-check>
<ab-test-group>705</ab-test-group>
<ab-watch-now>0</ab-watch-now>
<ab_recently_played_feature_time_filter_threshold>com.spotify.gaia=30,driving-mode=120,spotify%3Ainternal%3Astartpage=30</ab_recently_played_feature_time_filter_threshold>
<ad-formats-preroll-video>0</ad-formats-preroll-video>
<ad-formats-video-takeover>0</ad-formats-video-takeover>
<ad-persist-reward-time>0</ad-persist-reward-time>
<ad-session-persistence>1</ad-session-persistence>
<ads>0</ads>
<allow-override-internal-prefs>0</allow-override-internal-prefs>
<ap-resolve-pods>0</ap-resolve-pods>
<app-developer>0</app-developer>
<arsenal_country>1</arsenal_country>
<audio-preview-url-template>https://p.scdn.co/mp3-preview/{id}</audio-preview-url-template>
<browse-overview-enabled>1</browse-overview-enabled>
<buffering-strategy>2</buffering-strategy>
<buffering-strategy-parameters>0.8:0.2:0.0:0.0:0.0:0.0:1.0:10:10:2000:10000:10485760</buffering-strategy-parameters>
<capper-profile></capper-profile>
<capping-bar-threshold>3601</capping-bar-threshold>
<catalogue>premium</catalogue>
<collection>1</collection>
<enable-annotations-read>0</enable-annotations-read>
<enable-autostart>1</enable-autostart>
<enable-crossfade>1</enable-crossfade>
<enable-gapless>1</enable-gapless>
<expiry>1</expiry>
<explicit-content>1</explicit-content>
<fb-grant-permission-local-render>0</fb-grant-permission-local-render>
<fb-info-confirmation>control</fb-info-confirmation>
<financial-product>pr:premium,tc:0,rt:v2_NL_default_new-family-master_14.99_EUR_default</financial-product>
<head-file-caching>1</head-file-caching>
<head-files>1</head-files>
<head-files-url>http://heads4-ak.spotify.com.edgesuite.net/head/{file_id}</head-files-url>
<high-bitrate>1</high-bitrate>
<image-url>https://i.scdn.co/image/{file_id}</image-url>
<incognito_mode_timeout>21600</incognito_mode_timeout>
<india-experience>0</india-experience>
<instant-search>0</instant-search>
<instant-search-expand-sidebar>0</instant-search-expand-sidebar>
<is_email_verified>1</is_email_verified>
<is_maybe_in_social_session>0</is_maybe_in_social_session>
<key-caching-max-count>10000</key-caching-max-count>
<key-caching-max-offline-seconds>1800</key-caching-max-offline-seconds>
<lastfm-session></lastfm-session>
<libspotify>1</libspotify>
<license-acceptance-grace-days>30</license-acceptance-grace-days>
<license-agreements></license-agreements>
<local-files-import>0</local-files-import>
<metadata-link-lookup-modes>0</metadata-link-lookup-modes>
<mobile>1</mobile>
<mobile-browse>0</mobile-browse>
<mobile-login>1</mobile-login>
<mobile-payment>0</mobile-payment>
<name>Spotify Premium</name>
<network-operator-premium-activation>1</network-operator-premium-activation>
<nft-disabled>1</nft-disabled>
<npt-disabled>2</npt-disabled>
<offline>1</offline>
<on-demand>1</on-demand>
<pause-after>0</pause-after>
<payment-state></payment-state>
<payments-cancel-state-interstitial>0</payments-cancel-state-interstitial>
<payments-initial-campaign>default</payments-initial-campaign>
<payments-latest-reusable-provider>adyen_ideal;2020-06-02</payments-latest-reusable-provider>
<payments-locked-state>0</payments-locked-state>
<player-license>premium</player-license>
<playlist-annotations-markup>0</playlist-annotations-markup>
<playlist-folders>1</playlist-folders>
<preferred-locale>nl-nl</preferred-locale>
<prefetch-keys>1</prefetch-keys>
<prefetch-strategy>8</prefetch-strategy>
<prefetch-window-max>2</prefetch-window-max>
<public-toplist>1</public-toplist>
<publish-activity>1</publish-activity>
<publish-playlist>1</publish-playlist>
<radio>1</radio>
<remote-control>0</remote-control>
<send-email>1</send-email>
<shows-collection>0</shows-collection>
<shows-collection-jam>0</shows-collection-jam>
<shuffle>0</shuffle>
<shuffle-algorithm>1</shuffle-algorithm>
<sidebar-navigation-enabled>0</sidebar-navigation-enabled>
<storage-size-config>10240,90,500,3</storage-size-config>
<streaming>1</streaming>
<streaming-rules></streaming-rules>
<taste-onboarding-disabled>0</taste-onboarding-disabled>
<track-cap>0</track-cap>
<ugc-abuse-report>0</ugc-abuse-report>
<ugc-abuse-report-url>https://support.spotify.com/abuse/?uri={uri}</ugc-abuse-report-url>
<unrestricted>1</unrestricted>
<use-fb-publish-backend>2</use-fb-publish-backend>
<use-pl3>0</use-pl3>
<use-playlist-uris>0</use-playlist-uris>
<user-profile-show-invitation-codes>0</user-profile-show-invitation-codes>
<video-cdn-sampling>1</video-cdn-sampling>
<video-device-blacklisted>0</video-device-blacklisted>
<video-initial-bitrate>200000</video-initial-bitrate>
<video-keyframe-url>http://keyframes-fa.cdn.spotify.com/keyframes/v1/sources/{source_id}/keyframe/heights/{height}/timestamps/{timestamp_ms}.jpg</video-keyframe-url>
<video-manifest-url>https://spclient.wg.spotify.com/manifests/v3/{type}/sources/{source_id}</video-manifest-url>
<video-wifi-initial-bitrate>800000</video-wifi-initial-bitrate>
<wanted-licenses></wanted-licenses>
<widevine-license-url>https://spclient.wg.spotify.com/widevine-license/v1/video/license</widevine-license-url>
</product>
</products> |
Beta Was this translation helpful? Give feedback.
-
i'm working on an other project. but this thread helps me a lot. thank you very much. |
Beta Was this translation helpful? Give feedback.
-
Connecting as a client, I see more messages being pushed, like these ones when you favourite songs:
When you create a playlist and add a track to it, remove one, rename it:
I can't remember what this was, I think they arrived seemingly randomly as I was just playing a track:
|
Beta Was this translation helpful? Give feedback.
-
Over the course of the past few years, Spotify has updated it's protobufs several times, along with its endpoints. This was to be expected as they continued to add functionality, nonetheless librespot is now pretty significantly diverged from the protobuf definitions that are in use in the official clients, and possibly at higher risk of experiencing issues with endpoints being depreciated at short notice, such as the recent issues Facebook login flow (admittedly not due to protobuf definition issues though).
Furthermore, newer functionality such as canvas, context management, streaming groups, etc. is implemented in the newer
proto3
definitions, attached below.Given that Spotify is slowly standardising to HTTP/Websockets/GRPC transports, and moving away from Hermes, it may be good for this project in the long run if we were to try to follow suit. To this end, further reverse engineering of the current endpoints that are in use will need to be carried out, and the existing code updated where necessary. As a side effect of this, my gut tells me that a number of the smaller issues/feature requests (eg. repeat functionality only partially working, more 'spotify-like' normalization, etc.) will be easier to implement once we are using their up to date APIs.
I will start investigating when I get some free time, and add to this comment accordingly with any findings that I turn up. Anyone else is also invited to crack out
spotify-dissect
and start digging through the network traffic. If the log of notes starts to become unwieldy we can always form some sort of to-do list or stick the information in a wiki page temporarily.The latest protobufs: spotify_protobufs.zip
Beta Was this translation helpful? Give feedback.
All reactions