mirror of
https://github.com/onyx-and-iris/obsws-python.git
synced 2024-11-22 12:50:53 +00:00
Merge pull request #11 from onyx-and-iris/dev
check if auth required, context manager for reqclient + logging
This commit is contained in:
commit
f239173edb
@ -14,3 +14,5 @@ host = "localhost"
|
|||||||
port = 4455
|
port = 4455
|
||||||
password = "mystrongpass"
|
password = "mystrongpass"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Closing OBS ends the script.
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
|
import time
|
||||||
|
|
||||||
import obsws_python as obs
|
import obsws_python as obs
|
||||||
|
|
||||||
|
|
||||||
class Observer:
|
class Observer:
|
||||||
def __init__(self, cl):
|
def __init__(self):
|
||||||
self._cl = cl
|
self._client = obs.EventClient()
|
||||||
self._cl.callback.register(
|
self._client.callback.register(
|
||||||
[
|
[
|
||||||
self.on_current_program_scene_changed,
|
self.on_current_program_scene_changed,
|
||||||
self.on_scene_created,
|
self.on_scene_created,
|
||||||
@ -12,7 +14,8 @@ class Observer:
|
|||||||
self.on_exit_started,
|
self.on_exit_started,
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
print(f"Registered events: {self._cl.callback.get()}")
|
print(f"Registered events: {self._client.callback.get()}")
|
||||||
|
self.running = True
|
||||||
|
|
||||||
def on_current_program_scene_changed(self, data):
|
def on_current_program_scene_changed(self, data):
|
||||||
"""The current program scene has changed."""
|
"""The current program scene has changed."""
|
||||||
@ -29,13 +32,12 @@ class Observer:
|
|||||||
def on_exit_started(self, _):
|
def on_exit_started(self, _):
|
||||||
"""OBS has begun the shutdown process."""
|
"""OBS has begun the shutdown process."""
|
||||||
print(f"OBS closing!")
|
print(f"OBS closing!")
|
||||||
self._cl.unsubscribe()
|
self._client.unsubscribe()
|
||||||
|
self.running = False
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
cl = obs.EventClient()
|
observer = Observer()
|
||||||
observer = Observer(cl)
|
|
||||||
|
|
||||||
while cmd := input("<Enter> to exit\n"):
|
while observer.running:
|
||||||
if not cmd:
|
time.sleep(0.1)
|
||||||
break
|
|
||||||
|
@ -5,10 +5,10 @@ import obsws_python as obs
|
|||||||
|
|
||||||
|
|
||||||
class Observer:
|
class Observer:
|
||||||
def __init__(self, cl):
|
def __init__(self):
|
||||||
self._cl = cl
|
self._client = obs.EventClient()
|
||||||
self._cl.callback.register(self.on_current_program_scene_changed)
|
self._client.callback.register(self.on_current_program_scene_changed)
|
||||||
print(f"Registered events: {self._cl.callback.get()}")
|
print(f"Registered events: {self._client.callback.get()}")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def event_identifier(self):
|
def event_identifier(self):
|
||||||
@ -20,20 +20,19 @@ class Observer:
|
|||||||
|
|
||||||
|
|
||||||
def version():
|
def version():
|
||||||
resp = req_cl.get_version()
|
resp = req_client.get_version()
|
||||||
print(
|
print(
|
||||||
f"Running OBS version:{resp.obs_version} with websocket version:{resp.obs_web_socket_version}"
|
f"Running OBS version:{resp.obs_version} with websocket version:{resp.obs_web_socket_version}"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def set_scene(scene, *args):
|
def set_scene(scene, *args):
|
||||||
req_cl.set_current_program_scene(scene)
|
req_client.set_current_program_scene(scene)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
req_cl = obs.ReqClient()
|
req_client = obs.ReqClient()
|
||||||
ev_cl = obs.EventClient()
|
observer = Observer()
|
||||||
observer = Observer(ev_cl)
|
|
||||||
|
|
||||||
keyboard.add_hotkey("0", version)
|
keyboard.add_hotkey("0", version)
|
||||||
keyboard.add_hotkey("1", set_scene, args=("START",))
|
keyboard.add_hotkey("1", set_scene, args=("START",))
|
||||||
|
@ -4,16 +4,15 @@ import obsws_python as obs
|
|||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
resp = cl.get_scene_list()
|
with obs.ReqClient() as client:
|
||||||
scenes = reversed(tuple(di.get("sceneName") for di in resp.scenes))
|
resp = client.get_scene_list()
|
||||||
|
scenes = [di.get("sceneName") for di in reversed(resp.scenes)]
|
||||||
|
|
||||||
for scene in scenes:
|
for scene in scenes:
|
||||||
print(f"Switching to scene {scene}")
|
print(f"Switching to scene {scene}")
|
||||||
cl.set_current_program_scene(scene)
|
client.set_current_program_scene(scene)
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
cl = obs.ReqClient()
|
|
||||||
|
|
||||||
main()
|
main()
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import base64
|
import base64
|
||||||
import hashlib
|
import hashlib
|
||||||
import json
|
import json
|
||||||
|
import logging
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from random import randint
|
from random import randint
|
||||||
|
|
||||||
@ -11,9 +12,11 @@ except ModuleNotFoundError:
|
|||||||
|
|
||||||
import websocket
|
import websocket
|
||||||
|
|
||||||
|
from .error import OBSSDKError
|
||||||
|
|
||||||
|
|
||||||
class ObsClient:
|
class ObsClient:
|
||||||
DELAY = 0.001
|
logger = logging.getLogger("baseclient.obsclient")
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
defaultkwargs = {
|
defaultkwargs = {
|
||||||
@ -23,7 +26,7 @@ class ObsClient:
|
|||||||
kwargs = defaultkwargs | kwargs
|
kwargs = defaultkwargs | kwargs
|
||||||
for attr, val in kwargs.items():
|
for attr, val in kwargs.items():
|
||||||
setattr(self, attr, val)
|
setattr(self, attr, val)
|
||||||
if not (self.host and self.port and self.password):
|
if not (self.host and self.port):
|
||||||
conn = self._conn_from_toml()
|
conn = self._conn_from_toml()
|
||||||
self.host = conn["host"]
|
self.host = conn["host"]
|
||||||
self.port = conn["port"]
|
self.port = conn["port"]
|
||||||
@ -40,50 +43,51 @@ class ObsClient:
|
|||||||
return conn["connection"]
|
return conn["connection"]
|
||||||
|
|
||||||
def authenticate(self):
|
def authenticate(self):
|
||||||
secret = base64.b64encode(
|
|
||||||
hashlib.sha256(
|
|
||||||
(
|
|
||||||
self.password + self.server_hello["d"]["authentication"]["salt"]
|
|
||||||
).encode()
|
|
||||||
).digest()
|
|
||||||
)
|
|
||||||
|
|
||||||
auth = base64.b64encode(
|
|
||||||
hashlib.sha256(
|
|
||||||
(
|
|
||||||
secret.decode()
|
|
||||||
+ self.server_hello["d"]["authentication"]["challenge"]
|
|
||||||
).encode()
|
|
||||||
).digest()
|
|
||||||
).decode()
|
|
||||||
|
|
||||||
payload = {
|
payload = {
|
||||||
"op": 1,
|
"op": 1,
|
||||||
"d": {
|
"d": {
|
||||||
"rpcVersion": 1,
|
"rpcVersion": 1,
|
||||||
"authentication": auth,
|
|
||||||
"eventSubscriptions": self.subs,
|
"eventSubscriptions": self.subs,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if "authentication" in self.server_hello["d"]:
|
||||||
|
secret = base64.b64encode(
|
||||||
|
hashlib.sha256(
|
||||||
|
(
|
||||||
|
self.password + self.server_hello["d"]["authentication"]["salt"]
|
||||||
|
).encode()
|
||||||
|
).digest()
|
||||||
|
)
|
||||||
|
|
||||||
|
auth = base64.b64encode(
|
||||||
|
hashlib.sha256(
|
||||||
|
(
|
||||||
|
secret.decode()
|
||||||
|
+ self.server_hello["d"]["authentication"]["challenge"]
|
||||||
|
).encode()
|
||||||
|
).digest()
|
||||||
|
).decode()
|
||||||
|
|
||||||
|
payload["d"]["authentication"] = auth
|
||||||
|
|
||||||
self.ws.send(json.dumps(payload))
|
self.ws.send(json.dumps(payload))
|
||||||
return self.ws.recv()
|
try:
|
||||||
|
response = json.loads(self.ws.recv())
|
||||||
|
return response["op"] == 2
|
||||||
|
except json.decoder.JSONDecodeError:
|
||||||
|
raise OBSSDKError("failed to identify client with the server")
|
||||||
|
|
||||||
def req(self, req_type, req_data=None):
|
def req(self, req_type, req_data=None):
|
||||||
|
id = randint(1, 1000)
|
||||||
|
self.logger.debug(f"Sending request with id {id}")
|
||||||
|
payload = {
|
||||||
|
"op": 6,
|
||||||
|
"d": {"requestType": req_type, "requestId": id},
|
||||||
|
}
|
||||||
if req_data:
|
if req_data:
|
||||||
payload = {
|
payload["d"]["requestData"] = req_data
|
||||||
"op": 6,
|
|
||||||
"d": {
|
|
||||||
"requestType": req_type,
|
|
||||||
"requestId": randint(1, 1000),
|
|
||||||
"requestData": req_data,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
else:
|
|
||||||
payload = {
|
|
||||||
"op": 6,
|
|
||||||
"d": {"requestType": req_type, "requestId": randint(1, 1000)},
|
|
||||||
}
|
|
||||||
self.ws.send(json.dumps(payload))
|
self.ws.send(json.dumps(payload))
|
||||||
response = json.loads(self.ws.recv())
|
response = json.loads(self.ws.recv())
|
||||||
|
self.logger.debug(f"Response received {response}")
|
||||||
return response["d"]
|
return response["d"]
|
||||||
|
@ -31,7 +31,7 @@ class Callback:
|
|||||||
for fn in iterator:
|
for fn in iterator:
|
||||||
if fn not in self._callbacks:
|
if fn not in self._callbacks:
|
||||||
self._callbacks.append(fn)
|
self._callbacks.append(fn)
|
||||||
except TypeError as e:
|
except TypeError:
|
||||||
if fns not in self._callbacks:
|
if fns not in self._callbacks:
|
||||||
self._callbacks.append(fns)
|
self._callbacks.append(fns)
|
||||||
|
|
||||||
@ -43,7 +43,7 @@ class Callback:
|
|||||||
for fn in iterator:
|
for fn in iterator:
|
||||||
if fn in self._callbacks:
|
if fn in self._callbacks:
|
||||||
self._callbacks.remove(fn)
|
self._callbacks.remove(fn)
|
||||||
except TypeError as e:
|
except TypeError:
|
||||||
if fns in self._callbacks:
|
if fns in self._callbacks:
|
||||||
self._callbacks.remove(fns)
|
self._callbacks.remove(fns)
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import json
|
import json
|
||||||
|
import logging
|
||||||
import time
|
import time
|
||||||
from enum import IntEnum
|
from enum import IntEnum
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
@ -20,6 +21,7 @@ Subs = IntEnum(
|
|||||||
|
|
||||||
|
|
||||||
class EventClient:
|
class EventClient:
|
||||||
|
logger = logging.getLogger("events.eventclient")
|
||||||
DELAY = 0.001
|
DELAY = 0.001
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
@ -40,10 +42,14 @@ class EventClient:
|
|||||||
}
|
}
|
||||||
kwargs = defaultkwargs | kwargs
|
kwargs = defaultkwargs | kwargs
|
||||||
self.base_client = ObsClient(**kwargs)
|
self.base_client = ObsClient(**kwargs)
|
||||||
self.base_client.authenticate()
|
if self.base_client.authenticate():
|
||||||
|
self.logger.info(f"Successfully identified {self} with the server")
|
||||||
self.callback = Callback()
|
self.callback = Callback()
|
||||||
self.subscribe()
|
self.subscribe()
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return type(self).__name__
|
||||||
|
|
||||||
def subscribe(self):
|
def subscribe(self):
|
||||||
worker = Thread(target=self.trigger, daemon=True)
|
worker = Thread(target=self.trigger, daemon=True)
|
||||||
worker.start()
|
worker.start()
|
||||||
@ -56,12 +62,13 @@ class EventClient:
|
|||||||
"""
|
"""
|
||||||
self.running = True
|
self.running = True
|
||||||
while self.running:
|
while self.running:
|
||||||
self.data = json.loads(self.base_client.ws.recv())
|
event = json.loads(self.base_client.ws.recv())
|
||||||
event, data = (
|
self.logger.debug(f"Event received {event}")
|
||||||
self.data["d"].get("eventType"),
|
type_, data = (
|
||||||
self.data["d"].get("eventData"),
|
event["d"].get("eventType"),
|
||||||
|
event["d"].get("eventData"),
|
||||||
)
|
)
|
||||||
self.callback.trigger(event, data if data else {})
|
self.callback.trigger(type_, data if data else {})
|
||||||
time.sleep(self.DELAY)
|
time.sleep(self.DELAY)
|
||||||
|
|
||||||
def unsubscribe(self):
|
def unsubscribe(self):
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import logging
|
||||||
|
|
||||||
from .baseclient import ObsClient
|
from .baseclient import ObsClient
|
||||||
from .error import OBSSDKError
|
from .error import OBSSDKError
|
||||||
from .util import as_dataclass
|
from .util import as_dataclass
|
||||||
@ -10,9 +12,21 @@ https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.
|
|||||||
|
|
||||||
|
|
||||||
class ReqClient:
|
class ReqClient:
|
||||||
|
logger = logging.getLogger("reqs.reqclient")
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
self.base_client = ObsClient(**kwargs)
|
self.base_client = ObsClient(**kwargs)
|
||||||
self.base_client.authenticate()
|
if self.base_client.authenticate():
|
||||||
|
self.logger.info(f"Successfully identified {self} with the server")
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __exit__(self, exc_type, exc_value, exc_traceback):
|
||||||
|
self.base_client.ws.close()
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return type(self).__name__
|
||||||
|
|
||||||
def send(self, param, data=None):
|
def send(self, param, data=None):
|
||||||
response = self.base_client.req(param, data)
|
response = self.base_client.req(param, data)
|
||||||
@ -486,7 +500,7 @@ class ReqClient:
|
|||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return self.send("GetSceneList")
|
return self.send("GetGroupList")
|
||||||
|
|
||||||
def get_current_program_scene(self):
|
def get_current_program_scene(self):
|
||||||
"""
|
"""
|
||||||
|
Loading…
Reference in New Issue
Block a user