Initial Commit
Initial commit of Code Base.
This commit is contained in:
parent
293b1213e1
commit
c11a4ebbc2
653 changed files with 36893 additions and 1 deletions
461
addons/twitcher/irc/twitch_irc.gd
Normal file
461
addons/twitcher/irc/twitch_irc.gd
Normal file
|
|
@ -0,0 +1,461 @@
|
|||
@icon("res://addons/twitcher/assets/chat-icon.svg")
|
||||
@tool
|
||||
extends Twitcher
|
||||
|
||||
## @deprecated: Twitch plans to remove IRC so use the eventsub solution instead
|
||||
class_name TwitchIRC
|
||||
|
||||
static var log: TwitchLogger = TwitchLogger.new("TwitchIRC")
|
||||
|
||||
## Sent when the bot or moderator removes all messages from the chat room or removes all messages for the specified user.
|
||||
signal received_clearchat(channel_name: String, banned_or_timeout_user: String, tags: TwitchTags.ClearChat)
|
||||
## Sent when the bot removes a single message from the chat room.
|
||||
signal received_clearmsg(channel_name: String, chat_message_removed: String, tags: TwitchTags.ClearMsg)
|
||||
## Sent after the bot authenticates with the server.
|
||||
signal received_global_userstate(tags: TwitchTags.GlobalUserState)
|
||||
## Sent when a channel starts or stops hosting viewers from another channel.
|
||||
signal received_host_target(channel_being_hosted: String, hosting_channel: String, number_of_viewers: int)
|
||||
## Sent to indicate the outcome of an action like banning a user.[br]
|
||||
## handled = when the Twitcher already handled the message.
|
||||
signal received_notice(channel_name: String, message: String, tags: TwitchTags.Notice, handled: bool)
|
||||
## Sent when the Twitch IRC server needs to terminate the connection for maintenance reasons. This gives your bot a chance to perform minimal clean up and save state before the server terminates the connection. The amount of time between receiving the message and the server closing the connection is indeterminate.
|
||||
signal received_reconnect
|
||||
## Sent when the bot joins a channel or when the channel’s chat settings change.
|
||||
signal received_roomstate(channel_name: String, tags: TwitchTags.Roomstate)
|
||||
## Sent when events like someone subscribing to the channel occurs. [br]
|
||||
## - A user subscribes to the channel, re-subscribes to the channel, or gifts a subscription to another user.[br]
|
||||
## - Another broadcaster raids the channel. Raid is a Twitch feature that lets broadcasters send their viewers to another channel to help support and grow other members in the community.[br]
|
||||
## - A viewer milestone is celebrated such as a new viewer chatting for the first time.
|
||||
signal received_usernotice(channel_name: String, message: String, tags: TwitchTags.Usernotice)
|
||||
## Sent when the bot joins a channel or sends a PRIVMSG message.
|
||||
signal received_userstate(channel_name: String, tags: TwitchTags.Userstate)
|
||||
## Sent when a WHISPER message is directed specifically to your bot. Your bot will never receive whispers sent to other users.[br]
|
||||
## from_user - The user that’s sending the whisper message.[br]
|
||||
## to_user - The user that’s receiving the whisper message.
|
||||
signal received_whisper(from_user: String, to_user: String, message: String, tags: TwitchTags.Whisper)
|
||||
## The Twitch IRC server sends this message after a user posts a message to the chat room.
|
||||
signal received_privmsg(channel_name: String, username: String, message: String, tags: TwitchTags.PrivMsg)
|
||||
## When the token isn't valid anymore
|
||||
signal unauthenticated
|
||||
## When the token doesn't have enough permissions to join IRC
|
||||
signal unauthorized
|
||||
## Called when the connection got opened and the authorization was done
|
||||
signal connection_opened
|
||||
## Called when the connection got closed
|
||||
signal connection_closed
|
||||
|
||||
|
||||
enum JoinState {
|
||||
NOT_JOINED, JOINING, JOINED
|
||||
}
|
||||
|
||||
class ChannelData extends RefCounted:
|
||||
|
||||
signal has_joined
|
||||
|
||||
var join_state: JoinState = JoinState.NOT_JOINED
|
||||
var channel_name: String
|
||||
var nodes: Array[TwitchIrcChannel] = []
|
||||
var user_state: TwitchTags.Userstate
|
||||
var room_state: TwitchTags.Roomstate:
|
||||
set(val):
|
||||
room_state = val
|
||||
if join_state != JoinState.JOINED && val != null:
|
||||
join_state = JoinState.JOINED
|
||||
has_joined.emit()
|
||||
|
||||
func _init(channel: String) -> void:
|
||||
channel_name = channel
|
||||
|
||||
func leave() -> void:
|
||||
room_state = null
|
||||
join_state = JoinState.NOT_JOINED
|
||||
for node in nodes: node.leave()
|
||||
|
||||
func is_joined() -> void:
|
||||
if join_state != JoinState.JOINED: await has_joined
|
||||
|
||||
|
||||
class ParsedMessage extends RefCounted:
|
||||
## Parses all of the messages of IRC
|
||||
## Group1: Tags
|
||||
## Group2: Server / To User (Whisper) / From User (Chat)
|
||||
## Group3: Command
|
||||
## Group4: Channel / From User (Whisper)
|
||||
## Group5: Message / Payload
|
||||
var _irc_message_parser_regex = RegEx.create_from_string("(@.*? )?:(.*?)( [A-Z0-9]*)( #?.*?)?( :.*?)?$")
|
||||
|
||||
var tags: String:
|
||||
get: return tags.trim_prefix("@")
|
||||
|
||||
## Server / To User (Whisper) / From User (Chat)
|
||||
var server: String
|
||||
|
||||
var command: String:
|
||||
get: return command.strip_edges()
|
||||
|
||||
## Channel / From User (Whisper)
|
||||
var channel: String:
|
||||
get: return channel.strip_edges().trim_prefix("#")
|
||||
|
||||
## Message / Payload
|
||||
var message: String:
|
||||
get: return message.strip_edges().trim_prefix(":")
|
||||
|
||||
func _init(msg: String) -> void:
|
||||
var matches = _irc_message_parser_regex.search(msg)
|
||||
if matches != null:
|
||||
tags = matches.get_string(1)
|
||||
server = matches.get_string(2)
|
||||
command = matches.get_string(3)
|
||||
channel = matches.get_string(4)
|
||||
message = matches.get_string(5)
|
||||
|
||||
|
||||
class EmoteLocation extends RefCounted:
|
||||
var id : Variant
|
||||
var start : int
|
||||
var end : int
|
||||
var sprite_frames: SpriteFrames
|
||||
|
||||
func _init(emote_id: Variant, start_idx: int, end_idx: int):
|
||||
self.id = emote_id
|
||||
self.start = start_idx
|
||||
self.end = end_idx
|
||||
|
||||
static func smaller(a : EmoteLocation, b : EmoteLocation):
|
||||
return a.start < b.start
|
||||
|
||||
|
||||
@export var setting: TwitchIrcSetting = TwitchIrcSetting.new():
|
||||
set(val):
|
||||
setting = val
|
||||
_client.connection_url = setting.server
|
||||
update_configuration_warnings()
|
||||
@export var token: OAuthToken:
|
||||
set(val):
|
||||
token = val
|
||||
update_configuration_warnings()
|
||||
@export var irc_send_message_delay: int = 360
|
||||
## All connected channels of the bot.
|
||||
## Key: channel_name as StringName | Value: ChannelData
|
||||
var _channels := {}
|
||||
|
||||
## will automatically reconnect in case of authorization problems
|
||||
var _auto_reconnect: bool
|
||||
var _ready_to_send: bool
|
||||
var _client := WebsocketClient.new()
|
||||
|
||||
## Timestamp when the next message should be sent.
|
||||
var _next_message := Time.get_ticks_msec()
|
||||
|
||||
## Messages to send with an interval for disconnection protection
|
||||
## see TwitchIrcSetting.send_message_delay_ms.
|
||||
var _chat_queue : Array[String] = []
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
_client.name = "Websocket"
|
||||
_client.message_received.connect(_data_received)
|
||||
_client.connection_established.connect(_on_connection_established)
|
||||
_client.connection_closed.connect(_on_connection_closed)
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
token.authorized.connect(_on_authorized)
|
||||
add_child(_client)
|
||||
|
||||
|
||||
func _on_authorized() -> void:
|
||||
log.i("Token got authorized reconnect to irc? Client Closed: %s, Auto Reconnect enabled: %s" % [_client.is_closed, _client.auto_reconnect])
|
||||
if _client.is_closed and _auto_reconnect:
|
||||
open_connection()
|
||||
|
||||
|
||||
## Propergated call from TwitchService
|
||||
func do_setup() -> void:
|
||||
await open_connection()
|
||||
log.i("IRC setup")
|
||||
|
||||
|
||||
func open_connection() -> void:
|
||||
_auto_reconnect = true
|
||||
log.i("Irc open connection")
|
||||
await _client.open_connection()
|
||||
|
||||
|
||||
func close_connection() -> void:
|
||||
_auto_reconnect = false
|
||||
_client.close(1000, "intentionally closed")
|
||||
log.i("Irc closed connection")
|
||||
|
||||
|
||||
func _on_connection_established() -> void:
|
||||
_login()
|
||||
_reconnect_to_channels()
|
||||
connection_opened.emit()
|
||||
|
||||
|
||||
func _on_connection_closed() -> void:
|
||||
_ready_to_send = false
|
||||
connection_closed.emit()
|
||||
for channel_name: StringName in _channels:
|
||||
_channels[channel_name].leave()
|
||||
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
if _ready_to_send: _send_messages()
|
||||
|
||||
|
||||
## Sends the login message for authorization pupose and sets an username
|
||||
func _login() -> void:
|
||||
_client.send_text("PASS oauth:%s" % await token.get_access_token())
|
||||
_send("NICK " + setting.username)
|
||||
_send("CAP REQ :" + " ".join(setting.irc_capabilities))
|
||||
|
||||
|
||||
## Reconnect to all channels the bot was joined before (in case programatically joined channels)
|
||||
func _reconnect_to_channels():
|
||||
for channel_name in _channels: join_channel(channel_name)
|
||||
|
||||
|
||||
func _join_channels_on_connect():
|
||||
for channel_name: StringName in setting.auto_join_channels:
|
||||
var channel = join_channel(channel_name)
|
||||
await channel.is_joined()
|
||||
log.i("%s joined" % channel_name)
|
||||
|
||||
|
||||
## Receives data on the websocket aka new messages
|
||||
func _data_received(data : PackedByteArray) -> void:
|
||||
var messages : PackedStringArray = data.get_string_from_utf8().strip_edges(false).split("\r\n")
|
||||
for message: String in messages:
|
||||
# Reminder PONG messages is just different cant use match for it...
|
||||
if message.begins_with("PING"):
|
||||
_send("PONG :tmi.twitch.tv")
|
||||
continue
|
||||
|
||||
var parsed_message = ParsedMessage.new(message)
|
||||
_handle_message(parsed_message)
|
||||
|
||||
|
||||
## Tries to send messages as long as the websocket is open
|
||||
func _send_messages() -> void:
|
||||
if _chat_queue.is_empty():
|
||||
return
|
||||
|
||||
if not _client.is_open:
|
||||
log.e("Can't send message. Connection not open.")
|
||||
# Maybe buggy when the websocket got opened but not authorized yet
|
||||
# Can possible happen when we have a lot of load and a reconnect in the socket
|
||||
return
|
||||
|
||||
if _next_message <= Time.get_ticks_msec():
|
||||
var msg_to_send = _chat_queue.pop_front()
|
||||
_send(msg_to_send)
|
||||
_next_message = Time.get_ticks_msec() + irc_send_message_delay
|
||||
|
||||
|
||||
## Sends join channel message
|
||||
func join_channel(channel_name : StringName) -> ChannelData:
|
||||
var lower_channel = channel_name.to_lower()
|
||||
if not _channels.has(channel_name):
|
||||
_channels[channel_name] = ChannelData.new(lower_channel)
|
||||
|
||||
if _channels[channel_name].join_state == JoinState.NOT_JOINED:
|
||||
_chat_queue.append("JOIN #" + lower_channel)
|
||||
_channels[channel_name].join_state = JoinState.JOINING
|
||||
|
||||
return _channels[channel_name]
|
||||
|
||||
|
||||
## Sends leave channel message
|
||||
func leave_channel(channel_name : StringName) -> void:
|
||||
if not _channels.has(channel_name):
|
||||
log.e("Can't leave %s channel cause we are not joined" % channel_name)
|
||||
return
|
||||
|
||||
var lower_channel : StringName = channel_name.to_lower()
|
||||
_chat_queue.append("PART #" + lower_channel)
|
||||
_channels.erase(lower_channel)
|
||||
|
||||
|
||||
## Sends a chat message to a channel. Defaults to the only connected channel.
|
||||
## Channel should be always without '#'.
|
||||
func chat(message : String, channel_name : StringName = &""):
|
||||
var channel_names : Array = _channels.keys()
|
||||
if channel_name == &"" && channel_names.size() == 1:
|
||||
channel_name = channel_names[0]
|
||||
|
||||
if channel_name == &"":
|
||||
log.e("No channel is specified to send %s" % message)
|
||||
return
|
||||
|
||||
_chat_queue.append("PRIVMSG #%s :%s\r\n" % [channel_name, message])
|
||||
|
||||
# Call it defered otherwise the response of the bot will be send before the command.
|
||||
_send_message_to_channel.call_deferred(channel_name, message)
|
||||
|
||||
|
||||
## send the message of the bot to the channel for display purpose
|
||||
func _send_message_to_channel(channel_name: StringName, message: String) -> void:
|
||||
if _channels.has(channel_name):
|
||||
var channel = _channels[channel_name] as ChannelData
|
||||
var username = channel.user_state.display_name
|
||||
# Convert the tags in a dirty way
|
||||
var tag = TwitchTags.PrivMsg.new(channel.user_state._raw)
|
||||
tag.room_id = channel.room_state.room_id
|
||||
received_privmsg.emit(channel_name, username, message, tag)
|
||||
|
||||
|
||||
## Sends a string message to Twitch.
|
||||
func _send(text : String) -> void:
|
||||
_client.send_text(text)
|
||||
log.i("< " + text.strip_edges(false))
|
||||
|
||||
|
||||
## Handles all the messages. Tags can be empty when not requested via capabilities
|
||||
func _handle_message(parsed_message : ParsedMessage) -> void:
|
||||
if parsed_message.command != "WHISPER":
|
||||
log.i("> [%15s] %s: %s" % [parsed_message.command, parsed_message.server, parsed_message.message])
|
||||
|
||||
match parsed_message.command:
|
||||
"001":
|
||||
log.i("Authentication successful.")
|
||||
_join_channels_on_connect()
|
||||
_ready_to_send = true
|
||||
|
||||
"CLEARCHAT":
|
||||
var clear_chat_tags = TwitchTags.ClearChat.new(parsed_message.tags)
|
||||
var user_to_ban_or_timeout = parsed_message.message
|
||||
received_clearchat.emit(parsed_message.channel, parsed_message.message, clear_chat_tags)
|
||||
|
||||
"CLEARMSG":
|
||||
var clear_msg_tags = TwitchTags.ClearMsg.new(parsed_message.tags)
|
||||
var message_to_remove = parsed_message.message
|
||||
received_clearmsg.emit(parsed_message.channel, message_to_remove, clear_msg_tags)
|
||||
|
||||
"GLOBALUSERSTATE":
|
||||
var global_userstate = TwitchTags.GlobalUserState.new(parsed_message.tags)
|
||||
received_global_userstate.emit(global_userstate)
|
||||
|
||||
"HOSTTARGET":
|
||||
# Example: [-|<channel>] <number-of-viewers>
|
||||
var host_target_message = parsed_message.message.split(" ")
|
||||
var channel_being_hosted = host_target_message[0]
|
||||
var number_of_viewers = int(host_target_message[1])
|
||||
var hosting_channel = parsed_message.channel
|
||||
received_host_target.emit(channel_being_hosted, hosting_channel, number_of_viewers)
|
||||
|
||||
"NOTICE":
|
||||
var notice_tags = TwitchTags.Notice.new(parsed_message.tags)
|
||||
var message = parsed_message.message
|
||||
var handled := false
|
||||
if not await _handle_cmd_notice(message):
|
||||
handled = true
|
||||
received_notice.emit(parsed_message.channel, message, notice_tags, handled)
|
||||
|
||||
"RECONNECT":
|
||||
received_reconnect.emit()
|
||||
|
||||
"ROOMSTATE":
|
||||
var roomstate_tags = TwitchTags.Roomstate.new(parsed_message.tags)
|
||||
var channel_name = parsed_message.channel
|
||||
received_roomstate.emit(channel_name, roomstate_tags)
|
||||
|
||||
var channel = _channels[channel_name] as ChannelData
|
||||
channel.room_state = roomstate_tags
|
||||
|
||||
"USERNOTICE":
|
||||
var user_notice_tags = TwitchTags.Usernotice.new(parsed_message.tags)
|
||||
received_usernotice.emit(parsed_message.channel, parsed_message.message, user_notice_tags)
|
||||
|
||||
"USERSTATE":
|
||||
var userstate_tags = TwitchTags.Userstate.new(parsed_message.tags)
|
||||
var channel_name = parsed_message.channel
|
||||
received_usernotice.emit(channel_name, userstate_tags)
|
||||
|
||||
var channel = _channels[channel_name] as ChannelData
|
||||
channel.user_state = userstate_tags
|
||||
|
||||
"WHISPER":
|
||||
var whisper_tags = TwitchTags.Whisper.new(parsed_message.tags)
|
||||
# Example: :<to-user>!<to-user>@<to-user>.tmi.twitch.tv
|
||||
var to_user = parsed_message.server
|
||||
to_user = to_user.substr(0, to_user.find("!"))
|
||||
# Special case for whisper
|
||||
var from_user = parsed_message.channel
|
||||
received_whisper.emit(from_user, to_user, parsed_message.message, whisper_tags)
|
||||
|
||||
"PRIVMSG":
|
||||
var privmsg_tags = TwitchTags.PrivMsg.new(parsed_message.tags)
|
||||
var from_user = parsed_message.server
|
||||
from_user = from_user.substr(0, from_user.find("!"))
|
||||
received_privmsg.emit(parsed_message.channel, from_user, parsed_message.message, privmsg_tags)
|
||||
|
||||
|
||||
## Handles the update of rooms when joining the channel or a moderator
|
||||
## updates it (Example :tmi.twitch.tv ROOMSTATE #bar)
|
||||
func _handle_cmd_state(command: String, channel_name: StringName, tags: Dictionary) -> void:
|
||||
# right(-1) -> Remove the preceding # of the channel name
|
||||
channel_name = channel_name.right(-1).to_lower()
|
||||
if not _channels.has(channel_name):
|
||||
_channels[channel_name] = _create_channel(channel_name)
|
||||
|
||||
var channel: TwitchIrcChannel = _channels[channel_name]
|
||||
channel.update_state(command, tags)
|
||||
#channel_data_updated.emit(channel_name, channel.data)
|
||||
log.i("Channel updated %s" % channel_name)
|
||||
|
||||
|
||||
func _create_channel(channel_name: StringName) -> TwitchIrcChannel:
|
||||
var channel = TwitchIrcChannel.new()
|
||||
channel.channel_name = channel_name
|
||||
_channels[channel_name] = channel
|
||||
Engine.get_main_loop().root.add_child(channel)
|
||||
return channel
|
||||
|
||||
|
||||
## Tracks the channel.
|
||||
func add_channel(channel: TwitchIrcChannel):
|
||||
var channel_name = channel.channel_name
|
||||
if not _channels.has(channel_name):
|
||||
join_channel(channel_name)
|
||||
var nodes = _channels[channel_name].nodes as Array[TwitchIrcChannel]
|
||||
nodes.append(channel)
|
||||
|
||||
|
||||
## Remove the channel from getting tracked within the service
|
||||
func remove_channel(channel: TwitchIrcChannel):
|
||||
var channel_name = channel.channel_name
|
||||
var channel_data = _channels[channel_name] as ChannelData
|
||||
channel_data.nodes.erase(channel)
|
||||
if channel_data.nodes.is_empty():
|
||||
leave_channel(channel_name)
|
||||
|
||||
|
||||
func _handle_cmd_notice(info: String) -> bool:
|
||||
if info == "Login authentication failed" || info == "Login unsuccessful":
|
||||
log.e("Authentication failed.")
|
||||
unauthenticated.emit()
|
||||
_client.close(1000, "Unauthenticated.")
|
||||
return true
|
||||
elif info == "You don't have permission to perform that action":
|
||||
log.i("No permission. Please check if you have all required scopes (chat:read or chat:write).")
|
||||
unauthorized.emit()
|
||||
_client.close(1000, "Token became invalid.")
|
||||
return true
|
||||
return false
|
||||
|
||||
|
||||
func get_client() -> WebsocketClient:
|
||||
return _client
|
||||
|
||||
|
||||
func _get_configuration_warnings() -> PackedStringArray:
|
||||
var result: Array[String] = []
|
||||
if token == null:
|
||||
result.append("Token is missing")
|
||||
if setting == null:
|
||||
result.append("IRC Settings are missing")
|
||||
return result
|
||||
1
addons/twitcher/irc/twitch_irc.gd.uid
Normal file
1
addons/twitcher/irc/twitch_irc.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://wkh0l2xsyapj
|
||||
110
addons/twitcher/irc/twitch_irc_channel.gd
Normal file
110
addons/twitcher/irc/twitch_irc_channel.gd
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
@icon("res://addons/twitcher/assets/chat-icon.svg")
|
||||
extends Twitcher
|
||||
|
||||
## Direct access to the chat for one specific channel
|
||||
##
|
||||
## Usefull when using multiple channels otherwise TwitchIRC has everything you need
|
||||
## This one exists only for tracking user join and leave events.
|
||||
## ## @deprecated: Twitch plans to remove IRC so use the eventsub solution instead
|
||||
class_name TwitchIrcChannel
|
||||
|
||||
static var _log: TwitchLogger = TwitchLogger.new("TwitchIrcChannel")
|
||||
|
||||
## when a chat message in this channel got received
|
||||
signal message_received(from_user: String, message: String, tags: TwitchTags.Message)
|
||||
|
||||
## Sent when the bot joins a channel or sends a PRIVMSG message.
|
||||
signal user_state_received(tags: TwitchTags.Userstate)
|
||||
|
||||
## Sent when the bot joins a channel or when the channel’s chat settings change.
|
||||
signal room_state_received(tags: TwitchTags.Roomstate)
|
||||
|
||||
## Called when the bot joined the channel or atleast get the channel informations.
|
||||
signal has_joined()
|
||||
|
||||
## Called when thie bot left the channel.
|
||||
signal has_left()
|
||||
|
||||
@export var twitch_service: TwitchService
|
||||
@export var channel_name: StringName:
|
||||
set = _update_channel_name,
|
||||
get = _get_channel_name
|
||||
|
||||
var user_state: TwitchTags.Userstate
|
||||
var room_state: TwitchTags.Roomstate:
|
||||
set(val):
|
||||
room_state = val
|
||||
if !joined && val != null:
|
||||
joined = true
|
||||
has_joined.emit()
|
||||
|
||||
var joined: bool
|
||||
var irc: TwitchIRC
|
||||
|
||||
|
||||
func _enter_tree() -> void:
|
||||
_enter_channel()
|
||||
|
||||
|
||||
func _get_channel_name() -> StringName:
|
||||
return channel_name.to_lower()
|
||||
|
||||
|
||||
func _update_channel_name(new_name: StringName) -> void:
|
||||
if channel_name != "": irc.remove_channel(self)
|
||||
channel_name = new_name
|
||||
_enter_channel()
|
||||
|
||||
|
||||
func _enter_channel() -> void:
|
||||
if irc == null: return
|
||||
if channel_name == &"":
|
||||
_log.e("No channel is specified to join. The channel name can be set on the TwitchIrcChannel node.")
|
||||
return
|
||||
irc.add_channel(self)
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
irc = twitch_service.irc
|
||||
irc.received_privmsg.connect(_on_message_received)
|
||||
irc.received_roomstate.connect(_on_roomstate_received)
|
||||
irc.received_userstate.connect(_on_userstate_received)
|
||||
_enter_channel()
|
||||
|
||||
|
||||
func _exit_tree() -> void:
|
||||
irc.remove_channel(self)
|
||||
|
||||
|
||||
func _on_message_received(channel: StringName, from_user: String, message: String, tags: TwitchTags.PrivMsg):
|
||||
if channel_name != channel: return
|
||||
var message_tag = TwitchTags.Message.from_priv_msg(tags)
|
||||
await message_tag.load_sprites(twitch_service)
|
||||
message_received.emit(from_user, message, message_tag)
|
||||
|
||||
|
||||
func _on_roomstate_received(channel: StringName, tags: TwitchTags.Roomstate):
|
||||
if channel != channel_name: return
|
||||
room_state = tags
|
||||
room_state_received.emit(room_state)
|
||||
|
||||
|
||||
func _on_userstate_received(channel: StringName, tags: TwitchTags.Userstate):
|
||||
if channel != channel_name: return
|
||||
user_state = tags
|
||||
user_state_received.emit(user_state)
|
||||
|
||||
|
||||
func chat(message: String) -> void:
|
||||
await is_joined()
|
||||
irc.chat(message, channel_name)
|
||||
|
||||
|
||||
func is_joined() -> void:
|
||||
if not joined: await has_joined
|
||||
|
||||
|
||||
func leave() -> void:
|
||||
room_state = null
|
||||
joined = false
|
||||
has_left.emit()
|
||||
1
addons/twitcher/irc/twitch_irc_channel.gd.uid
Normal file
1
addons/twitcher/irc/twitch_irc_channel.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://cva5e053boj4u
|
||||
38
addons/twitcher/irc/twitch_irc_setting.gd
Normal file
38
addons/twitcher/irc/twitch_irc_setting.gd
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
extends Resource
|
||||
|
||||
## @deprecated: Twitch plans to remove IRC so use the eventsub solution instead
|
||||
class_name TwitchIrcSetting
|
||||
|
||||
const CAP_COMMANDS := &"twitch.tv/commands"
|
||||
const CAP_MEMBERSHIP := &"twitch.tv/membership"
|
||||
const CAP_TAGS := &"twitch.tv/tags"
|
||||
|
||||
|
||||
## The name of the bot within the chat
|
||||
@export var username := ""
|
||||
|
||||
## Join the channels after connect
|
||||
@export var auto_join_channels: Array[StringName] = []
|
||||
|
||||
## Twitch IRC Server URL
|
||||
@export var server := "wss://irc-ws.chat.twitch.tv:443"
|
||||
|
||||
## Needed because IRC may disconnect on to many message per second
|
||||
@export var send_message_delay_ms := 320
|
||||
|
||||
@export_flags(CAP_COMMANDS, CAP_MEMBERSHIP, CAP_TAGS) var capabilities := 0
|
||||
|
||||
var irc_capabilities: Array[StringName]:
|
||||
get():
|
||||
var result : Array[StringName] = []
|
||||
if capabilities & 1 == 1:
|
||||
result.append(CAP_COMMANDS)
|
||||
if capabilities & 2 == 2:
|
||||
result.append(CAP_MEMBERSHIP)
|
||||
if capabilities & 4 == 4:
|
||||
result.append(CAP_TAGS)
|
||||
return result
|
||||
|
||||
|
||||
static func get_all_capabillities() -> Array[StringName]:
|
||||
return [CAP_COMMANDS, CAP_MEMBERSHIP, CAP_TAGS];
|
||||
1
addons/twitcher/irc/twitch_irc_setting.gd.uid
Normal file
1
addons/twitcher/irc/twitch_irc_setting.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://c8mv0lq0a2l8f
|
||||
469
addons/twitcher/irc/twitch_tags.gd
Normal file
469
addons/twitcher/irc/twitch_tags.gd
Normal file
|
|
@ -0,0 +1,469 @@
|
|||
extends RefCounted
|
||||
|
||||
class_name TwitchTags
|
||||
|
||||
## A normal user
|
||||
const USER_TYPE_NORMA := &""
|
||||
## A Twitch administrator
|
||||
const USER_TYPE_ADMIN := &"admin"
|
||||
## A global moderator
|
||||
const USER_TYPE_GLOBAL_MOD := &"global_mod"
|
||||
## A Twitch employee
|
||||
const USER_TYPE_STAFF := &"staff"
|
||||
|
||||
const MSG_ID_SUB := &"sub"
|
||||
const MSG_ID_RESUB := &"resub"
|
||||
const MSG_ID_SUBGIFT := &"subgift"
|
||||
const MSG_ID_SUBMYSTERYGIFT := &"submysterygift"
|
||||
const MSG_ID_GIFTPAIDUPGRADE := &"giftpaidupgrade"
|
||||
const MSG_ID_REWARDGIFT := &"rewardgift"
|
||||
const MSG_ID_ANONGIFTPAIDUPGRADE := &"anongiftpaidupgrade"
|
||||
const MSG_ID_RAID := &"raid"
|
||||
const MSG_ID_UNRAID := &"unraid"
|
||||
const MSG_ID_RITUAL := &"ritual"
|
||||
const MSG_ID_BITSBADGETIER := &"bitsbadgetier"
|
||||
#region TagWrapper
|
||||
|
||||
class Message extends RefCounted:
|
||||
var color: String
|
||||
var _badges: String
|
||||
var _emotes: String
|
||||
var room_id: String
|
||||
var raw: Variant
|
||||
|
||||
var badges: Array[SpriteFrames]
|
||||
var emotes: Array[TwitchIRC.EmoteLocation]
|
||||
|
||||
|
||||
static func from_priv_msg(tag: PrivMsg) -> Message:
|
||||
var msg = Message.new()
|
||||
msg.color = tag.color
|
||||
msg._badges = tag.badges
|
||||
msg._emotes = tag.emotes
|
||||
msg.room_id = tag.room_id
|
||||
msg.raw = tag
|
||||
return msg
|
||||
|
||||
|
||||
func load_sprites(twitch_service: TwitchService) -> void:
|
||||
badges = await _load_badges(twitch_service)
|
||||
emotes = await _load_emotes(twitch_service)
|
||||
pass
|
||||
|
||||
|
||||
func _load_badges(twitch_service: TwitchService) -> Array[SpriteFrames]:
|
||||
var badge_definitions : Array[TwitchBadgeDefinition] = []
|
||||
for badge in _badges.split(",", false):
|
||||
# Maybe Broke?!
|
||||
var badge_info := badge.split("/")
|
||||
var badge_definition = TwitchBadgeDefinition.new(badge_info[0], badge_info[1], 1, room_id)
|
||||
badge_definitions.append(badge_definition)
|
||||
var result = await twitch_service.media_loader.get_badges(badge_definitions)
|
||||
var sprite_frames : Array[SpriteFrames] = []
|
||||
sprite_frames.assign(result.values())
|
||||
return sprite_frames
|
||||
|
||||
|
||||
func _load_emotes(twitch_service: TwitchService) -> Array[TwitchIRC.EmoteLocation]:
|
||||
var locations : Array[TwitchIRC.EmoteLocation] = []
|
||||
var emotes_to_load : Array[String] = []
|
||||
if _emotes != null && _emotes != "":
|
||||
for emote in _emotes.split("/", false):
|
||||
var data : Array = emote.split(":")
|
||||
for d in data[1].split(","):
|
||||
var start_end = d.split("-")
|
||||
locations.append(TwitchIRC.EmoteLocation.new(data[0], int(start_end[0]), int(start_end[1])))
|
||||
emotes_to_load.append(data[0])
|
||||
locations.sort_custom(Callable(TwitchIRC.EmoteLocation, "smaller"))
|
||||
|
||||
var emotes_definition: Dictionary = await twitch_service.media_loader.get_emotes(emotes_to_load)
|
||||
for emote_location: TwitchIRC.EmoteLocation in locations:
|
||||
emote_location.sprite_frames = emotes_definition[emote_location.id]
|
||||
|
||||
return locations
|
||||
|
||||
|
||||
|
||||
func get_color() -> String:
|
||||
return color
|
||||
|
||||
#endregion
|
||||
|
||||
#region Lowlevel Tags
|
||||
|
||||
class BaseTags:
|
||||
var _raw: String
|
||||
var _unmapped: Dictionary = {}
|
||||
|
||||
|
||||
func parse_tags(tag_string: String, output: Object) -> void:
|
||||
_raw = tag_string
|
||||
if tag_string.left(1) == "@":
|
||||
tag_string = tag_string.substr(1)
|
||||
|
||||
var tags = tag_string.split(";")
|
||||
for tag in tags:
|
||||
if tag == "": continue
|
||||
var tag_value = tag.split("=")
|
||||
var property_name = tag_value[0].replace("-", "_")
|
||||
if _has_property(output, property_name):
|
||||
output.set(property_name, tag_value[1])
|
||||
elif tag_value.size() == 2:
|
||||
output._unmapped[property_name] = tag_value[1]
|
||||
else:
|
||||
output._unmapped[property_name] = ""
|
||||
|
||||
|
||||
func _has_property(obj: Object, property_name: String) -> bool:
|
||||
var properties = obj.get_property_list()
|
||||
for property in properties:
|
||||
if property.name == property_name:
|
||||
return true
|
||||
return false
|
||||
|
||||
|
||||
func get_unmapped(property: String) -> Variant:
|
||||
return _unmapped[property]
|
||||
|
||||
|
||||
func has_unmapped(property: String) -> bool:
|
||||
return _unmapped.has(property)
|
||||
|
||||
## Sent when the bot or moderator removes all messages from the chat room or removes all messages for the specified user. [br]
|
||||
## @ban-duration=<duration>;room-id=<room-id>;target-user-id=<user-id>;tmi-sent-ts=<timestamp> [br]
|
||||
## See: https://dev.twitch.tv/docs/irc/tags/#clearchat-tags
|
||||
class ClearChat extends BaseTags:
|
||||
## Optional. The message includes this tag if the user was put in a timeout. The tag contains the duration of the timeout, in seconds.
|
||||
var ban_duration: String
|
||||
## The ID of the channel where the messages were removed from.
|
||||
var room_id: String
|
||||
## Optional. The ID of the user that was banned or put in a timeout. The user was banned if the message doesn’t include the ban-duration tag.
|
||||
var target_user_id: String
|
||||
## The UNIX timestamp.
|
||||
var tmi_sent_ts: String
|
||||
|
||||
|
||||
func _init(tags: String) -> void:
|
||||
parse_tags(tags, self)
|
||||
|
||||
|
||||
## Sent when the bot removes a single message from the chat room. [br]
|
||||
## @login=<login>;room-id=<room-id>;target-msg-id=<target-msg-id>;tmi-sent-ts=<timestamp> [br]
|
||||
## See: https://dev.twitch.tv/docs/irc/tags/#clearmsg-tags
|
||||
class ClearMsg extends BaseTags:
|
||||
## The name of the user who sent the message.
|
||||
var login: String
|
||||
## Optional. The ID of the channel (chat room) where the message was removed from.
|
||||
var room_id: String
|
||||
## A UUID that identifies the message that was removed.
|
||||
var target_msg_id: String
|
||||
## The UNIX timestamp.
|
||||
var tmi_sent_ts: String
|
||||
|
||||
|
||||
func _init(tags: String) -> void:
|
||||
parse_tags(tags, self)
|
||||
|
||||
|
||||
## Sent when the bot authenticates with the server. [br]
|
||||
## @badge-info=<badge-info>;badges=<badges>;color=<color>;display-name=<display-name>;emote-sets=<emote-sets>;turbo=<turbo>;user-id=<user-id>;user-type=<user-type> [br]
|
||||
## See https://dev.twitch.tv/docs/irc/tags/#globaluserstate-tags
|
||||
class GlobalUserState extends BaseTags:
|
||||
## Contains metadata related to the chat badges in the badges tag. [br]
|
||||
## Currently, this tag contains metadata only for subscriber badges, to indicate the number of months the user has been a subscriber.
|
||||
var badge_info: String
|
||||
## Comma-separated list of chat badges in the form, <badge>/<version>. For example, admin/1. There are many possible badge values.
|
||||
var badges: String
|
||||
## The color of the user’s name in the chat room. This is a hexadecimal RGB color code in the form, #<RGB>. This tag may be empty if it is never set.
|
||||
var color: String
|
||||
## The user’s display name, escaped as described in the IRCv3 spec. This tag may be empty if it is never set.
|
||||
var display_name: String
|
||||
## A comma-delimited list of IDs that identify the emote sets that the user has access to. Is always set to at least zero (0). To access the emotes in the set, use the Get Emote Sets API.
|
||||
var emote_sets: String
|
||||
## A Boolean value that indicates whether the user has site-wide commercial free mode enabled. Is true (1) if enabled; otherwise, false (0).
|
||||
var turbo: String
|
||||
## The user’s ID.
|
||||
var user_id: String
|
||||
## The type of user. See TwitchTags.USER_TYPE_*
|
||||
var user_type: String
|
||||
|
||||
|
||||
func _init(tags: String) -> void:
|
||||
parse_tags(tags, self)
|
||||
|
||||
|
||||
## Sent to indicate the outcome of an action like banning a user. [br]
|
||||
## @msg-id=<msg-id>;target-user-id=<user-id> [br]
|
||||
## See: https://dev.twitch.tv/docs/irc/tags/#notice-tags
|
||||
class Notice extends BaseTags:
|
||||
## An ID that you can use to programmatically determine the action’s outcome. For a list of possible IDs, see NOTICE Message IDs.
|
||||
var msg_id: String
|
||||
## The ID of the user that the action targeted.
|
||||
var target_user_id: String
|
||||
|
||||
|
||||
func _init(tags: String) -> void:
|
||||
parse_tags(tags, self)
|
||||
|
||||
|
||||
## Sent when a user posts a message to the chat room. [br]
|
||||
## @badge-info=<badge-info>;badges=<badges>;bits=<bits>client-nonce=<nonce>;color=<color>;display-name=<display-name>;emotes=<emotes>;first-msg=<first-msg>;flags=<flags>;id=<msg-id>;mod=<mod>;room-id=<room-id>;subscriber=<subscriber>;tmi-sent-ts=<timestamp>;turbo=<turbo>;user-id=<user-id>;user-type=<user-type>;reply-parent-msg-id=<reply-parent-msg-id>;reply-parent-user-id=<reply-parent-user-id>;reply-parent-user-login=<reply-parent-user-login>;reply-parent-display-name=<reply-parent-display-name>;reply-parent-msg-body=<reply-parent-msg-body>;reply-thread-parent-msg-id=<reply-thread-parent-msg-id>;reply-thread-parent-user-login=<reply-thread-parent-user-login>;vip=<vip> [br]
|
||||
## See: https://dev.twitch.tv/docs/irc/tags/#privmsg-tags
|
||||
class PrivMsg extends BaseTags:
|
||||
## Contains metadata related to the chat badges in the badges tag. [br]
|
||||
##Currently, this tag contains metadata only for subscriber badges, to indicate the number of months the user has been a subscriber.
|
||||
var badge_info: String
|
||||
## Comma-separated list of chat badges in the form, <badge>/<version>. For example, admin/1. There are many possible badge values,
|
||||
var badges: String
|
||||
## The amount of Bits the user cheered. Only a Bits cheer message includes this tag. To learn more about Bits, see the Extensions Monetization Guide. To get the cheermote, use the Get Cheermotes API. Match the cheer amount to the id field’s value in the response. Then, get the cheermote’s URL based on the cheermote theme, type, and size you want to use.
|
||||
var bits: String
|
||||
## The color of the user’s name in the chat room. This is a hexadecimal RGB color code in the form, #<RGB>. This tag may be empty if it is never set.
|
||||
var color: String
|
||||
## The user’s display name, escaped as described in the IRCv3 spec. This tag may be empty if it is never set.
|
||||
var display_name: String
|
||||
## A comma-delimited list of emotes and their positions in the message. Each emote is in the form, <emote ID>:<start position>-<end position>. The position indices are zero-based.
|
||||
var emotes: String
|
||||
## An ID that uniquely identifies the message.
|
||||
var id: String
|
||||
## A Boolean value that determines whether the user is a moderator. Is true (1) if the user is a moderator otherwise, false (0).
|
||||
var mod: String
|
||||
## The value of the Hype Chat sent by the user.
|
||||
var pinned_chat_paid_amount: String
|
||||
## The ISO 4217 alphabetic currency code the user has sent the Hype Chat in.
|
||||
var pinned_chat_paid_currency: String
|
||||
## Indicates how many decimal points this currency represents partial amounts in. Decimal points start from the right side of the value defined in pinned-chat-paid-amount.
|
||||
var pinned_chat_paid_exponent: String
|
||||
## The level of the Hype Chat, in English. Possible values are: ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN
|
||||
var pinned_chat_paid_level: String
|
||||
##A Boolean value that determines if the message sent with the Hype Chat was filled in by the system. [br]
|
||||
##If true (1), the user entered no message and the body message was automatically filled in by the system. [br]
|
||||
##If false (0), the user provided their own message to send with the Hype Chat.
|
||||
var pinned_chat_paid_is_system_message: String
|
||||
## An ID that uniquely identifies the direct parent message that this message is replying to. The message does not include this tag if this message is not a reply.
|
||||
var reply_parent_msg_id: String
|
||||
## An ID that identifies the sender of the direct parent message. The message does not include this tag if this message is not a reply.
|
||||
var reply_parent_user_id: String
|
||||
## The login name of the sender of the direct parent message. The message does not include this tag if this message is not a reply.
|
||||
var reply_parent_user_login: String
|
||||
## The display name of the sender of the direct parent message. The message does not include this tag if this message is not a reply.
|
||||
var reply_parent_display_name: String
|
||||
## The text of the direct parent message. The message does not include this tag if this message is not a reply.
|
||||
var reply_parent_msg_body: String
|
||||
## An ID that uniquely identifies the top-level parent message of the reply thread that this message is replying to. The message does not include this tag if this message is not a reply.
|
||||
var reply_thread_parent_msg_id: String
|
||||
## The login name of the sender of the top-level parent message. The message does not include this tag if this message is not a reply.
|
||||
var reply_thread_parent_user_login: String
|
||||
## An ID that identifies the chat room (channel).
|
||||
var room_id: String
|
||||
## A Boolean value that determines whether the user is a subscriber. Is true (1) if the user is a subscriber otherwise, false (0).
|
||||
var subscriber: String
|
||||
## The UNIX timestamp.
|
||||
var tmi_sent_ts: String
|
||||
## A Boolean value that indicates whether the user has site-wide commercial free mode enabled. Is true (1) if enabled otherwise, false (0).
|
||||
var turbo: String
|
||||
## The user’s ID.
|
||||
var user_id: String
|
||||
## The type of user. See TwitchTags.USER_TYPE_*
|
||||
var user_type: String
|
||||
## A Boolean value that determines whether the user that sent the chat is a VIP. The message includes this tag if the user is a VIP otherwise, the message doesn’t include this tag (check for the presence of the tag instead of whether the tag is set to true or false).
|
||||
var vip: String
|
||||
## Not documented by Twitch.
|
||||
var first_msg: String
|
||||
## Not documented by Twitch.
|
||||
var client_nonce: String
|
||||
|
||||
|
||||
func _init(tags: String) -> void:
|
||||
parse_tags(tags, self)
|
||||
|
||||
|
||||
## Sent when the bot joins a channel or when the channel’s chat room settings change. [br]
|
||||
## @emote-only=<emote-only>;followers-only=<followers-only>;r9k=<r9k>;rituals=<rituals>;room-id=<room-id>;slow=<slow>;subs-only=<subs-only> [br]
|
||||
## See: https://dev.twitch.tv/docs/irc/tags/#roomstate-tags
|
||||
class Roomstate extends BaseTags:
|
||||
## A Boolean value that determines whether the chat room allows only messages with emotes. Is true (1) if only emotes are allowed otherwise, false (0).
|
||||
var emote_only: String
|
||||
## An integer value that determines whether only followers can post messages in the chat room. The value indicates how long, in minutes, the user must have followed the broadcaster before posting chat messages. If the value is -1, the chat room is not restricted to followers only.
|
||||
var followers_only: String
|
||||
## A Boolean value that determines whether a user’s messages must be unique. Applies only to messages with more than 9 characters. Is true (1) if users must post unique messages otherwise, false (0).
|
||||
var r9k: String
|
||||
## An ID that identifies the chat room (channel).
|
||||
var room_id: String
|
||||
## An integer value that determines how long, in seconds, users must wait between sending messages.
|
||||
var slow: String
|
||||
## A Boolean value that determines whether only subscribers and moderators can chat in the chat room. Is true (1) if only subscribers and moderators can chat otherwise, false (0).
|
||||
var subs_only: String
|
||||
|
||||
|
||||
func _init(tags: String) -> void:
|
||||
parse_tags(tags, self)
|
||||
|
||||
|
||||
## Sent when events like someone subscribing to the channel occurs.[br]
|
||||
## @badge-info=<badge-info>;badges=<badges>;color=<color>;display-name=<display-name>;emotes=<emotes>;id=<id-of-msg>;login=<user>;mod=<mod>;msg-id=<msg-id>;room-id=<room-id>;subscriber=<subscriber>;system-msg=<system-msg>;tmi-sent-ts=<timestamp>;turbo=<turbo>;user-id=<user-id>;user-type=<user-type>[br]
|
||||
## See: https://dev.twitch.tv/docs/irc/tags/#usernotice-tags
|
||||
class Usernotice extends BaseTags:
|
||||
## Contains metadata related to the chat badges in the badges tag. [br]
|
||||
## Currently, this tag contains metadata only for subscriber badges, to indicate the number of months the user has been a subscriber.
|
||||
var badge_info: String
|
||||
## Comma-separated list of chat badges in the form, <badge>/<version>. For example, admin/1. There are many possible badge values.
|
||||
var badges: String
|
||||
## The color of the user’s name in the chat room. This is a hexadecimal RGB color code in the form, #<RGB>. This tag may be empty if it is never set.
|
||||
var color: String
|
||||
## The user’s display name, escaped as described in the IRCv3 spec. This tag may be empty if it is never set.
|
||||
var display_name: String
|
||||
## A comma-delimited list of emotes and their positions in the message. Each emote is in the form, <emote ID>:<start position>-<end position>. The position indices are zero-based.
|
||||
var emotes: String
|
||||
## An ID that uniquely identifies this message.
|
||||
var id: String
|
||||
## The login name of the user whose action generated the message.
|
||||
var login: String
|
||||
## A Boolean value that determines whether the user is a moderator. Is true (1) if the user is a moderator otherwise, false (0).
|
||||
var mod: String
|
||||
## The type of notice (not the ID). Possible values are: TwitchTags.MSG_ID_*
|
||||
var msg_id: String
|
||||
## An ID that identifies the chat room (channel).
|
||||
var room_id: String
|
||||
## A Boolean value that determines whether the user is a subscriber. Is true (1) if the user is a subscriber otherwise, false (0).
|
||||
var subscriber: String
|
||||
## The message Twitch shows in the chat room for this notice.
|
||||
var system_msg: String
|
||||
## The UNIX timestamp for when the Twitch IRC server received the message.
|
||||
var tmi_sent_ts: String
|
||||
## A Boolean value that indicates whether the user has site-wide commercial free mode enabled. Is true (1) if enabled otherwise, false (0).
|
||||
var turbo: String
|
||||
## The user’s ID.
|
||||
var user_id: String
|
||||
## The type of user. See TwitchTags.USER_TYPE_*
|
||||
var user_type: String
|
||||
#
|
||||
# Depending on State
|
||||
#
|
||||
## Included only with sub and resub notices. [br]
|
||||
## The total number of months the user has subscribed. This is the same as msg-param-months but sent for different types of user notices.
|
||||
var msg_param_cumulative_months: String
|
||||
## Included only with raid notices. [br]
|
||||
## The display name of the broadcaster raiding this channel.
|
||||
var msg_param_displayName: String
|
||||
## Included only with raid notices. [br]
|
||||
## The login name of the broadcaster raiding this channel.
|
||||
var msg_param_login: String
|
||||
## Included only with subgift notices. [br]
|
||||
## The total number of months the user has subscribed. This is the same as msg-param-cumulative-months but sent for different types of user notices.
|
||||
var msg_param_months: String
|
||||
## Included only with anongiftpaidupgrade and giftpaidupgrade notices. [br]
|
||||
## The number of gifts the gifter has given during the promo indicated by msg-param-promo-name.
|
||||
var msg_param_promo_gift_total: String
|
||||
## Included only with anongiftpaidupgrade and giftpaidupgrade notices. [br]
|
||||
## The subscriptions promo, if any, that is ongoing (for example, Subtember 2018).
|
||||
var msg_param_promo_name: String
|
||||
## Included only with subgift notices.[br]
|
||||
## The display name of the subscription gift recipient.
|
||||
var msg_param_recipient_display_name: String
|
||||
## Included only with subgift notices.[br]
|
||||
## The user ID of the subscription gift recipient.
|
||||
var msg_param_recipient_id: String
|
||||
## Included only with subgift notices.[br]
|
||||
## The user name of the subscription gift recipient.
|
||||
var msg_param_recipient_user_name: String
|
||||
## Included only with giftpaidupgrade notices. [br]
|
||||
## The login name of the user who gifted the subscription.
|
||||
var msg_param_sender_login: String
|
||||
## Include only with giftpaidupgrade notices.[br]
|
||||
## The display name of the user who gifted the subscription.
|
||||
var msg_param_sender_name: String
|
||||
## Included only with sub and resub notices.[br]
|
||||
## A Boolean value that indicates whether the user wants their streaks shared.
|
||||
var msg_param_should_share_streak: String
|
||||
## Included only with sub and resub notices.
|
||||
## The number of consecutive months the user has subscribed. This is zero (0) if msg-param-should-share-streak is 0.
|
||||
var msg_param_streak_months: String
|
||||
## Included only with sub, resub and subgift notices.[br]
|
||||
## [br]
|
||||
## The type of subscription plan being used. Possible values are:[br]
|
||||
## [br]
|
||||
## Prime — Amazon Prime subscription[br]
|
||||
## 1000 — First level of paid subscription[br]
|
||||
## 2000 — Second level of paid subscription[br]
|
||||
## 3000 — Third level of paid subscription[br]
|
||||
var msg_param_sub_plan: String
|
||||
## Included only with sub, resub, and subgift notices.[br]
|
||||
## The display name of the subscription plan. This may be a default name or one created by the channel owner.
|
||||
var msg_param_sub_plan_name: String
|
||||
## Included only with raid notices.[br]
|
||||
## The number of viewers raiding this channel from the broadcaster’s channel.
|
||||
var msg_param_viewerCount: String
|
||||
## Included only with ritual notices.[br]
|
||||
## The name of the ritual being celebrated. Possible values are: new_chatter.
|
||||
var msg_param_ritual_name: String
|
||||
## Included only with bitsbadgetier notices.[br]
|
||||
## The tier of the Bits badge the user just earned. For example, 100, 1000, or 10000.
|
||||
var msg_param_threshold: String
|
||||
## Included only with subgift notices.[br]
|
||||
## The number of months gifted as part of a single, multi-month gift.
|
||||
var msg_param_gift_months: String
|
||||
|
||||
|
||||
func _init(tags: String) -> void:
|
||||
parse_tags(tags, self)
|
||||
|
||||
|
||||
## Sent when the bot joins a channel or sends a PRIVMSG message. [br]
|
||||
## @badge-info=<badge-info>;badges=<badges>;color=<color>;display-name=<display-name>;emote-sets=<emote-sets>;id=<id>;mod=<mod>;subscriber=<subscriber>;turbo=<turbo>;user-type=<user-type>[br][br]
|
||||
## See: https://dev.twitch.tv/docs/irc/tags/#userstate-tags
|
||||
class Userstate extends BaseTags:
|
||||
## Contains metadata related to the chat badges in the badges tag. [br]
|
||||
## Currently, this tag contains metadata only for subscriber badges, to indicate the number of months the user has been a subscriber.
|
||||
var badge_info: String
|
||||
## Comma-separated list of chat badges in the form, <badge>/<version>. For example, admin/1. There are many possible badge values.
|
||||
var badges: String
|
||||
## The color of the user’s name in the chat room. This is a hexadecimal RGB color code in the form, #<RGB>. This tag may be empty if it is never set.
|
||||
var color: String
|
||||
## The user’s display name, escaped as described in the IRCv3 spec. This tag may be empty if it is never set.
|
||||
var display_name: String
|
||||
## A comma-delimited list of IDs that identify the emote sets that the user has access to. Is always set to at least zero (0). To access the emotes in the set, use the Get Emote Sets API.
|
||||
var emote_sets: String
|
||||
## If a privmsg was sent, an ID that uniquely identifies the message.
|
||||
var id: String
|
||||
## A Boolean value that determines whether the user is a moderator. Is true (1) if the user is a moderator; otherwise, false (0).
|
||||
var mod: String
|
||||
## A Boolean value that determines whether the user is a subscriber. Is true (1) if the user is a subscriber; otherwise, false (0).
|
||||
var subscriber: String
|
||||
## A Boolean value that indicates whether the user has site-wide commercial free mode enabled. Is true (1) if enabled; otherwise, false (0).
|
||||
var turbo: String
|
||||
## The type of user. See TwitchTags.USER_TYPE_*
|
||||
var user_type: String
|
||||
|
||||
|
||||
func _init(tags: String) -> void:
|
||||
parse_tags(tags, self)
|
||||
|
||||
|
||||
## Sent when someone sends your bot a whisper message. [br]
|
||||
## @badges=<badges>;color=<color>;display-name=<display-name>;emotes=<emotes>;message-id=<msg-id>;thread-id=<thread-id>;turbo=<turbo>;user-id=<user-id>;user-type=<user-type>[br]
|
||||
## See: https://dev.twitch.tv/docs/irc/tags/#whisper-tags
|
||||
class Whisper extends BaseTags:
|
||||
## Comma-separated list of chat badges in the form, <badge>/<version>. For example, admin/1. There are many possible badge values.
|
||||
var badges: String
|
||||
## The color of the user’s name in the chat room. This is a hexadecimal RGB color code in the form, #<RGB>. This tag may be empty if it is never set.
|
||||
var color: String
|
||||
## The display name of the user sending the whisper message, escaped as described in the IRCv3 spec. This tag may be empty if it is never set.
|
||||
var display_name: String
|
||||
## A comma-delimited list of emotes and their positions in the message. Each emote is in the form, <emote ID>:<start position>-<end position>. The position indices are zero-based.
|
||||
var emotes: String
|
||||
## An ID that uniquely identifies the whisper message.
|
||||
var message_id: String
|
||||
## An ID that uniquely identifies the whisper thread. The ID is in the form, <smaller-value-user-id>_<larger-value-user-id>.
|
||||
var thread_id: String
|
||||
## A Boolean value that indicates whether the user has site-wide commercial free mode enabled. Is true (1) if enabled; otherwise, false (0).
|
||||
var turbo: String
|
||||
## The ID of the user sending the whisper message.
|
||||
var user_id: String
|
||||
## The type of user. See TwitchTags.USER_TYPE_*
|
||||
var user_type: String
|
||||
|
||||
|
||||
func _init(tags: String) -> void:
|
||||
parse_tags(tags, self)
|
||||
|
||||
#endregion
|
||||
1
addons/twitcher/irc/twitch_tags.gd.uid
Normal file
1
addons/twitcher/irc/twitch_tags.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://drb7ly83s17kp
|
||||
Loading…
Add table
Add a link
Reference in a new issue