sp-playcount-librespot
sp-playcount-librespot copied to clipboard
Unable to get playcounts Error 502
Since today I am unable to get the playcounts for any track. Only getting the folling error:
xyz.gianlu.librespot.mercury.MercuryClient$MercuryException: status: 502 at xyz.gianlu.librespot.mercury.MercuryClient.sendSync(MercuryClient.java:83) at xyz.gianlu.librespot.handler.PlayCountHandler.handle(PlayCountHandler.java:57) at jdk.httpserver/com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:77) at jdk.httpserver/sun.net.httpserver.AuthFilter.doFilter(AuthFilter.java:82) at jdk.httpserver/com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:80) at jdk.httpserver/sun.net.httpserver.ServerImpl$Exchange$LinkHandler.handle(ServerImpl.java:848) at jdk.httpserver/com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:77) at jdk.httpserver/sun.net.httpserver.ServerImpl$Exchange.run(ServerImpl.java:817) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) at java.base/java.lang.Thread.run(Thread.java:829)
Did something change on Spotify's side?
I recently have been unable to access playcounts aswell, but I am having the same issue as #11 although this has not happened before. I am assuming this might be something on Spotify's side too
Same issue for me 😔
Seeing they have some outages on downdetector. Hopefully that’s all it is.
I don’t see playcounts being returned even in Spotify’s own web anymore either. The counts always showed in the logs of the api call. Now they aren’t there.
I am getting this error
{"success": false, "data": "An unknown error has occurred; logged to console"}
http://MYIPADDRESS:8080/albumPlayCount?albumid=XXXXXX
and this error in the console
2023-06-19 21:26:33,101 INFO ApResolver:66 - Loaded aps into pool: {accesspoint=[ap-gew4.spotify.com:4070, ap-gew4.spotify.com:443, ap-gew4.spotify.com:80, ap-guc3.spotify.com:4070, ap-gue1.spotify.com:443, ap-gew1.spotify.com:80], dealer=[gew4-dealer.spotify.com:443, guc3-dealer.spotify.com:443, gue1-dealer.spotify.com:443, gew1-dealer.spotify.com:443], spclient=[gew4-spclient.spotify.com:443, guc3-spclient.spotify.com:443, gue1-spclient.spotify.com:443, gew1-spclient.spotify.com:443]} 2023-06-19 21:26:33,366 INFO Session:94 - Created new session! {deviceId: c70f928698cc099e39bddfd469f7de38e3b805db, ap: ap-guc3.spotify.com:4070} 2023-06-19 21:26:34,351 INFO Session:223 - Connected successfully! 2023-06-19 21:26:34,647 INFO Session:242 - Authenticated as woklxlz1f9wkuu6j9fk3x6q54! 2023-06-19 21:26:34,647 INFO Session:716 - Skipping SecretBlock 2023-06-19 21:26:34,647 INFO Session:694 - Received LicenseVersion: 0 2023-06-19 21:26:34,647 INFO Session:684 - Received CountryCode: NL [main] INFO org.cache2k.core.Cache2kCoreProviderImpl - cache2k starting. version=1.2.4.Final 2023-06-19 21:26:34,694 INFO Session:716 - Skipping UnknownData_AllZeros 2023-06-19 21:26:34,694 INFO Session:716 - Skipping LegacyWelcome Listening on port 8080 2023-06-19 21:26:35,085 INFO Session:651 - Skipping unknown command {cmd: 0x75, payload: 000000} xyz.gianlu.librespot.mercury.MercuryClient$MercuryException: status: 502 at xyz.gianlu.librespot.mercury.MercuryClient.sendSync(MercuryClient.java:83) at xyz.gianlu.librespot.handler.PlayCountHandler.handle(PlayCountHandler.java:57) at com.sun.net.httpserver.Filter$Chain.doFilter(Unknown Source) at sun.net.httpserver.AuthFilter.doFilter(Unknown Source) at com.sun.net.httpserver.Filter$Chain.doFilter(Unknown Source) at sun.net.httpserver.ServerImpl$Exchange$LinkHandler.handle(Unknown Source) at com.sun.net.httpserver.Filter$Chain.doFilter(Unknown Source) at sun.net.httpserver.ServerImpl$Exchange.run(Unknown Source) at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) at java.lang.Thread.run(Unknown Source)
I recently have been unable to access playcounts aswell, but I am having the same issue as #11 although this has not happened before. I am assuming this might be something on Spotify's side too
This is related to the country of the account. Spotify seems to have changed the accounts to the country they were created. I changed back to the country where librespot is running, but didnt fix the problem. Now, it is happening with the error I just posted above.
This issue is also only happening for the artistInfo and albumPlayCount end points . artistInsights still works.
I think Spotify finally killed support for this mercury endpoint. You can actually replicate all these calls over REST to the sp client. For example https://gae2-spclient.spotify.com/artist/v1/{artistId}/desktop currently returns 502 with response:
{
"error": {
"status": 502,
"message": "Request was not transferred"
}
}
I hope not 😔 - I wonder if there is another way to retrieve playcounts then.
I hope not 😔 - I wonder if there is another way to retrieve playcounts then.
well you can always find the appropriate album of a track, and then fetch the album (using the graphql endpoint)
https://api-partner.spotify.com/pathfinder/v1/query?operationName=getAlbum&variables={"uri":"spotify:album:{id}","locale":"","offset":0,"limit":50}&extensions={"persistedQuery":{"version":1,"sha256Hash":"46ae954ef2d2fe7732b4b2b4022157b2e18b7ea84f70591ceb164e4de1b5d5d3
returns
{
"data":{
"albumUnion":{
"__typename":"Album",
"uri":"spotify:album:...",
"name":"...",
"artists":{
....
},
"coverArt":{
...
},
...
"label":"...",
"copyright":{...
},
"courtesyLine":"",
"saved":false,
"sharingInfo":{
"shareUrl":"",
"shareId":""
},
"tracks":{
"totalCount":1,
"items":[
{
"uid":"edda05c86f012f7409cc",
"track":{
"saved":false,
"uri":"spotify:track:...",
"name":"...",
"playcount":"50288750",
"discNumber":1,
"trackNumber":1,
"contentRating":{
"label":"NONE"
},
"relinkingInformation":null,
"duration":{
"totalMilliseconds":192497
},
"playability":{
"playable":true
},
"artists":{
....
}
}
}
]
},
"moreAlbumsByArtist":{
....
}
},
"extensions":{
}
}
I hope not 😔 - I wonder if there is another way to retrieve playcounts then.
well you can always find the appropriate album of a track, and then fetch the album (using the graphql endpoint)
https://api-partner.spotify.com/pathfinder/v1/query?operationName=getAlbum&variables={"uri":"spotify:album:{id}","locale":"","offset":0,"limit":50}&extensions={"persistedQuery":{"version":1,"sha256Hash":"46ae954ef2d2fe7732b4b2b4022157b2e18b7ea84f70591ceb164e4de1b5d5d3
returns
{ "data":{ "albumUnion":{ "__typename":"Album", "uri":"spotify:album:...", "name":"...", "artists":{ .... }, "coverArt":{ ... }, ... "label":"...", "copyright":{... }, "courtesyLine":"", "saved":false, "sharingInfo":{ "shareUrl":"", "shareId":"" }, "tracks":{ "totalCount":1, "items":[ { "uid":"edda05c86f012f7409cc", "track":{ "saved":false, "uri":"spotify:track:...", "name":"...", "playcount":"50288750", "discNumber":1, "trackNumber":1, "contentRating":{ "label":"NONE" }, "relinkingInformation":null, "duration":{ "totalMilliseconds":192497 }, "playability":{ "playable":true }, "artists":{ .... } } } ] }, "moreAlbumsByArtist":{ .... } }, "extensions":{ } }
But is there a way using graph to get the complete list of Albums and Singles for an artistID?
@jpgrovy Yes but it's paged, which is really annoying. It's
https://api-partner.spotify.com/pathfinder/v1/query?operationName=queryArtistDiscographyAll&variables={"uri":"spotify:artist:{id}","offset":0,"limit":100}&extensions={"persistedQuery":{"version":1,"sha256Hash":"35a699e12a728c1a02f5bf67121a50f87341e65054e13126c03b7697fbd26692"}}
How / where do you use this link? How does it replace the mercury call? If i simply check the link you share it tells "No token provided"
That would be for you to figure out :)
Hint: use the mercury client to get a bearer and then put it in the headers
That won't be for me then I suppose, I always struggle to cope with clients/protocols, etc, I have no idea what your hint means tbh
Oh I thought you were a maintainer of this project.. Well first you'd need a bearer token to authenticate with this client. Since this is an internal API, you can't just fetch one using the official method (Spotify developer console), as that will result in an 403 (forbid).
This project I think has the ability to fetch a good token over mercury (hm://keymaster/token/authenticated?scope...), which can then be used to authenticate properly and fetch the resource I provided.
It would require quite some changes to the project, unfortunately I am not actively involved in this project so I wont do it. But the developer may of course.
@jpgrovy Yes but it's paged, which is really annoying. It's
https://api-partner.spotify.com/pathfinder/v1/query?operationName=queryArtistDiscographyAll&variables={"uri":"spotify:artist:{id}","offset":0,"limit":100}&extensions={"persistedQuery":{"version":1,"sha256Hash":"35a699e12a728c1a02f5bf67121a50f87341e65054e13126c03b7697fbd26692"}}
I get “RBAC: Access Denied” when trying to make the api-partner calls.
Side note… anyone want to be awesome and fix the librespot playcount code? 🙏🙏🙏
Yep, they most likely killed the endpoint: librespot-org/librespot-java#678
Since it seems like Spotify doesn't use Hermes in their clients anymore, I think the only way forward with this project is to use Spotify's private API, so this repo may be archived once I figure things out.
Well... hermes is just their internal router. As I mentioned earlier, all hermes endpoints can be translated to their HTTPs counterpart by just replacing hm:// with the spclient url.
I think hermes will still be supported, since a lot of their internal services may still use them.
You can fetch an access token using :
hm://keymaster/token/authenticated?scope=user-read-private,user-read-email,playlist-modify-public,ugc-image-upload,playlist-read-private,playlist-read-collaborative,playlist-read&client_id=65b708073fc0480ea92a077233ca87bd&device_id=
Which you can then use to access the private api (partner + spclient) . The public (web api) endpoints also work
Yep, they most likely killed the endpoint: librespot-org#678
Since it seems like Spotify doesn't use Hermes in their clients anymore, I think the only way forward with this project is to use Spotify's private API, so this repo may be archived once I figure things out.
To re-do this repo maybe the easiest is to restart from the last version of librespot-java and import the few playcount / artist info handlers into it as the former now manages the Web API, has a token provider with the keymaster and all. In a first step it wouldn't be needed to stripe the unneeded content or anything.
Well... hermes is just their internal router. As I mentioned earlier, all hermes endpoints can be translated to their HTTPs counterpart by just replacing hm:// with the spclient url.
Ah, I haven't worked on this project in a while and forgot the terminology. I meant to say that their clients switched to using the GraphQL API for retrieving stuff like track play counts in an album. Since it seems that all endpoints that this project uses have become useless (albumPlayCount
and artistInfo
return status code 502, artistAbout
and artistInsights
just fills in 0 for all relevant values), the GraphQL API seems to be the only replacement for those endpoints. The access token for the GraphQL endpoints needed don't require Mercury or authentication either (the token can be retrieved through https://open.spotify.com/get_access_token?reason=transport&productType=web_player
).
...which at that point I'd essentially be making a CORS proxy for the GraphQL API. Seems like a cheap solution, though the main issue is that the GraphQL API is quite terrible to work with, so I'd have to look into that further :p
Yes the graphql api is terrible to work with, and I do not understand why Spotify did not just build on the web-api, which has a good schema.
Anyways, I was also able to implement the oauth protocol using PKCE, and reverse engineer their persistent login mechanism. Which still uses the actual TCP connection some parts.
Mainly, after the oauth callback, you get an access token, which you can then use to authenticate using the old method (over TCP). Then in the APWelcome message, you have some re-usable credentials which are then posted in the body of https://login5.spotify.com/v3/login
In pseudo code this will look like
var webResponse = openBrowserAndCatchRedirectToken();
var accessToken = webResponse.accessToken;
var username = webResponse.username;
var credentials = new LoginCredentials
{
Typ = AUTHENTICATION_SPOTIFY_TOKEN,
Username = username,
AuthData = ByteString.CopyFromUtf8(accessToken)
}
var apwelcome = performAuthOverTcp(credentials);
var reusablecredentials = apwelcome.reusable_auth_credentials;
Next in another login session: POST https://login5.spotify.com/v3/login the body is a protobuf with:
message LoginRequest {
.spotify.login5.v3.ClientInfo client_info = 1;
.spotify.login5.v3.credentials.StoredCredential stored_credential = 100;
}
Yes the graphql api is terrible to work with, and I do not understand why Spotify did not just build on the web-api, which has a good schema.
Anyways, I was also able to implement the oauth protocol using PKCE, and reverse engineer their persistent login mechanism. Which still uses the actual TCP connection some parts.
Mainly, after the oauth callback, you get an access token, which you can then use to authenticate using the old method (over TCP). Then in the APWelcome message, you have some re-usable credentials which are then posted in the body of https://login5.spotify.com/v3/login
In pseudo code this will look like
var webResponse = openBrowserAndCatchRedirectToken(); var accessToken = webResponse.accessToken; var username = webResponse.username; var credentials = new LoginCredentials { Typ = AUTHENTICATION_SPOTIFY_TOKEN, Username = username, AuthData = ByteString.CopyFromUtf8(accessToken) } var apwelcome = performAuthOverTcp(credentials); var reusablecredentials = apwelcome.reusable_auth_credentials;
Next in another login session: POST https://login5.spotify.com/v3/login the body is a protobuf with:
message LoginRequest { .spotify.login5.v3.ClientInfo client_info = 1; .spotify.login5.v3.credentials.StoredCredential stored_credential = 100; }
You guys are too smart for me 😉 … does this mean it’s fixable to get working again?
Hey @christosk92 ,
Do you know a replacement of artistInsights with their graphql API especially for top 50 cities ?
I don't find one.
queryArtistOverview
seems to be the only endpoint for retrieving artist data, which does include the top 5 cities.
I'm currently testing sp-playcount on api.t4ils.dev:
https://api.t4ils.dev/getArtist?id=1g8HCTiMwBtFtpRR9JXAZR (uses queryArtistOverview
)
https://api.t4ils.dev/getAlbum?id=5K4YFkTizFoMOyN5Khfp7G (uses getAlbum
)
https://api.t4ils.dev/getAlbumTracks?id=5K4YFkTizFoMOyN5Khfp7G (uses queryAlbumTracks
)
Hi @entriphy, How did you find the definition of the GQL query you document here ?
@entriphy : yes it seems old top 50 is no longer available via graphq :/
@louison You can find those when looking in the source code of the webplayer. Those queries are then hashed to decrease request size.. Specifically, the web-player.{}.js file will be interesting. There's a line in the file:
const t = await a.k.hash(e.body);
Which if you put a breakpoint there, you can expect the body
Hey @christosk92 ,
Do you know a replacement of artistInsights with their graphql API especially for top 50 cities ?
I don't find one.
Artist Insights is showing Top 50 cities and still works
Hey @christosk92 , Do you know a replacement of artistInsights with their graphql API especially for top 50 cities ? I don't find one.
Artist Insights is showing Top 50 cities and still works
Yes I know, but I anticipate
Is anyone working on an update / fix ?