6 Commits

Author SHA1 Message Date
78f9fc7f53 add entry point docstring 2026-04-01 12:28:05 +01:00
f75cb98d67 add v2.0.0 to CHANGELOG 2026-04-01 12:25:01 +01:00
d6a26fda34 update README 2026-03-25 05:47:02 +00:00
efde969527 upd CHANGELOG with note about {Client}.wait() 2026-03-25 05:46:48 +00:00
336a52d172 add block_forever example
update example READMEs

add script entry point for block_forever example
add poe task block-forever
2026-03-25 05:46:14 +00:00
e1fa0eea79 {Client}.sio is now a private attribute
{Client}.wait() added to expose {Client}._sio.wait() and {Client}._sio.sleep()
2026-03-25 05:40:20 +00:00
9 changed files with 142 additions and 22 deletions

View File

@@ -8,7 +8,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
The following changes are proposals for v2.
- [x]
## [2.0.0] - 2026-04-01
### Added
- wait() method on the Client class, it's a convenience method that exposes {socketio.Client}.sleep() and {socketio.Client}.wait().
### Fixed
@@ -22,8 +28,7 @@ The following changes are proposals for v2.
### Changed
- loguru is now used for logging. See the events example for a demonstration.
- loguru is now used for logging. See the examples for a demonstration.
## [1.1.2] - 2024-11-06

View File

