Handling a bot that can view events on a different channel (2 different twitch accounts) #24

Open
opened 2023-07-12 14:10:37 +02:00 by jitspoe · 5 comments
jitspoe commented 2023-07-12 14:10:37 +02:00 (Migrated from github.com)

So this is more of a request/discussion than a bug, but I was attempting to create a bot that would sit in my channel and have responses as the bot name but also respond to events like point redeems and follows to my channel. It seems like the only way to do this is to have 2 different authentications: one from my twitch, and one from the bot's twitch. The follow notifications worked by having the bot as a moderator, but it seems like other events don't have that functionality.

So I effectively, I set up 2 different scopes and 2 different authorizations. It was kind of a pain, because, since it opens the browser which is logged into my main twitch account, it would automatically authenticate. I ended up having the 2nd one just copy to the clipboard instead of open a browser window from the shell. That way I could paste it into a different browser that was logged into my bot account.

I'm not sure if this is the intended approach -- seems like a real hot mess, but I did get it technically working. Not sure the best way to handle the UX for this due to needing 2 different logins. I guess an "authenticate channel" button and "authenticate bot account" button that would copy the URLs to be pasted in appropriate browser windows?

I just wanted my bot to respond to point redeems! 😭

Side note, the refresh_tokens() function seems like it might not be entirely correct? Maybe I just don't understand it.

func refresh_token() -> void:
	await(get_tree().create_timer(3600).timeout)
	if (await(is_token_valid(token_user["access_token"])) == ""):
		user_token_invalid.emit()
		return
	else:
		refresh_token()
	var to_remove : Array[String] = []
	for entry in eventsub_messages.keys():
		if (Time.get_ticks_msec() - eventsub_messages[entry] > 600000):
			to_remove.append(entry)
	for n in to_remove:
		eventsub_messages.erase(n)

It seems it waits 1 hour, then, if the token is invalid, it emits a signal and returns. If it's still valid, it calls refresh_token() recursively, which waits 1 hour, etc. So if, after the first hour, the token is invalid, the signal emits (does anything listen to this?) and returns without clearing the eventsub messages (though now that I'm looking at it closer, I guess it only cares about removing old stuff, so maybe that's fine?)

For my thing, I rewrote it like this, but I'm not 100% sure if that's correct, either:

func refresh_token() -> void:
	var tokens_valid := true
	while (tokens_valid):
		await(get_tree().create_timer(3600).timeout)
		if (await(validate_token_and_set_id(token_user["access_token"], ScopeType.SCOPE_TYPE_USER)) == ""):
			tokens_valid = false
		if (await(validate_token_and_set_id(token_channel["access_token"], ScopeType.SCOPE_TYPE_CHANNEL)) == ""):
			tokens_valid = false
		
		if (!tokens_valid):
			user_token_invalid.emit()
			var to_remove : Array[String] = []
			for entry in eventsub_messages.keys():
				if (Time.get_ticks_msec() - eventsub_messages[entry] > 600000):
					to_remove.append(entry)
			for n in to_remove:
				eventsub_messages.erase(n)
			print("TOKENS INVALID!!!!!")

I did eventually run into the token becoming invalid after a few hours, and I'm not sure what to do after that -- just completely reconnect everything? Doesn't look like the original code handles that case either.

I can share more of my code if you'd like, but it's kind of a hot mess...

So this is more of a request/discussion than a bug, but I was attempting to create a bot that would sit in my channel and have responses as the bot name but also respond to events like point redeems and follows to my channel. It seems like the only way to do this is to have 2 different authentications: one from my twitch, and one from the bot's twitch. The follow notifications worked by having the bot as a moderator, but it seems like other events don't have that functionality. So I effectively, I set up 2 different scopes and 2 different authorizations. It was kind of a pain, because, since it opens the browser which is logged into my main twitch account, it would automatically authenticate. I ended up having the 2nd one just copy to the clipboard instead of open a browser window from the shell. That way I could paste it into a different browser that was logged into my bot account. I'm not sure if this is the intended approach -- seems like a real hot mess, but I did get it technically working. Not sure the best way to handle the UX for this due to needing 2 different logins. I guess an "authenticate channel" button and "authenticate bot account" button that would copy the URLs to be pasted in appropriate browser windows? I just wanted my bot to respond to point redeems! 😭 Side note, the refresh_tokens() function seems like it might not be entirely correct? Maybe I just don't understand it. ``` func refresh_token() -> void: await(get_tree().create_timer(3600).timeout) if (await(is_token_valid(token_user["access_token"])) == ""): user_token_invalid.emit() return else: refresh_token() var to_remove : Array[String] = [] for entry in eventsub_messages.keys(): if (Time.get_ticks_msec() - eventsub_messages[entry] > 600000): to_remove.append(entry) for n in to_remove: eventsub_messages.erase(n) ``` It seems it waits 1 hour, then, if the token is invalid, it emits a signal and returns. If it's still valid, it calls refresh_token() recursively, which waits 1 hour, etc. So if, after the first hour, the token is invalid, the signal emits (does anything listen to this?) and returns without clearing the eventsub messages (though now that I'm looking at it closer, I guess it only cares about removing old stuff, so maybe that's fine?) For my thing, I rewrote it like this, but I'm not 100% sure if that's correct, either: ``` func refresh_token() -> void: var tokens_valid := true while (tokens_valid): await(get_tree().create_timer(3600).timeout) if (await(validate_token_and_set_id(token_user["access_token"], ScopeType.SCOPE_TYPE_USER)) == ""): tokens_valid = false if (await(validate_token_and_set_id(token_channel["access_token"], ScopeType.SCOPE_TYPE_CHANNEL)) == ""): tokens_valid = false if (!tokens_valid): user_token_invalid.emit() var to_remove : Array[String] = [] for entry in eventsub_messages.keys(): if (Time.get_ticks_msec() - eventsub_messages[entry] > 600000): to_remove.append(entry) for n in to_remove: eventsub_messages.erase(n) print("TOKENS INVALID!!!!!") ``` I did eventually run into the token becoming invalid after a few hours, and I'm not sure what to do after that -- just completely reconnect everything? Doesn't look like the original code handles that case either. I can share more of my code if you'd like, but it's kind of a hot mess...
issork commented 2023-07-12 21:28:01 +02:00 (Migrated from github.com)

