diff --git a/examples/events/__main__.py b/examples/events/__main__.py index db2bf37..e5e14f7 100644 --- a/examples/events/__main__.py +++ b/examples/events/__main__.py @@ -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) diff --git a/examples/hotkeys/__main__.py b/examples/hotkeys/__main__.py index e64ca87..efc5803 100644 --- a/examples/hotkeys/__main__.py +++ b/examples/hotkeys/__main__.py @@ -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") diff --git a/examples/levels/__main__.py b/examples/levels/__main__.py index 62e03a8..2fc2a03 100644 --- a/examples/levels/__main__.py +++ b/examples/levels/__main__.py @@ -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(" to exit>\n"): - if not cmd: - break + while _ := input("Press to exit\n"): + pass if __name__ == "__main__": - DEVICE = "Desktop Audio" - main() diff --git a/obsws_python/events.py b/obsws_python/events.py index 5ac828e..8328909 100644 --- a/obsws_python/events.py +++ b/obsws_python/events.py @@ -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 diff --git a/obsws_python/reqs.py b/obsws_python/reqs.py index 2cef993..9c14895 100644 --- a/obsws_python/reqs.py +++ b/obsws_python/reqs.py @@ -31,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( @@ -42,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: diff --git a/obsws_python/version.py b/obsws_python/version.py index a985142..a55413d 100644 --- a/obsws_python/version.py +++ b/obsws_python/version.py @@ -1 +1 @@ -version = "1.6.2" +version = "1.7.0"