2026-03-02 02:04:03 -06:00
|
|
|
extends Node
|
|
|
|
|
|
|
|
|
|
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)
|
2026-03-06 21:22:09 -06:00
|
|
|
|
|
|
|
|
static var _log: TwitchLogger = TwitchLogger.new(&"ObsManager", true, true)
|
|
|
|
|
|
|
|
|
|
var obs: NoOBSWS
|
|
|
|
|
var _reconnect: bool = false
|
|
|
|
|
|
2026-03-02 02:04:03 -06:00
|
|
|
# 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)
|
2026-03-06 21:22:09 -06:00
|
|
|
obs.connection_ready.connect(func():
|
|
|
|
|
_reconnect = false
|
|
|
|
|
obs_ready.emit()
|
|
|
|
|
_log.i("Connected to OBS WebSocket server.")
|
|
|
|
|
)
|
2026-03-02 02:04:03 -06:00
|
|
|
obs.connection_closed_clean.connect(_handle_disconnect)
|
2026-03-06 21:22:09 -06:00
|
|
|
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()
|
|
|
|
|
)
|
2026-03-02 02:04:03 -06:00
|
|
|
|
|
|
|
|
func is_open() -> bool:
|
|
|
|
|
return obs.is_open()
|
|
|
|
|
|
|
|
|
|
func connect_to_host() -> void:
|
|
|
|
|
if not (Globals.settings.obs_host != "" and
|
|
|
|
|
Globals.settings.obs_port != 0 and
|
|
|
|
|
Globals.settings.obs_pass != ""):
|
|
|
|
|
return
|
|
|
|
|
|
2026-03-06 21:22:09 -06:00
|
|
|
_log.i("%s to OBS WebSocket server..." % "Reconnecting" if _reconnect else "Connecting")
|
|
|
|
|
if _reconnect: _reconnect = false
|
2026-03-02 02:04:03 -06:00
|
|
|
obs.connect_to_obsws(Globals.settings.obs_port, Globals.settings.obs_host, Globals.settings.obs_pass)
|
|
|
|
|
|
2026-03-06 21:22:09 -06:00
|
|
|
func _handle_disconnect(_reason: int, _message: String) -> void:
|
2026-03-02 02:04:03 -06:00
|
|
|
obs_disconnect.emit()
|
|
|
|
|
if Globals.settings.obs_reconnect:
|
2026-03-06 21:22:09 -06:00
|
|
|
_reconnect = true
|
2026-03-02 02:04:03 -06:00
|
|
|
connect_to_host()
|
|
|
|
|
|
|
|
|
|
func _handle_websock_events(event: NoOBSWS.Message) -> void:
|
|
|
|
|
var data := event.get_data()
|
|
|
|
|
if data.has("event_type"):
|
|
|
|
|
if not data.has("event_data"):
|
|
|
|
|
return
|
|
|
|
|
var ed: Dictionary = data.event_data
|
|
|
|
|
match data.event_type:
|
|
|
|
|
"StreamStateChanged":
|
|
|
|
|
stream_state_changed.emit(ed.output_active)
|
|
|
|
|
"InputMuteStateChanged":
|
|
|
|
|
input_state_changed.emit(ed.input_name, ed.input_muted)
|
|
|
|
|
"CurrentProgramSceneChanged":
|
|
|
|
|
scene_changed.emit(ed.scene_name, ed.scene_uuid)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func get_stream_status() -> bool:
|
|
|
|
|
var request_type := "GetStreamStatus"
|
|
|
|
|
var request := obs.make_generic_request(request_type)
|
|
|
|
|
await request.response_received
|
|
|
|
|
var response = request.message.get_data()
|
|
|
|
|
return response.response_data.output_active as bool
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func get_scene_item_id(scene_name: String, source_name: String) -> int:
|
|
|
|
|
var request_type := "GetSceneItemId"
|
|
|
|
|
var request_data := {"scene_name": scene_name, "source_name": source_name}
|
|
|
|
|
var request := obs.make_generic_request(request_type, request_data)
|
|
|
|
|
await request.response_received
|
|
|
|
|
var response = request.message.get_data()
|
|
|
|
|
return response.response_data.scene_item_id as int
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func get_item_enabled(scene_name: String, item_id: int) -> bool:
|
|
|
|
|
var request_type = "GetSceneItemEnabled"
|
|
|
|
|
var request_data = {"scene_name": scene_name, "scene_item_id": item_id}
|
|
|
|
|
var request = obs.make_generic_request(request_type, request_data)
|
|
|
|
|
await request.response_received
|
|
|
|
|
var response = request.message.get_data()
|
|
|
|
|
return response.response_data.scene_item_enabled as bool
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func set_item_enabled(scene_name: String, item_id: int, val: bool) -> void:
|
|
|
|
|
var request_type = "SetSceneItemEnabled"
|
|
|
|
|
var request_data = {"scene_name": scene_name, "scene_item_id": item_id, "scene_item_enabled": val}
|
|
|
|
|
obs.make_generic_request(request_type, request_data)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func get_item_transform(scene_name: String, item_id: int) -> Dictionary:
|
|
|
|
|
var request_type = "GetSceneItemTransform"
|
|
|
|
|
var request_data = {"scene_name": scene_name, "scene_item_id": item_id}
|
|
|
|
|
var request = obs.make_generic_request(request_type, request_data)
|
|
|
|
|
await request.response_received
|
|
|
|
|
var response = request.message.get_data()
|
|
|
|
|
return response.response_data.scene_item_transform as Dictionary
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func set_item_transform(scene_name: String, item_id: int, transform: Dictionary) -> void:
|
|
|
|
|
var request_type = "SetSceneItemTransform"
|
|
|
|
|
var request_data = {"scene_name": scene_name, "scene_item_id": item_id, "scene_item_transform": transform}
|
|
|
|
|
obs.make_generic_request(request_type, request_data)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func get_input_mute(input_name: String) -> bool:
|
|
|
|
|
var request_type = "GetInputMute"
|
|
|
|
|
var request_data = {"input_name": input_name}
|
|
|
|
|
var request = obs.make_generic_request(request_type, request_data)
|
|
|
|
|
await request.response_received
|
|
|
|
|
var response = request.message.get_data()
|
|
|
|
|
return response.response_data.input_muted
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func set_input_mute(input_name: String, val: bool) -> void:
|
|
|
|
|
var request_type = "SetInputMute"
|
|
|
|
|
var request_data = {"input_name": input_name, "input_muted": val}
|
|
|
|
|
obs.make_generic_request(request_type, request_data)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func get_item_filter_enabled(source_name: String, filter_name: String) -> bool:
|
|
|
|
|
var request_type = "GetSourceFilter"
|
|
|
|
|
var request_data = {
|
|
|
|
|
"source_name": source_name,
|
|
|
|
|
"filter_name": filter_name
|
|
|
|
|
}
|
|
|
|
|
var request = obs.make_generic_request(request_type, request_data)
|
|
|
|
|
await request.response_received
|
|
|
|
|
var response = request.message.get_data()
|
|
|
|
|
return response.response_data.filter_enabled
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func set_item_filter_enabled(source_name: String, filter_name: String, filter_enabled: bool) -> void:
|
|
|
|
|
var request_type = "SetSourceFilterEnabled"
|
|
|
|
|
var request_data = {
|
|
|
|
|
"source_name": source_name,
|
|
|
|
|
"filter_name": filter_name,
|
|
|
|
|
"filter_enabled": filter_enabled
|
|
|
|
|
}
|
|
|
|
|
obs.make_generic_request(request_type, request_data)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func get_item_filter_setting(source_name: String, filter_name: String) -> Dictionary:
|
|
|
|
|
var request_type = "GetSourceFilter"
|
|
|
|
|
var request_data = {
|
|
|
|
|
"source_name": source_name,
|
|
|
|
|
"filter_name": filter_name
|
|
|
|
|
}
|
|
|
|
|
var request = obs.make_generic_request(request_type, request_data)
|
|
|
|
|
await request.response_received
|
|
|
|
|
var response = request.message.get_data()
|
|
|
|
|
return response.response_data.filter_settings
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func set_item_filter_setting(source_name: String, filter_name: String, filter_settings: Dictionary) -> void:
|
|
|
|
|
var request_type = "SetSourceFilterSettings"
|
|
|
|
|
var request_data = {
|
|
|
|
|
"sourceName": source_name,
|
|
|
|
|
"filterName": filter_name,
|
|
|
|
|
"filterSettings": filter_settings,
|
|
|
|
|
"overlay": true
|
|
|
|
|
}
|
|
|
|
|
var res: NoOBSWS.RequestResponse = obs.make_generic_request(request_type, request_data)
|
|
|
|
|
await res.response_received
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func stop_stream() -> void:
|
|
|
|
|
var request_type = "StopStream"
|
|
|
|
|
var request_data = {}
|
|
|
|
|
var request = obs.make_generic_request(request_type, request_data)
|
|
|
|
|
await request.response_received
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func restart_media(media_name) -> void:
|
|
|
|
|
var request_type = "TriggerMediaInputAction"
|
|
|
|
|
var request_data = {"input_name": media_name, "media_action": "OBS_WEBSOCKET_MEDIA_INPUT_ACTION_RESTART"}
|
|
|
|
|
var request = obs.make_generic_request(request_type, request_data)
|
|
|
|
|
await request.response_received
|