Currently, it is intended that you handle invalid tokens yourself - for example by requesting a new one, I unfortunately did not find the time yet to add handling all cases and error messages. It is not important for the EventSub messages to be cleared, so I didn't bother with that because clearing after 1h if you decide to reconnect is fine too ^^

Receiving channel point redemption events should work in theory from the bot account by adding the channel:read:redemptions or channel:manage:redemptions scope, but I've also heard from issues with that approach which I couldn't find anything about in the documentation. My guess for one of the issues was that only the app that created the reward may receive notifications of its redemption.

Currently, it is intended that you handle invalid tokens yourself - for example by requesting a new one, I unfortunately did not find the time yet to add handling all cases and error messages. It is not important for the EventSub messages to be cleared, so I didn't bother with that because clearing after 1h if you decide to reconnect is fine too ^^ Receiving channel point redemption events should work in theory from the bot account by adding the _channel:read:redemptions_ or _channel:manage:redemptions_ scope, but I've also heard from issues with that approach which I couldn't find anything about in the documentation. My guess for one of the issues was that only the app that created the reward may receive notifications of its redemption.
jitspoe commented 2023-07-13 08:31:07 +02:00 (Migrated from github.com)

Gotcha, so I'm supposed to connect to the invalid token event and get a new token? Also, if the token goes invalid, is there any down time between when the token went invalid and when the check happens that could result in lost events? Sorry, I'm new to all this twitch event stuff, and it's super confusing. 😅

The problem with the scopes is it gives it the scope to read the channel points on the bot's channel, not my channel. At least, I couldn't figure out how to do it -- either I had to be 100% on my account or the bot's account with a single token, so I made 2.

Gotcha, so I'm supposed to connect to the invalid token event and get a new token? Also, if the token goes invalid, is there any down time between when the token went invalid and when the check happens that could result in lost events? Sorry, I'm new to all this twitch event stuff, and it's super confusing. 😅 The problem with the scopes is it gives it the scope to read the channel points on the *bot's* channel, not my channel. At least, I couldn't figure out how to do it -- either I had to be 100% on my account or the bot's account with a single token, so I made 2.
issork commented 2023-07-13 08:46:44 +02:00 (Migrated from github.com)

The event subscription has a 'condition' parameter, make sure to pass in a dictionary with "broadcaster_user_id": "<your_broadcaster_user_id>" as an entry. (see https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelchannel_points_custom_reward_redemptionadd)

I think there is a downtime, but I'm not 100% sure.

The event subscription has a 'condition' parameter, make sure to pass in a dictionary with `"broadcaster_user_id": "<your_broadcaster_user_id>"` as an entry. (see https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelchannel_points_custom_reward_redemptionadd) I think there is a downtime, but I'm not 100% sure.
issork commented 2023-07-13 09:00:45 +02:00 (Migrated from github.com)

Took another look, Twitch does some guessing and sometimes resends events, but it's not guaranteed - so better take into account that an event might've been lost. Maybe by requesting reward redemptions from the regular API upon reconnect? (would also require you to create the rewards with the app itself)

Took another look, Twitch does some guessing and sometimes resends events, but it's not guaranteed - so better take into account that an event might've been lost. Maybe by [requesting reward redemptions](https://dev.twitch.tv/docs/api/reference/#get-custom-reward-redemption) from the regular API upon reconnect? (would also require you to create the rewards with the app itself)
issork commented 2023-11-29 13:31:12 +01:00 (Migrated from github.com)

Just an update on this issue - I am currently rewriting the entire plugin and in the coming release multiple bot accounts will be possible by using the "force_verify" parameter, which will forcefully show the login window again on which you can change the account to be used.

Just an update on this issue - I am currently rewriting the entire plugin and in the coming release multiple bot accounts will be possible by using the "force_verify" parameter, which will forcefully show the login window again on which you can change the account to be used.
Sign in to join this conversation.
No description provided.