From 95345fc50bcd4837726b6aff4786dd23ae6980cd Mon Sep 17 00:00:00 2001
From: Mario Steele
Date: Fri, 6 Mar 2026 21:20:45 -0600
Subject: [PATCH 1/8] Update Util
Updated Util convert_html_to_bbcode() to fix p tags.
---
lib/util.gd | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/lib/util.gd b/lib/util.gd
index f33c5f11..335e9409 100644
--- a/lib/util.gd
+++ b/lib/util.gd
@@ -41,10 +41,14 @@ static func convert_html_to_bbcode(html: String) -> String:
# NOTE: Replace
with [img]...[/img]
bb = _img_re.sub(bb, "[img]$1[/img]", true)
- # NOTE: Remove tags, convert
to newline
+ # NOTE: Replace ...
tags, with [b]...[/b]
bb = _h2_open_re.sub(bb, "[b]", true)
bb = bb.replace("", "[/b]\n")
+ # NOTE: Remove tags, convert
to new line
+ bb = _p_open_re.sub(bb, "", true)
+ bb = bb.replace("
", "\n")
+
# NOTE: List Items: -> •, -> newline
bb = bb.replace("", "• ")
bb = bb.replace("", "\n")
From 298381b2d9f1fd0909131d15283bffc88910123b Mon Sep 17 00:00:00 2001
From: Mario Steele
Date: Fri, 6 Mar 2026 21:22:09 -0600
Subject: [PATCH 2/8] Updated ObsManager
Added logging
Added reconnecting based upon obs_reconnect.
Added bool check to see if we are connecting, or re-connecting.
---
lib/obs_manager.gd | 25 ++++++++++++++++++++++---
1 file changed, 22 insertions(+), 3 deletions(-)
diff --git a/lib/obs_manager.gd b/lib/obs_manager.gd
index 47e1ba0b..63880882 100644
--- a/lib/obs_manager.gd
+++ b/lib/obs_manager.gd
@@ -1,18 +1,34 @@
extends Node
-var obs: NoOBSWS
signal obs_ready()
signal obs_disconnect()
signal stream_state_changed(state: bool)
signal input_state_changed(input_name: String, state: bool)
signal scene_changed(scene_name: String, scene_uuid: String)
+
+static var _log: TwitchLogger = TwitchLogger.new(&"ObsManager", true, true)
+
+var obs: NoOBSWS
+var _reconnect: bool = false
+
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
obs = NoOBSWS.new()
add_child(obs)
obs.event_received.connect(_handle_websock_events)
- obs.connection_ready.connect(obs_ready.emit)
+ obs.connection_ready.connect(func():
+ _reconnect = false
+ obs_ready.emit()
+ _log.i("Connected to OBS WebSocket server.")
+ )
obs.connection_closed_clean.connect(_handle_disconnect)
+ obs.connection_failed.connect(func():
+ _log.i("Failed to connect to server.")
+ if Globals.settings.obs_reconnect:
+ await get_tree().create_timer(15).timeout
+ _reconnect = true
+ connect_to_host()
+ )
func is_open() -> bool:
return obs.is_open()
@@ -23,11 +39,14 @@ func connect_to_host() -> void:
Globals.settings.obs_pass != ""):
return
+ _log.i("%s to OBS WebSocket server..." % "Reconnecting" if _reconnect else "Connecting")
+ if _reconnect: _reconnect = false
obs.connect_to_obsws(Globals.settings.obs_port, Globals.settings.obs_host, Globals.settings.obs_pass)
-func _handle_disconnect(reason: int, message: String) -> void:
+func _handle_disconnect(_reason: int, _message: String) -> void:
obs_disconnect.emit()
if Globals.settings.obs_reconnect:
+ _reconnect = true
connect_to_host()
func _handle_websock_events(event: NoOBSWS.Message) -> void:
From b47df7ad86e95c6db19902efd95bb0895efc5a88 Mon Sep 17 00:00:00 2001
From: Mario Steele
Date: Fri, 6 Mar 2026 21:22:36 -0600
Subject: [PATCH 3/8] Updated EventManager
Fixed warning about losing percision on a float.
---
lib/event_manager.gd | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/lib/event_manager.gd b/lib/event_manager.gd
index c482ec3e..059618b3 100644
--- a/lib/event_manager.gd
+++ b/lib/event_manager.gd
@@ -30,8 +30,8 @@ func test_notification(msg: String) -> void:
lbl.text = msg
lbl.modulate.a = 0
lbl.ready.connect(func() -> void:
- var half: Vector2 = lbl.size / 2
- lbl.position = Vector2(get_tree().root.size / 2) - half
+ var half: Vector2 = lbl.size / 2.0
+ lbl.position = Vector2(get_tree().root.size / 2.0) - half
var tw := create_tween()
tw.tween_property(lbl, "modulate:a", 1.0, 0.5)
tw.tween_interval(2.5)
From 2d25921688fc172184b1a7aca1b0e4fe550e8cfc Mon Sep 17 00:00:00 2001
From: Mario Steele
Date: Fri, 6 Mar 2026 21:23:54 -0600
Subject: [PATCH 4/8] Updated TwitcherExtended
Fixed typo in channel_points_voting_enabled.
Changed poll to _poll to avoid name conflicts with poll() function name.
---
lib/twitcher_extended/twitcher_extended.gd | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/lib/twitcher_extended/twitcher_extended.gd b/lib/twitcher_extended/twitcher_extended.gd
index 30427abf..7921d427 100644
--- a/lib/twitcher_extended/twitcher_extended.gd
+++ b/lib/twitcher_extended/twitcher_extended.gd
@@ -454,14 +454,14 @@ func poll(title: String, choices: Array[String], duration: int = 60, channel_poi
var poll_body: TwitchCreatePoll.Body = TwitchCreatePoll.Body.create(streamer_user.id, title, body_choices, duration)
if channel_points_voting_enabled:
poll_body.channel_points_per_vote = channel_points_per_vote
- poll_body.channel_points_voiting_enabled = channel_points_voting_enabled
+ poll_body.channel_points_voting_enabled = channel_points_voting_enabled
var poll_response: TwitchCreatePoll.Response = await api.create_poll(poll_body)
if poll_response.response.response_code != 200:
var error_message: String = poll_response.response.response_data.get_string_from_utf8()
push_error("Can't create poll response cause of ", error_message)
return {}
- var poll: TwitchPoll = poll_response.data[0]
- var poll_end_time: int = Time.get_ticks_msec() + duration * 100 * POLL_TIMEOUT_MS
+ var _poll: TwitchPoll = poll_response.data[0]
+ var poll_end_time: int = Time.get_ticks_msec() + duration * 1000 * POLL_TIMEOUT_MS
var event: TwitchEventsub.Event
if eventsub && eventsub.has_subscription(TwitchEventsubDefinition.CHANNEL_POLL_END, {&"broadcaster_user_id": streamer_user.id}):
var poll_ended: bool
@@ -469,8 +469,8 @@ func poll(title: String, choices: Array[String], duration: int = 60, channel_poi
if poll_end_time < Time.get_ticks_msec():
return {}
event = await eventsub.event_received
- if event.Type != TwitchEventsubDefinition.CHANNEL_POLL_END: continue
- if event.data[&"id"] != poll.id: continue
+ if event.type != TwitchEventsubDefinition.CHANNEL_POLL_END: continue
+ if event.data[&"id"] != _poll.id: continue
break
else:
_log.i("Can't wait for poll end. Either eventsub is not set to it not listening to ending polls")
From cb50e313a0770171de23f9bdbd3cf560eca9d715 Mon Sep 17 00:00:00 2001
From: Mario Steele
Date: Fri, 6 Mar 2026 21:24:18 -0600
Subject: [PATCH 5/8] Updated ChatbotAuthorization
Added warning ignore for tool function exported variable.
---
lib/twitcher_extended/chatbot_authorization.gd | 1 +
1 file changed, 1 insertion(+)
diff --git a/lib/twitcher_extended/chatbot_authorization.gd b/lib/twitcher_extended/chatbot_authorization.gd
index a8a65450..87cb9003 100644
--- a/lib/twitcher_extended/chatbot_authorization.gd
+++ b/lib/twitcher_extended/chatbot_authorization.gd
@@ -14,6 +14,7 @@ class_name ChatbotAuthorization
var api: TwitchAPI
var auth: TwitchAuth
+@warning_ignore("unused_private_class_variable")
@export_tool_button("Reset Token") var _reset_token := func() -> void:
token.remove_tokens()
From 20104cce0edfb4d712a2d9c7a618c84e2b8c2826 Mon Sep 17 00:00:00 2001
From: Mario Steele
Date: Fri, 6 Mar 2026 21:24:42 -0600
Subject: [PATCH 6/8] Started working on OverlayPlugin
Started work on implementing OverlayPlugin interface for scripts.
---
lib/scripting/overlay_plugin.gd | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/lib/scripting/overlay_plugin.gd b/lib/scripting/overlay_plugin.gd
index 27d9d238..44512ac7 100644
--- a/lib/scripting/overlay_plugin.gd
+++ b/lib/scripting/overlay_plugin.gd
@@ -4,13 +4,13 @@ class_name OverlayPlugin
#region Internal Variables
var _twitch: TwitcherExtended
-var _obs: NoOBSWS
#endregion
func _ready() -> void:
while not TwitcherExtended.instance:
await get_tree().process_frame
_twitch = TwitcherExtended.instance
+
@abstract func run() -> void
@@ -22,16 +22,16 @@ func _get_script_name() -> String:
func send_notification(message: String) -> void:
EventManager.test_notification(message)
-func get_setting(name: String, defval: Variant) -> Variant:
+func get_setting(sname: String, defval: Variant) -> Variant:
var script_name := _get_script_name()
if not Globals.settings.script_storage.has(script_name):
return defval
- if not Globals.settings.script_storage[script_name].has(name):
+ if not Globals.settings.script_storage[script_name].has(sname):
return defval
- return Globals.settings.script_storage[script_name][name]
+ return Globals.settings.script_storage[script_name][sname]
-func set_setting(name: String, value: Variant) -> void:
+func set_setting(sname: String, value: Variant) -> void:
var script_name := _get_script_name()
if not Globals.settings.script_storage.has(script_name):
Globals.settings.script_storage[script_name] = {}
- Globals.settings.script_storage[script_name][name] = value
+ Globals.settings.script_storage[script_name][sname] = value
From 00d437b5239b56780e1cda12487edd046302ed7b Mon Sep 17 00:00:00 2001
From: Mario Steele
Date: Fri, 6 Mar 2026 21:25:21 -0600
Subject: [PATCH 7/8] Updated SQLiteObject
Updated missing type assignment. This will be updated from another
repo.
---
addons/gdata_orm/sqlite_object.gd | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/addons/gdata_orm/sqlite_object.gd b/addons/gdata_orm/sqlite_object.gd
index b3ab920c..f403e4e8 100644
--- a/addons/gdata_orm/sqlite_object.gd
+++ b/addons/gdata_orm/sqlite_object.gd
@@ -215,8 +215,9 @@ static func set_column_type(klass: GDScript, column: String, type: DataType, ext
if type == DataType.CHAR and not extra_params.has("size"):
assert(false, "Attempting to set Column type to CHAR without a size parameter!")
-
- _tables[klass].types[column] = _DEFINITION[type] if type != DataType.CHAR else _DEFINITION[type] % extra_params.size
+
+ _tables[klass].types[column] = type
+ _tables[klass].columns[column].data_type = _DEFINITION[type] if type != DataType.CHAR else _DEFINITION[type] % extra_params.size
## Sets a variable that has been defined in the class, to be ignored, so as to not persist the data in the
## [SQLite] database. The variable must be defined, in order for it to be ignored.[br][br]
From 6611830c1884b03125601b5a60b35ca226150254 Mon Sep 17 00:00:00 2001
From: Mario Steele
Date: Fri, 6 Mar 2026 21:26:03 -0600
Subject: [PATCH 8/8] Updated FloatingMenu
Added OBSProc information, and VTuberProc information, for later when
testing if these programs are running, and maybe later implementing
killing of these programs.
---
UI/floating_menu.gd | 19 +++++++++++++++++--
1 file changed, 17 insertions(+), 2 deletions(-)
diff --git a/UI/floating_menu.gd b/UI/floating_menu.gd
index bdaa1cd9..5580b64c 100644
--- a/UI/floating_menu.gd
+++ b/UI/floating_menu.gd
@@ -77,8 +77,8 @@ var anchored_position: Vector2
var _set_win: Window
var _edit_win: Window
-var _obs_pid: int = -1
-var _vtuber_pid: int = -1
+var _obs_proc: ProcessTree.ProcessInfo = null
+var _vtuber_proc: ProcessTree.ProcessInfo = null
var _vtuber_sid: int
var _camera_sid: int
@@ -199,8 +199,15 @@ func _handle_script_editor() -> void:
_edit_win = win
func _handle_run_obs() -> void:
+ if _obs_proc and _obs_proc.is_running():
+ print("OBS is running.")
+ return
+ elif _obs_proc and not _obs_proc.is_running():
+ _obs_proc = null
+
var tree := ProcessTree.new()
if tree.has_process_name(Globals.settings.obs_name):
+ _obs_proc = tree.get_process_by_name(Globals.settings.obs_name)
print("OBS is running.")
return
else:
@@ -224,8 +231,16 @@ func _handle_step_away() -> void:
EventManager.add_alert(alert)
func _handle_run_vtuber() -> void:
+ if _vtuber_proc and _vtuber_proc.is_running():
+ print("VTuber is running.")
+ return
+ elif _vtuber_proc and not _vtuber_proc.is_running():
+ _vtuber_proc = null
+
+
var tree := ProcessTree.new()
if tree.has_process_name(Globals.settings.vtuber_name):
+ _vtuber_proc = tree.get_process_by_name(Globals.settings.vtuber_name)
print("VTuber is running.")
return
else: