mirror of
https://github.com/onyx-and-iris/streamlabs-socketio-py
synced 2025-01-30 23:00:49 +00:00
wrap exceptions in _token_from_toml and raise SteamlabsSIOError errors
remove the assert from _token_from_toml replace self.streamlabs,self.twitch and self.youtube with self.event_types
This commit is contained in:
parent
b655fd6360
commit
0b67bcd832
@ -1,11 +1,11 @@
|
|||||||
import logging
|
import logging
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Optional
|
from typing import Any, Union
|
||||||
|
|
||||||
import socketio
|
import socketio
|
||||||
from observable import Observable
|
from observable import Observable
|
||||||
|
|
||||||
from .error import SteamlabsSIOConnectionError
|
from .error import SteamlabsSIOConnectionError, SteamlabsSIOError
|
||||||
from .models import as_dataclass
|
from .models import as_dataclass
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@ -17,93 +17,128 @@ class Client:
|
|||||||
self.token = token or self._token_from_toml()
|
self.token = token or self._token_from_toml()
|
||||||
self._raw = raw
|
self._raw = raw
|
||||||
self.sio = socketio.Client()
|
self.sio = socketio.Client()
|
||||||
self.sio.on("connect", self.connect_handler)
|
self.sio.on('connect', self.connect_handler)
|
||||||
self.sio.on("event", self.event_handler)
|
self.sio.on('event', self.event_handler)
|
||||||
self.sio.on("disconnect", self.disconnect_handler)
|
self.sio.on('disconnect', self.disconnect_handler)
|
||||||
self.obs = Observable()
|
self.obs = Observable()
|
||||||
self.streamlabs = ("donation",)
|
self.event_types: set[str] = (
|
||||||
self.twitch = ("follow", "subscription", "host", "bits", "raid")
|
{'donation'} # streamlabs
|
||||||
self.youtube = ("follow", "subscription", "superchat")
|
| {'follow', 'subscription', 'host', 'bits', 'raid'} # twitch
|
||||||
|
| {'follow', 'subscription', 'superchat'} # youtube
|
||||||
|
)
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
try:
|
try:
|
||||||
self.sio.connect(f"https://sockets.streamlabs.com?token={self.token}")
|
self.sio.connect(f'https://sockets.streamlabs.com?token={self.token}')
|
||||||
except socketio.exceptions.ConnectionError as e:
|
except socketio.exceptions.ConnectionError as e:
|
||||||
self.logger.exception(f"{type(e).__name__}: {e}")
|
self.logger.exception(f'{type(e).__name__}: {e}')
|
||||||
raise SteamlabsSIOConnectionError(
|
raise SteamlabsSIOConnectionError(
|
||||||
"no connection could be established to the Streamlabs SIO server"
|
'no connection could be established to the Streamlabs SIO server'
|
||||||
) from e
|
) from e
|
||||||
self.log_mode()
|
self.log_mode()
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||||
|
self.sio.disconnect()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def raw(self):
|
def raw(self) -> bool:
|
||||||
return self._raw
|
return self._raw
|
||||||
|
|
||||||
@raw.setter
|
@raw.setter
|
||||||
def raw(self, val):
|
def raw(self, val: bool) -> None:
|
||||||
self._raw = val
|
self._raw = val
|
||||||
self.log_mode()
|
self.log_mode()
|
||||||
|
|
||||||
def log_mode(self):
|
def log_mode(self):
|
||||||
info = (f"Running client in {'raw' if self.raw else 'normal'} mode.",)
|
info = (
|
||||||
if self.raw:
|
'Raw mode' if self.raw else 'Normal mode',
|
||||||
info += ("raw JSON messages will be passed to callbacks",)
|
'activated.',
|
||||||
else:
|
'JSON messages' if self.raw else 'Event objects',
|
||||||
info += ("event data objects will be passed to callbacks",)
|
'will be passed to callbacks.',
|
||||||
self.logger.info(" ".join(info))
|
)
|
||||||
|
self.logger.info(' '.join(info))
|
||||||
|
|
||||||
def _token_from_toml(self) -> str:
|
def _token_from_toml(self) -> str:
|
||||||
|
"""
|
||||||
|
Retrieves the Streamlabs token from a TOML configuration file.
|
||||||
|
This method attempts to load the token from a 'config.toml' file located
|
||||||
|
either in the current working directory or in the user's home configuration
|
||||||
|
directory under '.config/streamlabsio/'.
|
||||||
|
Returns:
|
||||||
|
str: The Streamlabs token retrieved from the TOML configuration file.
|
||||||
|
Raises:
|
||||||
|
SteamlabsSIOError: If no configuration file is found, if the file cannot
|
||||||
|
be decoded, or if the required 'streamlabs' section or 'token' key is
|
||||||
|
missing from the configuration file.
|
||||||
|
"""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import tomllib
|
import tomllib
|
||||||
except ModuleNotFoundError:
|
except ModuleNotFoundError:
|
||||||
import tomli as tomllib
|
import tomli as tomllib
|
||||||
|
|
||||||
def get_filepath() -> Optional[Path]:
|
def get_filepath() -> Union[Path, None]:
|
||||||
filepaths = (
|
filepaths = (
|
||||||
Path.cwd() / "config.toml",
|
Path.cwd() / 'config.toml',
|
||||||
Path.home() / ".config" / "streamlabsio" / "config.toml",
|
Path.home() / '.config' / 'streamlabsio' / 'config.toml',
|
||||||
)
|
)
|
||||||
for filepath in filepaths:
|
for filepath in filepaths:
|
||||||
if filepath.exists():
|
if filepath.exists():
|
||||||
return filepath
|
return filepath
|
||||||
|
return None
|
||||||
|
|
||||||
try:
|
|
||||||
filepath = get_filepath()
|
filepath = get_filepath()
|
||||||
if not filepath:
|
if not filepath:
|
||||||
raise FileNotFoundError("config.toml was not found")
|
raise SteamlabsSIOError('no token provided and no config.toml file found')
|
||||||
with open(filepath, "rb") as f:
|
|
||||||
|
try:
|
||||||
|
with open(filepath, 'rb') as f:
|
||||||
conn = tomllib.load(f)
|
conn = tomllib.load(f)
|
||||||
assert (
|
except tomllib.TOMLDecodeError as e:
|
||||||
"streamlabs" in conn and "token" in conn["streamlabs"]
|
ERR_MSG = f'Error decoding {filepath}: {e}'
|
||||||
), "expected [streamlabs][token] in config.toml"
|
self.logger.exception(ERR_MSG)
|
||||||
return conn["streamlabs"]["token"]
|
raise SteamlabsSIOError(ERR_MSG) from e
|
||||||
except (FileNotFoundError, tomllib.TOMLDecodeError) as e:
|
|
||||||
self.logger.error(f"{type(e).__name__}: {e}")
|
|
||||||
raise
|
|
||||||
|
|
||||||
def connect_handler(self):
|
if 'streamlabs' not in conn or 'token' not in conn['streamlabs']:
|
||||||
self.logger.info("Connected to Streamlabs Socket API")
|
ERR_MSG = (
|
||||||
|
'config.toml does not contain a "streamlabs" section '
|
||||||
|
'or the "streamlabs" section does not contain a "token" key'
|
||||||
|
)
|
||||||
|
self.logger.exception(ERR_MSG)
|
||||||
|
raise SteamlabsSIOError(ERR_MSG)
|
||||||
|
|
||||||
def event_handler(self, data):
|
return conn['streamlabs']['token']
|
||||||
if "for" in data and data["type"] in set(
|
|
||||||
self.streamlabs + self.twitch + self.youtube
|
def connect_handler(self) -> None:
|
||||||
):
|
self.logger.info('Connected to Streamlabs Socket API')
|
||||||
message = data["message"][0]
|
|
||||||
|
def event_handler(self, data: Any) -> None:
|
||||||
|
"""
|
||||||
|
Handles incoming events and triggers corresponding OBS actions.
|
||||||
|
Args:
|
||||||
|
data (dict): The event data containing information about the event.
|
||||||
|
Expected keys:
|
||||||
|
- 'for': The target of the event.
|
||||||
|
- 'type': The type of the event.
|
||||||
|
- 'message': A list containing the event message.
|
||||||
|
Returns:
|
||||||
|
None
|
||||||
|
"""
|
||||||
|
|
||||||
|
if 'for' in data and data['type'] in self.event_types:
|
||||||
|
message = data['message'][0]
|
||||||
self.obs.trigger(
|
self.obs.trigger(
|
||||||
data["for"],
|
data['for'],
|
||||||
data["type"],
|
data['type'],
|
||||||
message if self.raw else as_dataclass(data["type"], message),
|
message if self.raw else as_dataclass(data['type'], message),
|
||||||
)
|
)
|
||||||
self.logger.debug(data)
|
self.logger.debug(data)
|
||||||
|
|
||||||
def disconnect_handler(self):
|
def disconnect_handler(self) -> None:
|
||||||
self.logger.info("Disconnected from Streamlabs Socket API")
|
self.logger.info('Disconnected from Streamlabs Socket API')
|
||||||
|
|
||||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
||||||
self.sio.disconnect()
|
|
||||||
|
|
||||||
|
|
||||||
def connect(**kwargs):
|
def connect(**kwargs) -> Client:
|
||||||
SIO_cls = Client
|
SIO_cls = Client
|
||||||
return SIO_cls(**kwargs)
|
return SIO_cls(**kwargs)
|
||||||
|
Loading…
Reference in New Issue
Block a user