fixed #20
This commit is contained in:
parent
1f1ad16e6f
commit
18450d661d
13
Gift.gd
13
Gift.gd
@ -3,7 +3,7 @@ extends Gift
|
||||
func _ready() -> void:
|
||||
cmd_no_permission.connect(no_permission)
|
||||
chat_message.connect(on_chat)
|
||||
channel_follow.connect(on_follow)
|
||||
event.connect(on_event)
|
||||
|
||||
# I use a file in the working directory to store auth data
|
||||
# so that I don't accidentally push it to the repository.
|
||||
@ -24,8 +24,11 @@ func _ready() -> void:
|
||||
if (success):
|
||||
request_caps()
|
||||
join_channel(initial_channel)
|
||||
events.append("channel.follow")
|
||||
await(connect_to_eventsub())
|
||||
# Refer to https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/ for details on
|
||||
# what events exist, which API versions are available and which conditions are required.
|
||||
# Make sure your token has all required scopes for the event.
|
||||
subscribe_event("channel.follow", 2, {"broadcaster_user_id": user_id, "moderator_user_id": user_id})
|
||||
|
||||
# Adds a command with a specified permission flag.
|
||||
# All implementations must take at least one arg for the command info.
|
||||
@ -75,8 +78,10 @@ func _ready() -> void:
|
||||
# Send a whisper to target user
|
||||
# whisper("TEST", initial_channel)
|
||||
|
||||
func on_follow(data : Dictionary) -> void:
|
||||
print("%s followed your channel!" % data["user_name"])
|
||||
func on_event(type : String, data : Dictionary) -> void:
|
||||
match(type):
|
||||
"channel.follow":
|
||||
print("%s followed your channel!" % data["user_name"])
|
||||
|
||||
func on_chat(data : SenderData, msg : String) -> void:
|
||||
%ChatContainer.put_chat(data, msg)
|
||||
|
@ -15,6 +15,7 @@ grow_vertical = 2
|
||||
|
||||
[node name="Gift" type="Node" parent="."]
|
||||
script = ExtResource("1")
|
||||
scopes = Array[String](["chat:edit", "chat:read", "moderator:read:followers"])
|
||||
|
||||
[node name="ChatContainer" type="VBoxContainer" parent="."]
|
||||
unique_name_in_owner = true
|
||||
|
17
README.md
17
README.md
@ -27,7 +27,7 @@ extends Gift
|
||||
func _ready() -> void:
|
||||
cmd_no_permission.connect(no_permission)
|
||||
chat_message.connect(on_chat)
|
||||
channel_follow.connect(on_follow)
|
||||
event.connect(on_event)
|
||||
|
||||
# I use a file in the working directory to store auth data
|
||||
# so that I don't accidentally push it to the repository.
|
||||
@ -48,8 +48,11 @@ func _ready() -> void:
|
||||
if (success):
|
||||
request_caps()
|
||||
join_channel(initial_channel)
|
||||
events.append("channel.follow")
|
||||
await(connect_to_eventsub())
|
||||
# Refer to https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/ for details on
|
||||
# what events exist, which API versions are available and which conditions are required.
|
||||
# Make sure your token has all required scopes for the event.
|
||||
subscribe_event("channel.follow", 2, {"broadcaster_user_id": user_id, "moderator_user_id": user_id})
|
||||
|
||||
# Adds a command with a specified permission flag.
|
||||
# All implementations must take at least one arg for the command info.
|
||||
@ -99,8 +102,10 @@ func _ready() -> void:
|
||||
# Send a whisper to target user
|
||||
# whisper("TEST", initial_channel)
|
||||
|
||||
func on_follow(data : Dictionary) -> void:
|
||||
print("%s followed your channel!" % data["user_name"])
|
||||
func on_event(type : String, data : Dictionary) -> void:
|
||||
match(type):
|
||||
"channel.follow":
|
||||
print("%s followed your channel!" % data["user_name"])
|
||||
|
||||
func on_chat(data : SenderData, msg : String) -> void:
|
||||
%ChatContainer.put_chat(data, msg)
|
||||
@ -174,9 +179,7 @@ func list(cmd_info : CommandInfo, arg_ary : PackedStringArray) -> void:
|
||||
|events_id(id)|id(String))|The id has been received from the welcome message.|
|
||||
|events_reconnect|-|Twitch directed the bot to reconnect to a different URL.|
|
||||
|events_revoked|event(String), reason(String)|Twitch revoked a event subscription|
|
||||
|
||||
Events from EventSub are named just like their subscription name, with all '.' replaced by '_'.
|
||||
Example: channel.follow emits the signal channel_follow(data(Dictionary))
|
||||
|event|type(String), data(Dictionary)|A subscribed eventsub event omitted data.|
|
||||
***
|
||||
|
||||
### Functions:
|
||||
|
@ -44,52 +44,8 @@ signal events_reconnect
|
||||
# Twitch revoked a event subscription
|
||||
signal events_revoked(event, reason)
|
||||
|
||||
# Currently supported Twitch events. Refer to https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/ for details.
|
||||
#signal channel_update
|
||||
signal channel_follow(event_dict) # Beta, Twitch might change the API.
|
||||
signal channel_subscribe(event_dict)
|
||||
#signal channel_subscription_end
|
||||
signal channel_subscription_gift(event_dict)
|
||||
signal channel_subscription_message(event_dict)
|
||||
signal channel_cheer(event_dict)
|
||||
#signal channel_raid
|
||||
#signal channel_ban
|
||||
#signal channel_unban
|
||||
#signal channel_moderator_add
|
||||
#signal channel_moderator_remove
|
||||
#signal channel_points_custom_reward_add
|
||||
#signal channel_points_custom_reward_update
|
||||
#signal channel_points_custom_reward_remove
|
||||
signal channel_points_custom_reward_redemption_add(event_dict)
|
||||
signal channel_points_custom_reward_redemption_update(event_dict)
|
||||
#signal channel_poll_begin
|
||||
#signal channel_poll_progress
|
||||
#signal channel_poll_end
|
||||
#signal channel_prediction_begin
|
||||
#signal channel_prediction_progress
|
||||
#signal channel_prediction_lock
|
||||
#signal channel_prediction_end
|
||||
signal channel_charity_campaign_donate(event_dict)
|
||||
#signal channel_charity_campaign_start
|
||||
#signal channel_charity_campaign_progress
|
||||
#signal channel_charity_campaign_stop
|
||||
#signal drop_entitlement_grant
|
||||
signal extension_bits_transaction_create(event_dict)
|
||||
#signal channel_goal_begin
|
||||
#signal channel_goal_progress
|
||||
#signal channel_goal_end
|
||||
#signal channel_hype_train_begin
|
||||
#signal channel_hype_train_progress
|
||||
#signal channel_hype_train_end
|
||||
#signal channel_shield_mode_begin
|
||||
#signal channel_shield_mode_end
|
||||
#signal channel_shoutout_create
|
||||
#signal channel_shoutout_receive
|
||||
#signal stream_online
|
||||
#signal stream_offline
|
||||
#signal user_authorization_grant
|
||||
#signal user_authorization_revoke
|
||||
#signal user_update
|
||||
# Refer to https://dev.twitch.tv/docs/eventsub/eventsub-reference/ data contained in the data dictionary.
|
||||
signal event(type, data)
|
||||
|
||||
@export_category("IRC")
|
||||
|
||||
@ -102,10 +58,6 @@ signal extension_bits_transaction_create(event_dict)
|
||||
## Scopes to request for the token. Look at https://dev.twitch.tv/docs/authentication/scopes/ for a list of all available scopes.
|
||||
@export var scopes : Array[String] = ["chat:edit", "chat:read"]
|
||||
|
||||
@export_category("EventSub")
|
||||
## Events to subscribe to. Make sure you have requested the required scope. Full list available at https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/
|
||||
@export var events : Array[String] = []
|
||||
|
||||
@export_category("Emotes/Badges")
|
||||
|
||||
## If true, caches emotes/badges to disk, so that they don't have to be redownloaded on every restart.
|
||||
@ -148,6 +100,8 @@ var connected : bool = false
|
||||
var user_regex : RegEx = RegEx.new()
|
||||
var twitch_restarting : bool = false
|
||||
|
||||
const USER_AGENT = "User-Agent: GIFT/4.0.0 (Godot Engine)"
|
||||
|
||||
enum RequestType {
|
||||
EMOTE,
|
||||
BADGE,
|
||||
@ -243,6 +197,9 @@ func get_token() -> void:
|
||||
peer.poll()
|
||||
if (peer.get_available_bytes() > 0):
|
||||
var response = peer.get_utf8_string(peer.get_available_bytes())
|
||||
if (response == ""):
|
||||
print("Empty response. Check if your redirect URL is set to http://localhost:18297.")
|
||||
return
|
||||
var start : int = response.find("?")
|
||||
response = response.substr(start + 1, response.find(" ", start) - start)
|
||||
var data : Dictionary = {}
|
||||
@ -269,7 +226,7 @@ func get_token() -> void:
|
||||
peer.disconnect_from_host()
|
||||
var request : HTTPRequest = HTTPRequest.new()
|
||||
add_child(request)
|
||||
request.request("https://id.twitch.tv/oauth2/token", ["User-Agent: GIFT/3.0.0 (Godot Engine)", "Content-Type: application/x-www-form-urlencoded"], HTTPClient.METHOD_POST, "client_id=" + client_id + "&client_secret=" + client_secret + "&code=" + data["code"] + "&grant_type=authorization_code&redirect_uri=http://localhost:18297")
|
||||
request.request("https://id.twitch.tv/oauth2/token", [USER_AGENT, "Content-Type: application/x-www-form-urlencoded"], HTTPClient.METHOD_POST, "client_id=" + client_id + "&client_secret=" + client_secret + "&code=" + data["code"] + "&grant_type=authorization_code&redirect_uri=http://localhost:18297")
|
||||
var answer = await(request.request_completed)
|
||||
if (!DirAccess.dir_exists_absolute("user://gift/auth")):
|
||||
DirAccess.make_dir_recursive_absolute("user://gift/auth")
|
||||
@ -285,7 +242,7 @@ func get_token() -> void:
|
||||
func is_token_valid(token : String) -> String:
|
||||
var request : HTTPRequest = HTTPRequest.new()
|
||||
add_child(request)
|
||||
request.request("https://id.twitch.tv/oauth2/validate", ["User-Agent: GIFT/3.0.0 (Godot Engine)", "Authorization: OAuth " + token])
|
||||
request.request("https://id.twitch.tv/oauth2/validate", [USER_AGENT, "Authorization: OAuth " + token])
|
||||
var data = await(request.request_completed)
|
||||
if (data[1] == 200):
|
||||
var payload : Dictionary = JSON.parse_string(data[3].get_string_from_utf8())
|
||||
@ -392,26 +349,8 @@ func process_event(data : PackedByteArray) -> void:
|
||||
"revocation":
|
||||
events_revoked.emit(payload["subscription"]["type"], payload["subscription"]["status"])
|
||||
"notification":
|
||||
var event : Dictionary = payload["event"]
|
||||
match payload["subscription"]["type"]:
|
||||
"channel.follow":
|
||||
channel_follow.emit(event)
|
||||
"channel.subscribe":
|
||||
channel_subscribe.emit(event)
|
||||
"channel.subscription.gift":
|
||||
channel_subscription_gift.emit(event)
|
||||
"channel.subscription.message":
|
||||
channel_subscription_message.emit(event)
|
||||
"channel.cheer":
|
||||
channel_cheer.emit(event)
|
||||
"channel.charity_campaign.donate":
|
||||
channel_charity_campaign_donate.emit(event)
|
||||
"channel.channel_points_custom_reward_redemption.add":
|
||||
channel_points_custom_reward_redemption_add.emit(event)
|
||||
"channel.channel_points_custom_reward_redemption.update":
|
||||
channel_points_custom_reward_redemption_update.emit(event)
|
||||
"extensions.bits.transaction.create":
|
||||
extension_bits_transaction_create.emit(event)
|
||||
var event_data : Dictionary = payload["event"]
|
||||
event.emit(payload["subscription"]["type"], event_data)
|
||||
|
||||
# Connect to Twitch IRC. Make sure to authenticate first.
|
||||
func connect_to_irc() -> bool:
|
||||
@ -432,28 +371,29 @@ func connect_to_eventsub(url : String = "wss://eventsub-beta.wss.twitch.tv/ws")
|
||||
eventsub.connect_to_url(url)
|
||||
print("Connecting to Twitch EventSub.")
|
||||
await(events_id)
|
||||
for event in events:
|
||||
var request : HTTPRequest = HTTPRequest.new()
|
||||
var version
|
||||
if (event == "channel_follow"):
|
||||
version = "beta"
|
||||
else:
|
||||
version = "1"
|
||||
var data : Dictionary = {}
|
||||
data["type"] = event
|
||||
data["version"] = version
|
||||
data["condition"] = {"broadcaster_user_id":user_id}
|
||||
data["transport"] = {
|
||||
"method":"websocket",
|
||||
"session_id":session_id
|
||||
}
|
||||
add_child(request)
|
||||
request.request("https://api.twitch.tv/helix/eventsub/subscriptions", ["User-Agent: GIFT/3.0.0 (Godot Engine)", "Authorization: Bearer " + token["access_token"], "Client-Id:" + client_id, "Content-Type: application/json"], HTTPClient.METHOD_POST, JSON.stringify(data))
|
||||
var reply : Array = await(request.request_completed)
|
||||
var response : Dictionary = JSON.parse_string(reply[3].get_string_from_utf8())
|
||||
print("Now listening to %s events for broadcaster_id %s." % [response["data"][0]["type"], response["data"][0]["condition"]["broadcaster_user_id"]])
|
||||
events_connected.emit()
|
||||
|
||||
# Refer to https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/ for details on
|
||||
# which API versions are available and which conditions are required.
|
||||
func subscribe_event(event_name : String, version : int, conditions : Dictionary) -> void:
|
||||
var data : Dictionary = {}
|
||||
data["type"] = event_name
|
||||
data["version"] = str(version)
|
||||
data["condition"] = conditions
|
||||
data["transport"] = {
|
||||
"method":"websocket",
|
||||
"session_id":session_id
|
||||
}
|
||||
var request : HTTPRequest = HTTPRequest.new()
|
||||
add_child(request)
|
||||
request.request("https://api.twitch.tv/helix/eventsub/subscriptions", [USER_AGENT, "Authorization: Bearer " + token["access_token"], "Client-Id:" + client_id, "Content-Type: application/json"], HTTPClient.METHOD_POST, JSON.stringify(data))
|
||||
var reply : Array = await(request.request_completed)
|
||||
var response : Dictionary = JSON.parse_string(reply[3].get_string_from_utf8())
|
||||
if (response.has("error")):
|
||||
print("Subscription failed for event '%s'. Error %s (%s): %s" % [event_name, response["status"], response["error"], response["message"]])
|
||||
return
|
||||
print("Now listening to '%s' events." % event_name)
|
||||
|
||||
# Request capabilities from twitch.
|
||||
func request_caps(caps : String = "twitch.tv/commands twitch.tv/tags twitch.tv/membership") -> void:
|
||||
send("CAP REQ :" + caps)
|
||||
|
@ -3,5 +3,5 @@
|
||||
name="Godot IRC For Twitch"
|
||||
description="Godot websocket implementation for Twitch IRC."
|
||||
author="issork"
|
||||
version="3.0.1"
|
||||
version="4.0.0"
|
||||
script="gift.gd"
|
||||
|
Loading…
x
Reference in New Issue
Block a user