@@ -41,23 +41,28 @@ def main():
client.obs.on('twitch_account', on_twitch_event)
# run for 30 seconds then disconnect client from server
client.sio.sleep(30)
client.wait(30)
if __name__ == '__main__':
main()
```
> note: From the [SocketIO docs](https://python-socketio.readthedocs.io/en/latest/client.html#managing-background-tasks), `client.sio.wait()` may be used if your application has nothing to do in the main thread.
### Client class
*`streamlabsio.connect(*, token: str, raw: bool = False)`*
*`streamlabsio.connect(*, token: str, raw: bool = False) -> Client`*
The following keyword arguments may be passed:
- token: Streamlabs SocketIO api token.
- raw: Receive raw data messages as json objects.
#### methods
*wait(self, seconds: float | None = None) -> None*
- float: Time in seconds to block the main thread
- If None, the method will block indefinitely.
### Event Data Attributes
For event data you may inspect the available attributes using `attrs()`.

View File

@@ -0,0 +1,18 @@
## About
This example demonstrates the following:
- How to register callback functions for different kinds of events.
- How to view the logs emitted by the streamlabsio library.
- How to use the raw data returned by the callback functions.
- How to use {Client}.wait() to block the main thread indefinitely.
## Configure
The script expects the Streamlabs token to be loaded into the environment with key `STREAMLABS_TOKEN`.
If you're running the script with `poetry poe block-forever` then poe is configured to load a `.env` file in the root of the repository.
## Use
Run the script and trigger any of the events with `Test Widgets` in the Streamlabs GUI.

View File

@@ -0,0 +1,55 @@
import os
from loguru import logger
import streamlabsio
logger.enable('streamlabsio')
def on_streamlabs_event(event, data):
match event:
case 'donation':
print('{name} donated {amount}! With message: {message}'.format(**data))
def on_twitch_event(event, data):
event_message = {
'follow': 'Received follow from {name}',
'bits': '{name} donated {amount} bits! With message: {message}',
'subscription': '{name} just subscribed for {months} months!',
'raid': '{name} just raided with {raiders} raiders!',
'host': '{name} just hosted with {viewers} viewers!',
}
if event in event_message:
print(event_message[event].format(**data))
def on_youtube_event(event, data):
event_message = {
'follow': 'Received follow from {name}',
'superchat': '{name} donated {displayString} with a superchat! With comment: {comment}',
'subscription': '{name} just subscribed for {months} months!',
}
if event in event_message:
print(event_message[event].format(**data))
def main():
try:
with streamlabsio.connect(
token=os.getenv('STREAMLABS_TOKEN'), raw=True
) as client:
client.obs.on('streamlabs', on_streamlabs_event)
client.obs.on('twitch_account', on_twitch_event)
client.obs.on('youtube_account', on_youtube_event)
client.wait()
except KeyboardInterrupt:
pass
if __name__ == '__main__':
main()

View File

@@ -1,18 +1,18 @@
## About
To view the logs emitted by the streamlabsio library simply add the following to your code:
This example demonstrates the following:
```python
from loguru import logger
logger.enable('streamlabsio')
```
- How to register callback functions for different kinds of events.
- How to view the logs emitted by the streamlabsio library.
- How to print the attributes of an event data dataclass using the *attrs()* method.
- How to use dataclass methods on the dataclasses, this case *asdict*.
- How to use {Client}.wait() to block the main thread for a period of time.
## Configure
The script expects the Streamlabs token to be loaded into the environment with key `STREAMLABS_TOKEN`.
If you're running the script with `poetry poe` then poe is configured to load a `.env` file in the root of the repository.
If you're running the script with `poetry poe events` then poe is configured to load a `.env` file in the root of the repository.
## Use

View File

@@ -9,6 +9,8 @@ logger.enable('streamlabsio')
def on_streamlabs_event(event, data):
print(data.attrs())
match event:
case 'donation':
print(f'{data.name} donated {data.amount}! With message: {data.message}')
@@ -44,7 +46,7 @@ def main():
client.obs.on('twitch_account', on_twitch_event)
client.obs.on('youtube_account', on_youtube_event)
client.sio.sleep(30)
client.wait(30)
if __name__ == '__main__':

View File

@@ -27,6 +27,7 @@ envfile = ".env"
[tool.poe.tasks]
events.script = "scripts:ex_events"
block-forever.script = "scripts:ex_block_forever"
[tool.ruff]
exclude = [

View File

@@ -6,3 +6,11 @@ from pathlib import Path
def ex_events():
scriptpath = Path.cwd() / 'examples' / 'events' / '.'
subprocess.run([sys.executable, str(scriptpath)])
def ex_block_forever():
scriptpath = Path.cwd() / 'examples' / 'block_forever' / '.'
try:
subprocess.run([sys.executable, str(scriptpath)])
except KeyboardInterrupt:
sys.exit(0)

View File

@@ -17,15 +17,15 @@ class Client:
self._logger = logger.bind(name=self.__class__.__name__)
self._token = token
self._raw = raw
self.sio = socketio.Client()
self.sio.on('connect', self._connect_handler)
self.sio.on('event', self._event_handler)
self.sio.on('disconnect', self._disconnect_handler)
self._sio = socketio.Client()
self._sio.on('connect', self._connect_handler)
self._sio.on('event', self._event_handler)
self._sio.on('disconnect', self._disconnect_handler)
self.obs = Observable()
def __enter__(self) -> 'Client':
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:
self._logger.exception('Connection to Streamlabs Socket API failed')
ERR_MSG = 'Failed to connect to Streamlabs Socket API. Please check your token and network connection.'
@@ -33,14 +33,31 @@ class Client:
return self
def __exit__(self, exc_type, exc_val, exc_tb) -> None:
self.sio.disconnect()
self._sio.disconnect()
def wait(self, seconds: float | None = None) -> None:
"""Exposes the wait and sleep methods of the socketio client to allow the user to keep the connection alive.
Args:
seconds (float | None): If None, the method will block indefinitely.
Returns:
None
"""
if seconds is None:
self._sio.wait()
else:
self._sio.sleep(seconds)
def _connect_handler(self) -> None:
self._logger.info('Connected to Streamlabs Socket API')
def _event_handler(self, data: dict) -> None:
"""
Handles incoming events and triggers corresponding OBS actions.
Handles incoming events and triggers the callback functions.
Args:
data (dict): The event data containing information about the event.
Expected keys:
@@ -77,4 +94,13 @@ class Client:
def request_client_object(*, token: str, raw: bool = False) -> Client:
"""Entry point for users to request a Client object.
Args:
token (str): The authentication token for the Streamlabs Socket API.
raw (bool, optional): If True, the client will return raw event data. Defaults to False.
Returns:
Client: An instance of the Client class.
"""
return Client(token=token, raw=raw)