Durss / Twitchat

Full featured Twitch chat alternative to fill gaps from the official one.
https://twitchat.fr
GNU General Public License v3.0
255 stars 30 forks source link

Too many spotify requests? #27

Open twidi opened 1 year ago

twidi commented 1 year ago

I have Twitchat always openon my secondary screen (because why not...)

But look at this screenshot of my spotify application dedicated to twitchat

image

It seems that the "currently-playing" endpoint is fetched very, very, VERY often. And If think it may causes my !song trigger to add songs to the queue to fail most of the time (nothing done even if the song exists)

PS: I use the hosted version of twitchat, I don't know if the API requests are sent by the front or backend

Durss commented 1 year ago

Hello! That's "normal". Spotify provides no API to let us know when we change the currently paying track. I could simply check the track duration and wait the remaining playing duration before checking again but if you changed the track during that timeframe, the twitchat player overlay wouldn't update before the expected end of the previous track.

To avoid this kind of issue I call this endpoint every 5 seconds. It should still remain below the rate limit which is not public but that is calculated from the number of queries made in the last 30s. This makes 15 queries every 30s which shouldn't be an issue. Unless your viewers make a lot of song request of course. If the music is paused it will do this call only every 10s instead of 5s I think

I'm not sure tho if I made it so if the rate limit is reached it either shows an error on twitchat or postpone the query to when the rate limiting is over... I should check that.

All queries are sent by the frontend so if you have some developer skills that could be helpful if you could check the console when you have an issue to isolate it.

I'm a bit busy rebuilding most of twitchat these days so I'll try to check all this but can't promise anything 😬

Thank you for your feedback :)

twidi commented 1 year ago

Thanks a lot for you answer, first of all I wanted to be sure if I correctly understood the issue.

So the query to get the currently playing track is only needed to get the song when requested by a viewer.

In my head the option would be to only do this request to this endpoint when it's actually requested.

But I may be wrong, what do you think about this?

I know it would imply a delay before displaying the track info but it's a very small tradeoff we could accept, imho, to avoid polling the API so often.

twidi commented 1 year ago

I just thought that as a streamer I can have the overlay always displayed, which is not my case, so you would have to handle both cases. Maybe a checkbox activating, or not, the "currently playing" endpoint? With a mention that, if not activated, the overlay would not work.

(just thinking out loud)

Durss commented 1 year ago

Yep the main reason for this "spam" is that player overlay that needs to be reactive. Even the 10s max of await before seing the music on the player when starting it is quite long.

Things could be handle more subtely and options could be added to avoid that but I'm afraid it would make things quite complicated for the "standard" user that has no knowledge about what's an API calls. Ideally i should just "spam" the currently-playing endpoint if the player overlay is configured. But I don't feel like fiving options to the user is the right thing to do.

If you have two instances of Twitchat i'd suggest you keep one of them "blank" by not syncing the parameters to the server and disconnecting its spotify integration so you don't have 2 instances of twitchat calling the endpoint endlessly.

There's noting official but I've read here and there that we can make around 10-20 requests per seconds which should make twitchat calls way bellow the rate limits. I'll try to make some spam tests to get a better and fresh estimate of it. On this other project ( https://multiblindtest.fr ) I make ~5 request/s with no rate limiting when loading the users' playlist. There's a difference tho, this spotify app has "extended quota" (i've been lucky enough to create this app before spotify requires to apply for extended quotas... this app couldn't exist anymore due to their new rules "no games using our API" --..)_

In 2019 they had a new API tested internally to get notified when changing track to avoid that currently-playing spam but no news since then. Apparently making it scalable was their main issue. I've read that this API publicly exists but it's only communicated to few parteners of them.

Before making things more complicated to manage I'd like to make sure the rate limiting is actually the source of your issues. You set no cooldown (either global or per user) on your "!song" command that could be the reason why no track is added sometimes ? Can't it be that the requested track was not found ?

twidi commented 1 year ago

Having a cooldown (global/user) is not possible because if a user mistype its request he cannot retry, so no, I don't have a cooldown.

But I am a small streamer so I don't have a lot of song requests (especially since I only added this command very recently) Maybe the problem was on the spotify side, it's just the "correlation" with the intensive API usage that made me thought it was the issue

I did a try just now and it worked, so maybe this is not related at all :(

PS: I manually tried the user requests at the time and they were matches

Durss commented 1 year ago

I know the Spotify APi isn't the most stable i've worked with.. I had to handle 500 errors on token refreshes as I had multiple of it a day. Maybe the endpoint to search a track and/or add it to the queue also aren't super stable. For now twitchat makes it fail silently, which is not ideal.

I should eithertry again a max number of times after a fail and/or warn the streamer when it fails. I'll try to at least add that.

twidi commented 1 year ago

If it happens again I'll try to investigate (which is not always easy to do while streaming!)

Thanks for your time!

Durss commented 1 year ago

That would be super helpful 🙏

Durss commented 1 year ago

I reopen this issue so I don't forget to better handle spotify fails and potential rate limits when I have time for it :D

Durss commented 1 year ago

I just checked for the unofficial websocket API that notifies when playback changes, it works well BUT it cannot be used via an oAuth token. It only works with a spotify token.

Here it is if that can be of any interest:

const ACCESS_TOKEN = "XXXX";//Needs an official spotify token. Doesn't work with oauth tokens.
const url = "wss://gew1-dealer.spotify.com/?access_token="+ACCESS_TOKEN;
const socket = new WebSocket(url);

socket.onmessage = (event) => {
    console.log("MESSAGE:");
    console.log(event);

    //If received data contains a "headers" object with a "Spotify-Connection-Id"
    //value, then we need to call the following HTTP endpoint to subscribe to events.
    const jsonMessage = JSON.parse(event.data);
    const id = jsonMessage.headers?['Spotify-Connection-Id'];
    if (id) {
        //Request events
        fetch("https://api.spotify.com/v1/me/notifications/player?connection_id="+id,{
            method:"PUT",
            headers: { Authorization: "Bearer"+ACCESS_TOKEN }
        }).then(() => console.log("Connected!"););
    };
}
socket.onopen = (event) => {
    //Ping every 30s to keep connexion opened
    setInterval(()=> {
        socket.send(JSON.stringify({type:"ping"}));
    }, 30000);
};