mirror of
https://codeberg.org/StreamGraph/StreamGraph.git
synced 2024-11-13 19:49:55 +01:00
Merge branch '0.0.3/irc-nodes' into main
This commit is contained in:
commit
7b0b687ddd
6 changed files with 349 additions and 226 deletions
|
@ -14,7 +14,8 @@ signal welcome_received()
|
||||||
var keepalive_timer := 0
|
var keepalive_timer := 0
|
||||||
var timeout_time : int
|
var timeout_time : int
|
||||||
|
|
||||||
var subscribed_events : Array[Twitch_Connection.EventSub_Subscription]
|
## Dictionary used for storing all the subscribed events in the format "subscription_type : Twitch_Connection.EventSub_Subscription"
|
||||||
|
var subscribed_events : Dictionary
|
||||||
|
|
||||||
|
|
||||||
func _init(owner, timeout : int):
|
func _init(owner, timeout : int):
|
||||||
|
@ -35,7 +36,7 @@ func poll_socket():
|
||||||
|
|
||||||
socket_closed.emit()
|
socket_closed.emit()
|
||||||
close()
|
close()
|
||||||
connect_to_eventsub(subscribed_events)
|
connect_to_eventsub(subscribed_events.values())
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -45,7 +46,10 @@ func connect_to_eventsub(events : Array[Twitch_Connection.EventSub_Subscription]
|
||||||
connect_to_url(eventsub_url)
|
connect_to_url(eventsub_url)
|
||||||
await welcome_received
|
await welcome_received
|
||||||
|
|
||||||
subscribed_events = events
|
for all in events:
|
||||||
|
|
||||||
|
subscribed_events[all.subscription_type] = all
|
||||||
|
|
||||||
|
|
||||||
return await subscribe_to_events(events)
|
return await subscribe_to_events(events)
|
||||||
|
|
||||||
|
@ -68,6 +72,15 @@ func subscribe_to_events(events : Array[Twitch_Connection.EventSub_Subscription]
|
||||||
return responses
|
return responses
|
||||||
|
|
||||||
|
|
||||||
|
func new_eventsub_subscription(info, event_subscription : Twitch_Connection.EventSub_Subscription):
|
||||||
|
|
||||||
|
if !event_subscription in subscribed_events:
|
||||||
|
|
||||||
|
subscribed_events[event_subscription.subscription_type] = event_subscription
|
||||||
|
|
||||||
|
event_subscription.sub_id = info.data.id
|
||||||
|
|
||||||
|
|
||||||
func data_received(packet : PackedByteArray):
|
func data_received(packet : PackedByteArray):
|
||||||
|
|
||||||
var info = JSON.parse_string(packet.get_string_from_utf8())
|
var info = JSON.parse_string(packet.get_string_from_utf8())
|
||||||
|
@ -82,7 +95,6 @@ func data_received(packet : PackedByteArray):
|
||||||
|
|
||||||
"session_ping":
|
"session_ping":
|
||||||
|
|
||||||
print("Ping Received")
|
|
||||||
send_pong(info)
|
send_pong(info)
|
||||||
|
|
||||||
|
|
||||||
|
@ -99,9 +111,3 @@ func data_received(packet : PackedByteArray):
|
||||||
|
|
||||||
print(info)
|
print(info)
|
||||||
|
|
||||||
|
|
||||||
func send_pong(pong):
|
|
||||||
|
|
||||||
pong.metadata.message_type = "session_pong"
|
|
||||||
send_text(str(pong))
|
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,8 @@ signal chat_received_rich(chat_dict)
|
||||||
|
|
||||||
@export var client_id := "qyjg1mtby1ycs5scm1pvctos7yvyc1"
|
@export var client_id := "qyjg1mtby1ycs5scm1pvctos7yvyc1"
|
||||||
@export var redirect_uri := "http://localhost"
|
@export var redirect_uri := "http://localhost"
|
||||||
## Port that the redirect_uri will head to on your local system. Defaults to 80 for most cases. Linux tends to prefer 8000 or possibly 1338
|
## Port that the redirect_uri will head to on your local system. Defaults to 80 for most cases.
|
||||||
|
## Linux tends to prefer 8000 or possibly 1338
|
||||||
@export var redirect_port := "8000"
|
@export var redirect_port := "8000"
|
||||||
|
|
||||||
var auth_url := "https://id.twitch.tv/oauth2/authorize?response_type=token&"
|
var auth_url := "https://id.twitch.tv/oauth2/authorize?response_type=token&"
|
||||||
|
@ -58,8 +59,8 @@ func cache_user_data():
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Handles the basic Twitch Authentication process to request and then later receive a Token (using [method check_auth_peer]).
|
## Handles the basic Twitch Authentication process to request and then later receive a Token
|
||||||
## Returns the authentication URL.
|
## (using [method check_auth_peer]). Returns the authentication URL.
|
||||||
func authenticate_with_twitch(client_id = client_id, scopes : Array[String] = auth_scopes) -> String:
|
func authenticate_with_twitch(client_id = client_id, scopes : Array[String] = auth_scopes) -> String:
|
||||||
auth_server = TCPServer.new()
|
auth_server = TCPServer.new()
|
||||||
auth_scopes = scopes
|
auth_scopes = scopes
|
||||||
|
@ -68,7 +69,9 @@ func authenticate_with_twitch(client_id = client_id, scopes : Array[String] = au
|
||||||
return url
|
return url
|
||||||
|
|
||||||
|
|
||||||
## Sets up the chat connection. Joining 1 room with [param token] as it's "PASS" specifying what account it's on. And the optional [param default_chat] specifying the default room to join. While [param nick] specifies the "nickname" (Not the username on Twitch)
|
## Sets up the chat connection. Joining 1 room with [param token] as it's "PASS" specifying what
|
||||||
|
## account it's on. And the optional [param default_chat] specifying the default room to join.
|
||||||
|
## While [param nick] specifies the "nickname" (Not the username on Twitch)
|
||||||
func setup_chat_connection(default_chat : String = "", token : String = token, request_twitch_info = true, nick = "terribletwitch"):
|
func setup_chat_connection(default_chat : String = "", token : String = token, request_twitch_info = true, nick = "terribletwitch"):
|
||||||
|
|
||||||
chat_socket = chat_socket_class.new(self)
|
chat_socket = chat_socket_class.new(self)
|
||||||
|
@ -90,12 +93,19 @@ func join_channel(channel : String):
|
||||||
chat_socket.join_chat(channel)
|
chat_socket.join_chat(channel)
|
||||||
|
|
||||||
|
|
||||||
|
## Leaves or "PART"s the given [param channel] over IRC. (Sends PART #[param channel])
|
||||||
|
func leave_channel(channel : String):
|
||||||
|
|
||||||
|
chat_socket.leave_chat(channel)
|
||||||
|
|
||||||
|
|
||||||
func send_chat(msg : String, channel : String = ""):
|
func send_chat(msg : String, channel : String = ""):
|
||||||
|
|
||||||
chat_socket.send_chat(msg, channel)
|
chat_socket.send_chat(msg, channel)
|
||||||
|
|
||||||
|
|
||||||
## Sets up an EventSub connection to allow subscribing to EventSub events. Ex. Alerts, Channel Point Redemptions etc.
|
## Sets up an EventSub connection to allow subscribing to EventSub events. Ex. Alerts, Channel Point
|
||||||
|
## Redemptions etc.
|
||||||
func setup_eventsub_connection(events : Array[EventSub_Subscription] = [], timeout_duration : int = 20):
|
func setup_eventsub_connection(events : Array[EventSub_Subscription] = [], timeout_duration : int = 20):
|
||||||
|
|
||||||
eventsub_socket = eventsub_socket_class.new(self, timeout_duration)
|
eventsub_socket = eventsub_socket_class.new(self, timeout_duration)
|
||||||
|
@ -103,6 +113,8 @@ func setup_eventsub_connection(events : Array[EventSub_Subscription] = [], timeo
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
## Adds a new subscription to a given EventSub Event using a [Twitch_Connection.EventSub_Subscription]
|
||||||
|
## to handle the data.
|
||||||
func add_eventsub_subscription(sub_type : EventSub_Subscription):
|
func add_eventsub_subscription(sub_type : EventSub_Subscription):
|
||||||
|
|
||||||
if eventsub_socket == null:
|
if eventsub_socket == null:
|
||||||
|
@ -126,7 +138,7 @@ func subscribe_to_channel_points(user_id : String):
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
return await add_eventsub_subscription(EventSub_Subscription.new("channel.channel_points_custom_reward_redemption.add", {"broadcaster_user_id" : user_id}, eventsub_socket.session_id))
|
return await add_eventsub_subscription(EventSub_Subscription.new("channel.channel_points_custom_reward_redemption.add", {"broadcaster_user_id" : user_id}, eventsub_socket.session_id))
|
||||||
|
|
||||||
|
|
||||||
func _process(delta):
|
func _process(delta):
|
||||||
|
@ -212,7 +224,8 @@ func request_user_info(users : Array[String] = []):
|
||||||
return twitch_request(req_url + user_list)
|
return twitch_request(req_url + user_list)
|
||||||
|
|
||||||
|
|
||||||
## Wrapper function around [method twitch_request] to grab information about a set of channels based off an Array of Channel IDs Ex. stream title, current category, current tags, etc.
|
## Wrapper function around [method twitch_request] to grab information about a set of channels based
|
||||||
|
## off an Array of Channel IDs Ex. stream title, current category, current tags, etc.
|
||||||
func request_channel_info(channels : Array[String] = []):
|
func request_channel_info(channels : Array[String] = []):
|
||||||
|
|
||||||
var req_url := "https://api.twitch.tv/helix/channels?broadcaster_id="
|
var req_url := "https://api.twitch.tv/helix/channels?broadcaster_id="
|
||||||
|
@ -236,7 +249,8 @@ func request_channel_info(channels : Array[String] = []):
|
||||||
return twitch_request(req_url + id_string)
|
return twitch_request(req_url + id_string)
|
||||||
|
|
||||||
|
|
||||||
## Utility function for creating a "state" used for different requests for some extra security as a semi password.
|
## Utility function for creating a "state" used for different requests for some extra security as a
|
||||||
|
## semi password.
|
||||||
func make_state(len : int = 16) -> String:
|
func make_state(len : int = 16) -> String:
|
||||||
|
|
||||||
var crypto = Crypto.new()
|
var crypto = Crypto.new()
|
||||||
|
@ -300,7 +314,9 @@ class HTTPResponse:
|
||||||
|
|
||||||
func request_complete(result: int, response_code: int, headers: PackedStringArray, body: PackedByteArray, http, storage):
|
func request_complete(result: int, response_code: int, headers: PackedStringArray, body: PackedByteArray, http, storage):
|
||||||
|
|
||||||
var info = JSON.parse_string(body.get_string_from_utf8())
|
var info : Dictionary
|
||||||
|
if !body.is_empty():
|
||||||
|
info = JSON.parse_string(body.get_string_from_utf8())
|
||||||
|
|
||||||
info["result"] = result
|
info["result"] = result
|
||||||
info["code"] = response_code
|
info["code"] = response_code
|
||||||
|
@ -311,7 +327,8 @@ class HTTPResponse:
|
||||||
push_error("NoTwitch Twitch API Error: " + str(info))
|
push_error("NoTwitch Twitch API Error: " + str(info))
|
||||||
return
|
return
|
||||||
|
|
||||||
info["data"] = info.data[0]
|
|
||||||
|
info["data"] = info.get("data", [[]])[0]
|
||||||
|
|
||||||
print("Response Received")
|
print("Response Received")
|
||||||
inf_data = info
|
inf_data = info
|
||||||
|
@ -322,17 +339,22 @@ class HTTPResponse:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Data handler class for making it easier to send the data used for EventSub Subscriptions over [member eventsub_socket]
|
## Data handler class for making it easier to send the data used for EventSub Subscriptions over
|
||||||
|
## [member eventsub_socket]
|
||||||
class EventSub_Subscription:
|
class EventSub_Subscription:
|
||||||
|
|
||||||
## Specifies the type of subscription this is representing (Ex. "Channel Update" is channel.update)
|
## Specifies the type of subscription this is representing (Ex. "Channel Update" is channel.update)
|
||||||
var subscription_type : String
|
var subscription_type : String
|
||||||
## Used for setting the "version" the subscription that we're currently using.
|
## Used for setting the "version" the subscription that we're currently using.
|
||||||
var version : String
|
var version : String
|
||||||
## Stores the "condition", AKA the condition for being able to subscribe to this Event. (Ex. The User ID of the channel you're listening to)
|
## Stores the "condition", AKA the condition for being able to subscribe to this Event.
|
||||||
|
## (Ex. The User ID of the channel you're listening to)
|
||||||
var condition : Dictionary
|
var condition : Dictionary
|
||||||
## Holds the "session" ID for this EventSub Subscription. Which is held in [member eventsub_socket.session_id]
|
## Holds the "session" ID for this EventSub Subscription. Which is held in
|
||||||
|
## [member eventsub_socket.session_id]
|
||||||
var session_id : String
|
var session_id : String
|
||||||
|
## Stores the subscription ID returned from the EventSub Subscription API Request
|
||||||
|
var sub_id
|
||||||
|
|
||||||
var method = "websocket"
|
var method = "websocket"
|
||||||
|
|
||||||
|
|
30
classes/deck/nodes/twitch/twitch_join_chat.gd
Normal file
30
classes/deck/nodes/twitch/twitch_join_chat.gd
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
# (c) 2023-present Eroax
|
||||||
|
# (c) 2023-present Yagich
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
extends DeckNode
|
||||||
|
|
||||||
|
|
||||||
|
func _init():
|
||||||
|
name = "Twitch Join Chat"
|
||||||
|
node_type = name.to_snake_case()
|
||||||
|
description = "Simple node to send a premade 'join' message to Twitch IRC allowing you to Join the given Channel and receive messages from it."
|
||||||
|
|
||||||
|
props_to_serialize = []
|
||||||
|
|
||||||
|
# Adds Input port for channel name
|
||||||
|
add_input_port(DeckType.Types.STRING, "Channel", "field")
|
||||||
|
|
||||||
|
# Adds Trigger for leaving the specified channel
|
||||||
|
add_input_port(DeckType.Types.ANY, "Leave Channel", "button")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
func _receive(to_input_port, data: Variant, extra_data: Array = []):
|
||||||
|
|
||||||
|
if to_input_port != 1:
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
Connections.twitch.join_channel(await resolve_input_port_value_async(0))
|
||||||
|
|
30
classes/deck/nodes/twitch/twitch_leave_chat.gd
Normal file
30
classes/deck/nodes/twitch/twitch_leave_chat.gd
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
# (c) 2023-present Eroax
|
||||||
|
# (c) 2023-present Yagich
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
extends DeckNode
|
||||||
|
|
||||||
|
|
||||||
|
func _init():
|
||||||
|
name = "Twitch Leave Chat"
|
||||||
|
node_type = name.to_snake_case()
|
||||||
|
description = "Simple node to send a premade 'leave' message to Twitch IRC. Allowing you to leave the specified channel and stop receiving from it."
|
||||||
|
|
||||||
|
props_to_serialize = []
|
||||||
|
|
||||||
|
# Adds Input port for channel name
|
||||||
|
add_input_port(DeckType.Types.STRING, "Channel", "field")
|
||||||
|
|
||||||
|
# Adds Trigger for leaving the specified channel
|
||||||
|
add_input_port(DeckType.Types.ANY, "Leave Channel", "button")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
func _receive(to_input_port, data: Variant, extra_data: Array = []):
|
||||||
|
|
||||||
|
if to_input_port != 1:
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
Connections.twitch.leave_channel(await resolve_input_port_value_async(0))
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
# (c) 2023-present Eroax
|
||||||
|
# (c) 2023-present Yagich
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
extends DeckNode
|
||||||
|
|
||||||
|
|
||||||
|
func _init():
|
||||||
|
name = "Twitch Remove EventSub Subscription"
|
||||||
|
node_type = name.to_snake_case()
|
||||||
|
description = "Removes the given EventSub Subscription by it's Type."
|
||||||
|
|
||||||
|
props_to_serialize = []
|
||||||
|
|
||||||
|
add_input_port(DeckType.Types.STRING, "Subscription Type", "field")
|
||||||
|
add_input_port(DeckType.Types.ANY, "Remove Subscription", "button")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
func _receive(to_input_port, data: Variant, extra_data: Array = []):
|
||||||
|
|
||||||
|
if !to_input_port == 1:
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
var sub_type = await resolve_input_port_value_async(0)
|
||||||
|
|
||||||
|
Connections.twitch.remove_eventsub_subscription_type(sub_type).response_completed.connect(eventsub_response_received)
|
||||||
|
|
||||||
|
|
||||||
|
func eventsub_response_received(info):
|
||||||
|
|
||||||
|
pass # TODO: Add Error Handling Later
|
||||||
|
|
Loading…
Reference in a new issue