mirror of
https://github.com/onyx-and-iris/obsws-python.git
synced 2026-04-18 22:13:32 +00:00
Compare commits
17 Commits
8aa2e78ba6
...
fix-discon
| Author | SHA1 | Date | |
|---|---|---|---|
| ef8df5cf4d | |||
| 1abca0c7e4 | |||
| 85180c1d94 | |||
| f4db1ad95c | |||
| efaee7594e | |||
| 2cebd5eedb | |||
| cac236c004 | |||
| 6aa6db09eb | |||
| f1c2efa4a1 | |||
|
|
4654d2529f | ||
| 1494208f63 | |||
|
|
d217630289 | ||
|
|
5bfe792fa6 | ||
| 3c36619173 | |||
| c4cf817042 | |||
| ba5da8dfef | |||
| 83577e2d61 |
@@ -17,6 +17,12 @@ class Observer:
|
||||
print(f"Registered events: {self._client.callback.get()}")
|
||||
self.running = True
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_value, exc_traceback):
|
||||
self._client.disconnect()
|
||||
|
||||
def on_current_program_scene_changed(self, data):
|
||||
"""The current program scene has changed."""
|
||||
print(f"Switched to scene {data.scene_name}")
|
||||
@@ -31,13 +37,11 @@ class Observer:
|
||||
|
||||
def on_exit_started(self, _):
|
||||
"""OBS has begun the shutdown process."""
|
||||
print(f"OBS closing!")
|
||||
self._client.unsubscribe()
|
||||
print("OBS closing!")
|
||||
self.running = False
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
observer = Observer()
|
||||
|
||||
while observer.running:
|
||||
time.sleep(0.1)
|
||||
with Observer() as observer:
|
||||
while observer.running:
|
||||
time.sleep(0.1)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import inspect
|
||||
|
||||
import keyboard
|
||||
|
||||
import obsws_python as obs
|
||||
|
||||
|
||||
@@ -10,6 +11,12 @@ class Observer:
|
||||
self._client.callback.register(self.on_current_program_scene_changed)
|
||||
print(f"Registered events: {self._client.callback.get()}")
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_value, exc_traceback):
|
||||
self._client.disconnect()
|
||||
|
||||
@property
|
||||
def event_identifier(self):
|
||||
return inspect.stack()[1].function
|
||||
@@ -31,13 +38,12 @@ def set_scene(scene, *args):
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
req_client = obs.ReqClient()
|
||||
observer = Observer()
|
||||
with obs.ReqClient() as req_client:
|
||||
with Observer() as observer:
|
||||
keyboard.add_hotkey("0", version)
|
||||
keyboard.add_hotkey("1", set_scene, args=("START",))
|
||||
keyboard.add_hotkey("2", set_scene, args=("BRB",))
|
||||
keyboard.add_hotkey("3", set_scene, args=("END",))
|
||||
|
||||
keyboard.add_hotkey("0", version)
|
||||
keyboard.add_hotkey("1", set_scene, args=("START",))
|
||||
keyboard.add_hotkey("2", set_scene, args=("BRB",))
|
||||
keyboard.add_hotkey("3", set_scene, args=("END",))
|
||||
|
||||
print("press ctrl+enter to quit")
|
||||
keyboard.wait("ctrl+enter")
|
||||
print("press ctrl+enter to quit")
|
||||
keyboard.wait("ctrl+enter")
|
||||
|
||||
@@ -9,6 +9,8 @@ LEVELTYPE = IntEnum(
|
||||
start=0,
|
||||
)
|
||||
|
||||
DEVICE = "Desktop Audio"
|
||||
|
||||
|
||||
def on_input_mute_state_changed(data):
|
||||
"""An input's mute state has changed."""
|
||||
@@ -32,15 +34,14 @@ def on_input_volume_meters(data):
|
||||
|
||||
|
||||
def main():
|
||||
client = obs.EventClient(subs=(obs.Subs.LOW_VOLUME | obs.Subs.INPUTVOLUMEMETERS))
|
||||
client.callback.register([on_input_volume_meters, on_input_mute_state_changed])
|
||||
with obs.EventClient(
|
||||
subs=(obs.Subs.LOW_VOLUME | obs.Subs.INPUTVOLUMEMETERS)
|
||||
) as client:
|
||||
client.callback.register([on_input_volume_meters, on_input_mute_state_changed])
|
||||
|
||||
while cmd := input("<Enter> to exit>\n"):
|
||||
if not cmd:
|
||||
break
|
||||
while _ := input("Press <Enter> to exit\n"):
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
DEVICE = "Desktop Audio"
|
||||
|
||||
main()
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import json
|
||||
import logging
|
||||
import time
|
||||
from threading import Thread
|
||||
import threading
|
||||
|
||||
from websocket import WebSocketTimeoutException
|
||||
from websocket import WebSocketConnectionClosedException, WebSocketTimeoutException
|
||||
|
||||
from .baseclient import ObsClient
|
||||
from .callback import Callback
|
||||
@@ -20,8 +19,6 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class EventClient:
|
||||
DELAY = 0.001
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self.logger = logger.getChild(self.__class__.__name__)
|
||||
defaultkwargs = {"subs": Subs.LOW_VOLUME}
|
||||
@@ -38,6 +35,12 @@ class EventClient:
|
||||
self.callback = Callback()
|
||||
self.subscribe()
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_value, exc_traceback):
|
||||
self.disconnect()
|
||||
|
||||
def __repr__(self):
|
||||
return type(
|
||||
self
|
||||
@@ -49,33 +52,40 @@ class EventClient:
|
||||
return type(self).__name__
|
||||
|
||||
def subscribe(self):
|
||||
worker = Thread(target=self.trigger, daemon=True)
|
||||
worker.start()
|
||||
self.base_client.ws.settimeout(None)
|
||||
stop_event = threading.Event()
|
||||
self.worker = threading.Thread(
|
||||
target=self.trigger, daemon=True, args=(stop_event,)
|
||||
)
|
||||
self.worker.start()
|
||||
|
||||
def trigger(self):
|
||||
def trigger(self, stop_event):
|
||||
"""
|
||||
Continuously listen for events.
|
||||
|
||||
Triggers a callback on event received.
|
||||
"""
|
||||
self.running = True
|
||||
while self.running:
|
||||
while not stop_event.is_set():
|
||||
try:
|
||||
event = json.loads(self.base_client.ws.recv())
|
||||
if response := self.base_client.ws.recv():
|
||||
event = json.loads(response)
|
||||
self.logger.debug(f"Event received {event}")
|
||||
type_, data = (
|
||||
event["d"].get("eventType"),
|
||||
event["d"].get("eventData"),
|
||||
)
|
||||
self.callback.trigger(type_, data if data else {})
|
||||
except WebSocketTimeoutException as e:
|
||||
self.logger.exception(f"{type(e).__name__}: {e}")
|
||||
raise OBSSDKTimeoutError("Timeout while waiting for event") from e
|
||||
self.logger.debug(f"Event received {event}")
|
||||
type_, data = (
|
||||
event["d"].get("eventType"),
|
||||
event["d"].get("eventData"),
|
||||
)
|
||||
self.callback.trigger(type_, data if data else {})
|
||||
time.sleep(self.DELAY)
|
||||
except (WebSocketConnectionClosedException, OSError) as e:
|
||||
self.logger.debug(f"{type(e).__name__} terminating the event thread")
|
||||
stop_event.set()
|
||||
|
||||
def disconnect(self):
|
||||
"""stop listening for events"""
|
||||
|
||||
def unsubscribe(self):
|
||||
"""
|
||||
stop listening for events
|
||||
"""
|
||||
self.running = False
|
||||
self.base_client.ws.close()
|
||||
self.worker.join()
|
||||
|
||||
unsubscribe = disconnect
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import logging
|
||||
from warnings import warn
|
||||
|
||||
from .baseclient import ObsClient
|
||||
from .error import OBSSDKError, OBSSDKRequestError
|
||||
@@ -30,7 +31,7 @@ class ReqClient:
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_value, exc_traceback):
|
||||
self.base_client.ws.close()
|
||||
self.disconnect()
|
||||
|
||||
def __repr__(self):
|
||||
return type(
|
||||
@@ -41,6 +42,9 @@ class ReqClient:
|
||||
|
||||
def __str__(self):
|
||||
return type(self).__name__
|
||||
|
||||
def disconnect(self):
|
||||
self.base_client.ws.close()
|
||||
|
||||
def send(self, param, data=None, raw=False):
|
||||
try:
|
||||
@@ -432,6 +436,19 @@ class ReqClient:
|
||||
"""
|
||||
return self.send("GetRecordDirectory")
|
||||
|
||||
def set_record_directory(self, recordDirectory):
|
||||
"""
|
||||
Sets the current directory that the record output writes files to.
|
||||
IMPORTANT NOTE: Requires obs websocket v5.3 or higher.
|
||||
|
||||
:param recordDirectory: Output directory
|
||||
:type recordDirectory: str
|
||||
"""
|
||||
payload = {
|
||||
"recordDirectory": recordDirectory,
|
||||
}
|
||||
return self.send("SetRecordDirectory", payload)
|
||||
|
||||
def get_source_active(self, name):
|
||||
"""
|
||||
Gets the active and show state of a source
|
||||
@@ -1938,3 +1955,66 @@ class ReqClient:
|
||||
|
||||
"""
|
||||
return self.send("GetMonitorList")
|
||||
|
||||
def open_video_mix_projector(
|
||||
self, video_mix_type, monitor_index=-1, projector_geometry=None
|
||||
):
|
||||
"""
|
||||
Opens a projector for a specific output video mix.
|
||||
|
||||
The available mix types are:
|
||||
OBS_WEBSOCKET_VIDEO_MIX_TYPE_PREVIEW
|
||||
OBS_WEBSOCKET_VIDEO_MIX_TYPE_PROGRAM
|
||||
OBS_WEBSOCKET_VIDEO_MIX_TYPE_MULTIVIEW
|
||||
|
||||
:param video_mix_type: Type of mix to open.
|
||||
:type video_mix_type: str
|
||||
:param monitor_index: Monitor index, use GetMonitorList to obtain index
|
||||
:type monitor_index: int
|
||||
:param projector_geometry:
|
||||
Size/Position data for a windowed projector, in Qt Base64 encoded format.
|
||||
Mutually exclusive with monitorIndex
|
||||
:type projector_geometry: str
|
||||
|
||||
"""
|
||||
warn(
|
||||
"open_video_mix_projector request serves to provide feature parity with 4.x. "
|
||||
"It is very likely to be changed/deprecated in a future release.",
|
||||
DeprecationWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
payload = {
|
||||
"videoMixType": video_mix_type,
|
||||
"monitorIndex": monitor_index,
|
||||
"projectorGeometry": projector_geometry,
|
||||
}
|
||||
self.send("OpenVideoMixProjector", payload)
|
||||
|
||||
def open_source_projector(
|
||||
self, source_name, monitor_index=-1, projector_geometry=None
|
||||
):
|
||||
"""
|
||||
Opens a projector for a source.
|
||||
|
||||
:param source_name: Name of the source to open a projector for
|
||||
:type source_name: str
|
||||
:param monitor_index: Monitor index, use GetMonitorList to obtain index
|
||||
:type monitor_index: int
|
||||
:param projector_geometry:
|
||||
Size/Position data for a windowed projector, in Qt Base64 encoded format.
|
||||
Mutually exclusive with monitorIndex
|
||||
:type projector_geometry: str
|
||||
|
||||
"""
|
||||
warn(
|
||||
"open_source_projector request serves to provide feature parity with 4.x. "
|
||||
"It is very likely to be changed/deprecated in a future release.",
|
||||
DeprecationWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
payload = {
|
||||
"sourceName": source_name,
|
||||
"monitorIndex": monitor_index,
|
||||
"projectorGeometry": projector_geometry,
|
||||
}
|
||||
self.send("OpenSourceProjector", payload)
|
||||
|
||||
@@ -1 +1 @@
|
||||
version = "1.6.0"
|
||||
version = "1.7.0"
|
||||
|
||||
@@ -15,9 +15,9 @@ class TestRequests:
|
||||
resp = req_cl.get_hot_key_list()
|
||||
obsbasic_hotkey_list = [
|
||||
"OBSBasic.SelectScene",
|
||||
"OBSBasic.SelectScene",
|
||||
"OBSBasic.SelectScene",
|
||||
"OBSBasic.SelectScene",
|
||||
"OBSBasic.QuickTransition.1",
|
||||
"OBSBasic.QuickTransition.2",
|
||||
"OBSBasic.QuickTransition.3",
|
||||
"OBSBasic.StartStreaming",
|
||||
"OBSBasic.StopStreaming",
|
||||
"OBSBasic.ForceStopStreaming",
|
||||
@@ -25,15 +25,17 @@ class TestRequests:
|
||||
"OBSBasic.StopRecording",
|
||||
"OBSBasic.PauseRecording",
|
||||
"OBSBasic.UnpauseRecording",
|
||||
"OBSBasic.SplitFile",
|
||||
"OBSBasic.StartReplayBuffer",
|
||||
"OBSBasic.StopReplayBuffer",
|
||||
"OBSBasic.StartVirtualCam",
|
||||
"OBSBasic.StopVirtualCam",
|
||||
"OBSBasic.EnablePreview",
|
||||
"OBSBasic.DisablePreview",
|
||||
"OBSBasic.EnablePreviewProgram",
|
||||
"OBSBasic.DisablePreviewProgram",
|
||||
"OBSBasic.ShowContextBar",
|
||||
"OBSBasic.HideContextBar",
|
||||
"OBSBasic.TogglePreviewProgram",
|
||||
"OBSBasic.Transition",
|
||||
"OBSBasic.ResetStats",
|
||||
"OBSBasic.Screenshot",
|
||||
|
||||
Reference in New Issue
Block a user