Initial Commit

Initial commit of Code Base.
This commit is contained in:
Mario Steele 2025-06-12 14:31:14 -05:00
parent 293b1213e1
commit c11a4ebbc2
653 changed files with 36893 additions and 1 deletions

View 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 channels 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 thats sending the whisper message.[br]
## to_user - The user thats 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

View file

@ -0,0 +1 @@
uid://wkh0l2xsyapj

View 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 channels 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()

View file

@ -0,0 +1 @@
uid://cva5e053boj4u

View 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];

View file

@ -0,0 +1 @@
uid://c8mv0lq0a2l8f

View 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 doesnt 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 users 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 users 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 users 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 actions 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 fields value in the response. Then, get the cheermotes URL based on the cheermote theme, type, and size you want to use.
var bits: String
## The color of the users 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 users 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 users 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 doesnt 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 channels 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 users 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 users 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 users 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 users 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 broadcasters 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 users 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 users 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 users 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

View file

@ -0,0 +1 @@
uid://drb7ly83s17kp