mirror of
https://github.com/onyx-and-iris/streamlabs-socketio-py
synced 2026-04-07 13:43:30 +00:00
Compare commits
46 Commits
e92c3b2e6f
...
v2
| Author | SHA1 | Date | |
|---|---|---|---|
| 78f9fc7f53 | |||
| f75cb98d67 | |||
| d6a26fda34 | |||
| efde969527 | |||
| 336a52d172 | |||
| e1fa0eea79 | |||
| 77d252ebe2 | |||
| 428db5bead | |||
| ba35960790 | |||
| 4b383df9a4 | |||
| 84cc8f65fe | |||
|
|
7d276e53a9 | ||
| 84e1746032 | |||
|
|
f6b1e9d93e | ||
| eaa7355a13 | |||
| 306df31390 | |||
| 3555d5fe6c | |||
| 0b67bcd832 | |||
| b655fd6360 | |||
|
|
0d8941aee0 | ||
| 06f9811247 | |||
| 987311e8f9 | |||
| 245578c060 | |||
| 1348e02c28 | |||
| db5e992fb6 | |||
|
|
3c0562e5ec | ||
| 25ee6e5c82 | |||
|
|
3f5944bdcc | ||
| c15cb0ecc3 | |||
|
|
16b227ae79 | ||
| 02509e00fc | |||
|
|
f917a41eff | ||
| 1c0c40072f | |||
|
|
8d264c2b71 | ||
| 67b1d7c345 | |||
|
|
6f29aae530 | ||
| efabcdaf73 | |||
|
|
5ac31d8455 | ||
| 23ec17e3ef | |||
|
|
b5f42188ce | ||
| d41233508b | |||
| 822bdfb60d | |||
| 6e13e71a09 | |||
| 7bea4453fa | |||
| 7d7704dd28 | |||
| d9e8c5391a |
53
.github/workflows/publish.yml
vendored
Normal file
53
.github/workflows/publish.yml
vendored
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
name: Publish to PyPI
|
||||||
|
|
||||||
|
on:
|
||||||
|
release:
|
||||||
|
types: [published]
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- 'v*.*.*'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
python-version: '3.11'
|
||||||
|
|
||||||
|
- name: Install Poetry
|
||||||
|
run: |
|
||||||
|
pip install poetry==2.3.1
|
||||||
|
poetry --version
|
||||||
|
|
||||||
|
- name: Build package
|
||||||
|
run: |
|
||||||
|
poetry install --only-root
|
||||||
|
poetry build
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: dist
|
||||||
|
path: ./dist
|
||||||
|
|
||||||
|
pypi-publish:
|
||||||
|
needs: build
|
||||||
|
name: Upload release to PyPI
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
environment:
|
||||||
|
name: pypi
|
||||||
|
url: https://pypi.org/project/streamlabs-socketio-py/
|
||||||
|
permissions:
|
||||||
|
id-token: write
|
||||||
|
steps:
|
||||||
|
- uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: dist
|
||||||
|
path: ./dist
|
||||||
|
|
||||||
|
- name: Publish package distributions to PyPI
|
||||||
|
uses: pypa/gh-action-pypi-publish@release/v1
|
||||||
|
with:
|
||||||
|
packages-dir: ./dist
|
||||||
19
.github/workflows/ruff.yml
vendored
Normal file
19
.github/workflows/ruff.yml
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
name: Ruff
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
|
||||||
|
pull_request:
|
||||||
|
branches: [main]
|
||||||
|
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
ruff:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
- uses: astral-sh/ruff-action@v3
|
||||||
|
with:
|
||||||
|
args: 'format --check --diff'
|
||||||
99
.gitignore
vendored
99
.gitignore
vendored
@@ -1,6 +1,9 @@
|
|||||||
|
# Generated by ignr: github.com/onyx-and-iris/ignr
|
||||||
|
|
||||||
|
## Python ##
|
||||||
# Byte-compiled / optimized / DLL files
|
# Byte-compiled / optimized / DLL files
|
||||||
__pycache__/
|
__pycache__/
|
||||||
*.py[cod]
|
*.py[codz]
|
||||||
*$py.class
|
*$py.class
|
||||||
|
|
||||||
# C extensions
|
# C extensions
|
||||||
@@ -20,7 +23,6 @@ parts/
|
|||||||
sdist/
|
sdist/
|
||||||
var/
|
var/
|
||||||
wheels/
|
wheels/
|
||||||
pip-wheel-metadata/
|
|
||||||
share/python-wheels/
|
share/python-wheels/
|
||||||
*.egg-info/
|
*.egg-info/
|
||||||
.installed.cfg
|
.installed.cfg
|
||||||
@@ -47,9 +49,10 @@ htmlcov/
|
|||||||
nosetests.xml
|
nosetests.xml
|
||||||
coverage.xml
|
coverage.xml
|
||||||
*.cover
|
*.cover
|
||||||
*.py,cover
|
*.py.cover
|
||||||
.hypothesis/
|
.hypothesis/
|
||||||
.pytest_cache/
|
.pytest_cache/
|
||||||
|
cover/
|
||||||
|
|
||||||
# Translations
|
# Translations
|
||||||
*.mo
|
*.mo
|
||||||
@@ -72,6 +75,7 @@ instance/
|
|||||||
docs/_build/
|
docs/_build/
|
||||||
|
|
||||||
# PyBuilder
|
# PyBuilder
|
||||||
|
.pybuilder/
|
||||||
target/
|
target/
|
||||||
|
|
||||||
# Jupyter Notebook
|
# Jupyter Notebook
|
||||||
@@ -82,7 +86,9 @@ profile_default/
|
|||||||
ipython_config.py
|
ipython_config.py
|
||||||
|
|
||||||
# pyenv
|
# pyenv
|
||||||
.python-version
|
# For a library or package, you might want to ignore these files since the code is
|
||||||
|
# intended to run in multiple environments; otherwise, check them in:
|
||||||
|
# .python-version
|
||||||
|
|
||||||
# pipenv
|
# pipenv
|
||||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||||
@@ -91,7 +97,37 @@ ipython_config.py
|
|||||||
# install all needed dependencies.
|
# install all needed dependencies.
|
||||||
#Pipfile.lock
|
#Pipfile.lock
|
||||||
|
|
||||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
# UV
|
||||||
|
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
||||||
|
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||||
|
# commonly ignored for libraries.
|
||||||
|
#uv.lock
|
||||||
|
|
||||||
|
# poetry
|
||||||
|
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
||||||
|
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||||
|
# commonly ignored for libraries.
|
||||||
|
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
||||||
|
#poetry.lock
|
||||||
|
#poetry.toml
|
||||||
|
|
||||||
|
# pdm
|
||||||
|
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
||||||
|
# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
|
||||||
|
# https://pdm-project.org/en/latest/usage/project/#working-with-version-control
|
||||||
|
#pdm.lock
|
||||||
|
#pdm.toml
|
||||||
|
.pdm-python
|
||||||
|
.pdm-build/
|
||||||
|
|
||||||
|
# pixi
|
||||||
|
# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
|
||||||
|
#pixi.lock
|
||||||
|
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
|
||||||
|
# in the .venv directory. It is recommended not to include this directory in version control.
|
||||||
|
.pixi
|
||||||
|
|
||||||
|
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
||||||
__pypackages__/
|
__pypackages__/
|
||||||
|
|
||||||
# Celery stuff
|
# Celery stuff
|
||||||
@@ -103,6 +139,7 @@ celerybeat.pid
|
|||||||
|
|
||||||
# Environments
|
# Environments
|
||||||
.env
|
.env
|
||||||
|
.envrc
|
||||||
.venv
|
.venv
|
||||||
env/
|
env/
|
||||||
venv/
|
venv/
|
||||||
@@ -128,12 +165,50 @@ dmypy.json
|
|||||||
# Pyre type checker
|
# Pyre type checker
|
||||||
.pyre/
|
.pyre/
|
||||||
|
|
||||||
.vscode/
|
# pytype static type analyzer
|
||||||
|
.pytype/
|
||||||
|
|
||||||
# toml config
|
# Cython debug symbols
|
||||||
config.toml
|
cython_debug/
|
||||||
|
|
||||||
# test
|
# PyCharm
|
||||||
quick.py
|
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
||||||
logging.json
|
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||||
tests/
|
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||||
|
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||||
|
#.idea/
|
||||||
|
|
||||||
|
# Abstra
|
||||||
|
# Abstra is an AI-powered process automation framework.
|
||||||
|
# Ignore directories containing user credentials, local state, and settings.
|
||||||
|
# Learn more at https://abstra.io/docs
|
||||||
|
.abstra/
|
||||||
|
|
||||||
|
# Visual Studio Code
|
||||||
|
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
|
||||||
|
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
|
||||||
|
# and can be added to the global gitignore or merged into this file. However, if you prefer,
|
||||||
|
# you could uncomment the following to ignore the entire vscode folder
|
||||||
|
# .vscode/
|
||||||
|
|
||||||
|
# Ruff stuff:
|
||||||
|
.ruff_cache/
|
||||||
|
|
||||||
|
# PyPI configuration file
|
||||||
|
.pypirc
|
||||||
|
|
||||||
|
# Cursor
|
||||||
|
# Cursor is an AI-powered code editor. `.cursorignore` specifies files/directories to
|
||||||
|
# exclude from AI features like autocomplete and code analysis. Recommended for sensitive data
|
||||||
|
# refer to https://docs.cursor.com/context/ignore-files
|
||||||
|
.cursorignore
|
||||||
|
.cursorindexingignore
|
||||||
|
|
||||||
|
# Marimo
|
||||||
|
marimo/_static/
|
||||||
|
marimo/_lsp/
|
||||||
|
__marimo__/
|
||||||
|
|
||||||
|
# End of ignr
|
||||||
|
|
||||||
|
test-*.py
|
||||||
|
|||||||
13
.pre-commit-config.yaml
Normal file
13
.pre-commit-config.yaml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
repos:
|
||||||
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
|
rev: v2.3.0
|
||||||
|
hooks:
|
||||||
|
- id: check-yaml
|
||||||
|
- id: end-of-file-fixer
|
||||||
|
- id: trailing-whitespace
|
||||||
|
|
||||||
|
- repo: https://github.com/python-poetry/poetry
|
||||||
|
rev: '2.3.2'
|
||||||
|
hooks:
|
||||||
|
- id: poetry-check
|
||||||
|
- id: poetry-lock
|
||||||
29
CHANGELOG.md
29
CHANGELOG.md
@@ -10,6 +10,32 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
- [x]
|
- [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
|
||||||
|
|
||||||
|
- The returned dataclasses now work properly with dataclass methods such as `asdict`. See the events example.
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
|
||||||
|
- Built-in support for loading the token from a config.toml. This is a job better left to the library consumer.
|
||||||
|
- {Client}.raw property, you can still configure the Client to return raw data via the raw kwarg.
|
||||||
|
- Support for python versions 3.8 and 3.9.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- loguru is now used for logging. See the examples for a demonstration.
|
||||||
|
|
||||||
|
## [1.1.2] - 2024-11-06
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- [PR #8][pr-8] fixes bug receiving `raid` events.
|
||||||
|
|
||||||
## [1.0.0] - 2023-06-28
|
## [1.0.0] - 2023-06-28
|
||||||
|
|
||||||
The only potential breaking change, a new error class raised if the initial connection fails.
|
The only potential breaking change, a new error class raised if the initial connection fails.
|
||||||
@@ -28,3 +54,6 @@ The only potential breaking change, a new error class raised if the initial conn
|
|||||||
- Python minimum required version changed to 3.8
|
- Python minimum required version changed to 3.8
|
||||||
- new error class
|
- new error class
|
||||||
- `SteamlabsSIOConnectionError` raised on a connection error
|
- `SteamlabsSIOConnectionError` raised on a connection error
|
||||||
|
|
||||||
|
|
||||||
|
[pr-8]: https://github.com/onyx-and-iris/streamlabs-socketio-py/pull/8
|
||||||
|
|||||||
74
README.md
74
README.md
@@ -1,7 +1,7 @@
|
|||||||
[](https://badge.fury.io/py/streamlabsio)
|
[](https://badge.fury.io/py/streamlabsio)
|
||||||
[](https://github.com/onyx-and-iris/streamlabs-socketio-py/blob/dev/LICENSE)
|
[](https://github.com/onyx-and-iris/streamlabs-socketio-py/blob/dev/LICENSE)
|
||||||
[](https://github.com/psf/black)
|
[](https://python-poetry.org/)
|
||||||
[](https://pycqa.github.io/isort/)
|
[](https://github.com/astral-sh/ruff)
|
||||||
|
|
||||||
# A Python client for Streamlabs Socket API
|
# A Python client for Streamlabs Socket API
|
||||||
|
|
||||||
@@ -12,65 +12,58 @@ For an outline of past/future changes refer to: [CHANGELOG](CHANGELOG.md)
|
|||||||
- A Streamlabs Socket API key.
|
- A Streamlabs Socket API key.
|
||||||
- You can acquire this by logging into your Streamlabs.com dashboard then `Settings->Api Settings->API Tokens`
|
- You can acquire this by logging into your Streamlabs.com dashboard then `Settings->Api Settings->API Tokens`
|
||||||
|
|
||||||
- Python 3.8 or greater
|
- Python 3.10 or greater
|
||||||
|
|
||||||
### How to install using pip
|
### Install
|
||||||
|
|
||||||
```
|
```console
|
||||||
pip install streamlabsio
|
pip install streamlabsio
|
||||||
```
|
```
|
||||||
|
|
||||||
### How to Use
|
### Use
|
||||||
|
|
||||||
You may store your api key in a `config.toml` file, its contents should resemble:
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[streamlabs]
|
|
||||||
token = "<apikey>"
|
|
||||||
```
|
|
||||||
|
|
||||||
Place it next to your `__main__.py` file.
|
|
||||||
|
|
||||||
#### Otherwise:
|
|
||||||
|
|
||||||
You may pass it as a keyword argument.
|
|
||||||
|
|
||||||
Example `__main__.py`:
|
|
||||||
|
|
||||||
```python
|
```python
|
||||||
import streamlabsio
|
import streamlabsio
|
||||||
|
|
||||||
|
|
||||||
|
def on_streamlabs_event(event, data):
|
||||||
|
print(f'{event}: {data.attrs()}')
|
||||||
|
|
||||||
|
|
||||||
def on_twitch_event(event, data):
|
def on_twitch_event(event, data):
|
||||||
print(f"{event}: {data.attrs()}")
|
if event == 'follow':
|
||||||
|
print(f'{data.name} just followed!')
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
with streamlabsio.connect(token="<apikey>") as client:
|
with streamlabsio.connect(token="<API token>") as client:
|
||||||
client.obs.on("streamlabs", on_twitch_event)
|
client.obs.on('streamlabs', on_streamlabs_event)
|
||||||
client.obs.on("twitch_account", on_twitch_event)
|
client.obs.on('twitch_account', on_twitch_event)
|
||||||
|
|
||||||
# run for 30 seconds then disconnect client from server
|
# run for 30 seconds then disconnect client from server
|
||||||
client.sio.sleep(30)
|
client.wait(30)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == '__main__':
|
||||||
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
|
### Client class
|
||||||
`streamlabsio.connect(token="<apikey>", raw=False)`
|
*`streamlabsio.connect(*, token: str, raw: bool = False) -> Client`*
|
||||||
|
|
||||||
The following keyword arguments may be passed:
|
The following keyword arguments may be passed:
|
||||||
|
|
||||||
- `token`: str Streamlabs SocketIO api token.
|
- token: Streamlabs SocketIO api token.
|
||||||
- `raw`: boolean=False Receive raw data messages as json objects.
|
- raw: Receive raw data messages as json objects.
|
||||||
|
|
||||||
### Attributes
|
#### 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()`.
|
For event data you may inspect the available attributes using `attrs()`.
|
||||||
|
|
||||||
@@ -78,16 +71,23 @@ example:
|
|||||||
|
|
||||||
```python
|
```python
|
||||||
def on_twitch_event(event, data):
|
def on_twitch_event(event, data):
|
||||||
print(f"{event}: {data.attrs()}")
|
print(f'{event}: {data.attrs()}')
|
||||||
```
|
```
|
||||||
|
|
||||||
### Errors
|
### Errors
|
||||||
|
|
||||||
|
- `SteamlabsSIOError`: Base StreamlabsSIO error class
|
||||||
- `SteamlabsSIOConnectionError`: Exception raised when connection errors occur
|
- `SteamlabsSIOConnectionError`: Exception raised when connection errors occur
|
||||||
|
|
||||||
### Logging
|
### Logging
|
||||||
|
|
||||||
To view raw incoming event data set logging level to DEBUG. Check `debug` example.
|
To view the logs emitted by the streamlabsio library simply add the following to your code:
|
||||||
|
|
||||||
|
```python
|
||||||
|
from loguru import logger
|
||||||
|
|
||||||
|
logger.enable('streamlabsio')
|
||||||
|
```
|
||||||
|
|
||||||
### Official Documentation
|
### Official Documentation
|
||||||
|
|
||||||
|
|||||||
31
__main__.py
31
__main__.py
@@ -1,31 +0,0 @@
|
|||||||
import streamlabsio
|
|
||||||
|
|
||||||
|
|
||||||
def on_youtube_event(event, data):
|
|
||||||
print(f"{event}: {data.attrs()}")
|
|
||||||
|
|
||||||
|
|
||||||
def on_twitch_event(event, data):
|
|
||||||
if event == "follow":
|
|
||||||
print(f"Received follow from {data.name}")
|
|
||||||
elif event == "bits":
|
|
||||||
print(f"{data.name} donated {data.amount} bits! With message: {data.message}")
|
|
||||||
elif event == "donation":
|
|
||||||
print(
|
|
||||||
f"{data.name} donated {data.formatted_amount}! With message: {data.message}"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
# read token from config.toml
|
|
||||||
with streamlabsio.connect() as client:
|
|
||||||
client.obs.on("streamlabs", on_twitch_event)
|
|
||||||
client.obs.on("twitch_account", on_twitch_event)
|
|
||||||
client.obs.on("youtube_account", on_youtube_event)
|
|
||||||
|
|
||||||
# run for 30 seconds then disconnect client from server
|
|
||||||
client.sio.sleep(30)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
18
examples/block_forever/README.md
Normal file
18
examples/block_forever/README.md
Normal 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.
|
||||||
55
examples/block_forever/__main__.py
Normal file
55
examples/block_forever/__main__.py
Normal 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()
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
## About
|
|
||||||
|
|
||||||
The underlying socketio and engineio packages emit a lot of logs so it may be useful to filter out streamlabsio logs.
|
|
||||||
|
|
||||||
This example prints raw messages whenever Client.event_handler() receives data.
|
|
||||||
|
|
||||||
## Use
|
|
||||||
|
|
||||||
Run the script and trigger any of the events with `Test Widgets` in the Streamlabs GUI.
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
from logging import config
|
|
||||||
|
|
||||||
import streamlabsio
|
|
||||||
|
|
||||||
config.dictConfig(
|
|
||||||
{
|
|
||||||
"version": 1,
|
|
||||||
"formatters": {
|
|
||||||
"standard": {
|
|
||||||
"format": "%(asctime)s,%(msecs)d %(name)s %(levelname)s %(message)s"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"handlers": {
|
|
||||||
"stream": {
|
|
||||||
"level": "DEBUG",
|
|
||||||
"class": "logging.StreamHandler",
|
|
||||||
"formatter": "standard",
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"loggers": {"streamlabsio.client": {"handlers": ["stream"], "level": "DEBUG"}},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def on_youtube_event(event, data):
|
|
||||||
print(f"{event}: {data.attrs()}")
|
|
||||||
|
|
||||||
|
|
||||||
def on_twitch_event(event, data):
|
|
||||||
if event == "follow":
|
|
||||||
print(f"Received follow from {data.name}")
|
|
||||||
elif event == "bits":
|
|
||||||
print(f"{data.name} donated {data.amount} bits! With message: {data.message}")
|
|
||||||
elif event == "donation":
|
|
||||||
print(
|
|
||||||
f"{data.name} donated {data.formatted_amount}! With message: {data.message}"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
with streamlabsio.connect() as client:
|
|
||||||
client.obs.on("streamlabs", on_twitch_event)
|
|
||||||
client.obs.on("twitch_account", on_twitch_event)
|
|
||||||
client.obs.on("youtube_account", on_youtube_event)
|
|
||||||
|
|
||||||
client.sio.sleep(30)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
19
examples/events/README.md
Normal file
19
examples/events/README.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
## 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 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 events` 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.
|
||||||
53
examples/events/__main__.py
Normal file
53
examples/events/__main__.py
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
import os
|
||||||
|
from dataclasses import asdict
|
||||||
|
|
||||||
|
from loguru import logger
|
||||||
|
|
||||||
|
import streamlabsio
|
||||||
|
|
||||||
|
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}')
|
||||||
|
|
||||||
|
|
||||||
|
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(**asdict(data)))
|
||||||
|
|
||||||
|
|
||||||
|
def on_youtube_event(event, data):
|
||||||
|
event_message = {
|
||||||
|
'follow': 'Received follow from {name}',
|
||||||
|
'superchat': '{name} donated {display_string} with a superchat! With comment: {comment}',
|
||||||
|
'subscription': '{name} just subscribed for {months} months!',
|
||||||
|
}
|
||||||
|
|
||||||
|
if event in event_message:
|
||||||
|
print(event_message[event].format(**asdict(data)))
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
with streamlabsio.connect(token=os.getenv('STREAMLABS_TOKEN')) 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(30)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
659
poetry.lock
generated
659
poetry.lock
generated
@@ -1,457 +1,420 @@
|
|||||||
[[package]]
|
# This file is automatically @generated by Poetry 2.3.2 and should not be changed by hand.
|
||||||
name = "black"
|
|
||||||
version = "22.12.0"
|
|
||||||
description = "The uncompromising code formatter."
|
|
||||||
category = "dev"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.7"
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
click = ">=8.0.0"
|
|
||||||
mypy-extensions = ">=0.4.3"
|
|
||||||
pathspec = ">=0.9.0"
|
|
||||||
platformdirs = ">=2"
|
|
||||||
tomli = {version = ">=1.1.0", markers = "python_full_version < \"3.11.0a7\""}
|
|
||||||
typed-ast = {version = ">=1.4.2", markers = "python_version < \"3.8\" and implementation_name == \"cpython\""}
|
|
||||||
typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""}
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
colorama = ["colorama (>=0.4.3)"]
|
|
||||||
d = ["aiohttp (>=3.7.4)"]
|
|
||||||
jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
|
|
||||||
uvloop = ["uvloop (>=0.15.2)"]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cachetools"
|
name = "bidict"
|
||||||
version = "5.3.1"
|
version = "0.23.1"
|
||||||
description = "Extensible memoizing collections and decorators"
|
description = "The bidirectional mapping library for Python."
|
||||||
category = "dev"
|
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.8"
|
||||||
|
groups = ["main"]
|
||||||
|
files = [
|
||||||
|
{file = "bidict-0.23.1-py3-none-any.whl", hash = "sha256:5dae8d4d79b552a71cbabc7deb25dfe8ce710b17ff41711e13010ead2abfc3e5"},
|
||||||
|
{file = "bidict-0.23.1.tar.gz", hash = "sha256:03069d763bc387bbd20e7d49914e75fc4132a41937fa3405417e1a5a2d006d71"},
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "certifi"
|
name = "certifi"
|
||||||
version = "2023.5.7"
|
version = "2026.2.25"
|
||||||
description = "Python package for providing Mozilla's CA Bundle."
|
description = "Python package for providing Mozilla's CA Bundle."
|
||||||
category = "main"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.6"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "chardet"
|
|
||||||
version = "5.1.0"
|
|
||||||
description = "Universal encoding detector for Python 3"
|
|
||||||
category = "dev"
|
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
|
groups = ["main"]
|
||||||
|
files = [
|
||||||
|
{file = "certifi-2026.2.25-py3-none-any.whl", hash = "sha256:027692e4402ad994f1c42e52a4997a9763c646b73e4096e4d5d6db8af1d6f0fa"},
|
||||||
|
{file = "certifi-2026.2.25.tar.gz", hash = "sha256:e887ab5cee78ea814d3472169153c2d12cd43b14bd03329a39a9c6e2e80bfba7"},
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "charset-normalizer"
|
name = "charset-normalizer"
|
||||||
version = "3.1.0"
|
version = "3.4.6"
|
||||||
description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
|
description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
|
||||||
category = "main"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.7.0"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "click"
|
|
||||||
version = "8.1.3"
|
|
||||||
description = "Composable command line interface toolkit"
|
|
||||||
category = "dev"
|
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
|
groups = ["main"]
|
||||||
[package.dependencies]
|
files = [
|
||||||
colorama = {version = "*", markers = "platform_system == \"Windows\""}
|
{file = "charset_normalizer-3.4.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2e1d8ca8611099001949d1cdfaefc510cf0f212484fe7c565f735b68c78c3c95"},
|
||||||
importlib-metadata = {version = "*", markers = "python_version < \"3.8\""}
|
{file = "charset_normalizer-3.4.6-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e25369dc110d58ddf29b949377a93e0716d72a24f62bad72b2b39f155949c1fd"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:259695e2ccc253feb2a016303543d691825e920917e31f894ca1a687982b1de4"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:dda86aba335c902b6149a02a55b38e96287157e609200811837678214ba2b1db"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:51fb3c322c81d20567019778cb5a4a6f2dc1c200b886bc0d636238e364848c89"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:4482481cb0572180b6fd976a4d5c72a30263e98564da68b86ec91f0fe35e8565"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:39f5068d35621da2881271e5c3205125cc456f54e9030d3f723288c873a71bf9"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:8bea55c4eef25b0b19a0337dc4e3f9a15b00d569c77211fa8cde38684f234fb7"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:f0cdaecd4c953bfae0b6bb64910aaaca5a424ad9c72d85cb88417bb9814f7550"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:150b8ce8e830eb7ccb029ec9ca36022f756986aaaa7956aad6d9ec90089338c0"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:e68c14b04827dd76dcbd1aeea9e604e3e4b78322d8faf2f8132c7138efa340a8"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:3778fd7d7cd04ae8f54651f4a7a0bd6e39a0cf20f801720a4c21d80e9b7ad6b0"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:dad6e0f2e481fffdcf776d10ebee25e0ef89f16d691f1e5dee4b586375fdc64b"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp310-cp310-win32.whl", hash = "sha256:74a2e659c7ecbc73562e2a15e05039f1e22c75b7c7618b4b574a3ea9118d1557"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp310-cp310-win_amd64.whl", hash = "sha256:aa9cccf4a44b9b62d8ba8b4dd06c649ba683e4bf04eea606d2e94cfc2d6ff4d6"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp310-cp310-win_arm64.whl", hash = "sha256:e985a16ff513596f217cee86c21371b8cd011c0f6f056d0920aa2d926c544058"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:82060f995ab5003a2d6e0f4ad29065b7672b6593c8c63559beefe5b443242c3e"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:60c74963d8350241a79cb8feea80e54d518f72c26db618862a8f53e5023deaf9"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f6e4333fb15c83f7d1482a76d45a0818897b3d33f00efd215528ff7c51b8e35d"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:bc72863f4d9aba2e8fd9085e63548a324ba706d2ea2c83b260da08a59b9482de"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9cc4fc6c196d6a8b76629a70ddfcd4635a6898756e2d9cac5565cf0654605d73"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:0c173ce3a681f309f31b87125fecec7a5d1347261ea11ebbb856fa6006b23c8c"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c907cdc8109f6c619e6254212e794d6548373cc40e1ec75e6e3823d9135d29cc"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:404a1e552cf5b675a87f0651f8b79f5f1e6fd100ee88dc612f89aa16abd4486f"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:e3c701e954abf6fc03a49f7c579cc80c2c6cc52525340ca3186c41d3f33482ef"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:7a6967aaf043bceabab5412ed6bd6bd26603dae84d5cb75bf8d9a74a4959d398"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:5feb91325bbceade6afab43eb3b508c63ee53579fe896c77137ded51c6b6958e"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:f820f24b09e3e779fe84c3c456cb4108a7aa639b0d1f02c28046e11bfcd088ed"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b35b200d6a71b9839a46b9b7fff66b6638bb52fc9658aa58796b0326595d3021"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp311-cp311-win32.whl", hash = "sha256:9ca4c0b502ab399ef89248a2c84c54954f77a070f28e546a85e91da627d1301e"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp311-cp311-win_amd64.whl", hash = "sha256:a9e68c9d88823b274cf1e72f28cb5dc89c990edf430b0bfd3e2fb0785bfeabf4"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp311-cp311-win_arm64.whl", hash = "sha256:97d0235baafca5f2b09cf332cc275f021e694e8362c6bb9c96fc9a0eb74fc316"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:2ef7fedc7a6ecbe99969cd09632516738a97eeb8bd7258bf8a0f23114c057dab"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a4ea868bc28109052790eb2b52a9ab33f3aa7adc02f96673526ff47419490e21"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:836ab36280f21fc1a03c99cd05c6b7af70d2697e374c7af0b61ed271401a72a2"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f1ce721c8a7dfec21fcbdfe04e8f68174183cf4e8188e0645e92aa23985c57ff"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0e28d62a8fc7a1fa411c43bd65e346f3bce9716dc51b897fbe930c5987b402d5"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:530d548084c4a9f7a16ed4a294d459b4f229db50df689bfe92027452452943a0"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:30f445ae60aad5e1f8bdbb3108e39f6fbc09f4ea16c815c66578878325f8f15a"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ac2393c73378fea4e52aa56285a3d64be50f1a12395afef9cce47772f60334c2"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:90ca27cd8da8118b18a52d5f547859cc1f8354a00cd1e8e5120df3e30d6279e5"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:8e5a94886bedca0f9b78fecd6afb6629142fd2605aa70a125d49f4edc6037ee6"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:695f5c2823691a25f17bc5d5ffe79fa90972cc34b002ac6c843bb8a1720e950d"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:231d4da14bcd9301310faf492051bee27df11f2bc7549bc0bb41fef11b82daa2"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a056d1ad2633548ca18ffa2f85c202cfb48b68615129143915b8dc72a806a923"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp312-cp312-win32.whl", hash = "sha256:c2274ca724536f173122f36c98ce188fd24ce3dad886ec2b7af859518ce008a4"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp312-cp312-win_amd64.whl", hash = "sha256:c8ae56368f8cc97c7e40a7ee18e1cedaf8e780cd8bc5ed5ac8b81f238614facb"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp312-cp312-win_arm64.whl", hash = "sha256:899d28f422116b08be5118ef350c292b36fc15ec2daeb9ea987c89281c7bb5c4"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:11afb56037cbc4b1555a34dd69151e8e069bee82e613a73bef6e714ce733585f"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:423fb7e748a08f854a08a222b983f4df1912b1daedce51a72bd24fe8f26a1843"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d73beaac5e90173ac3deb9928a74763a6d230f494e4bfb422c217a0ad8e629bf"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d60377dce4511655582e300dc1e5a5f24ba0cb229005a1d5c8d0cb72bb758ab8"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:530e8cebeea0d76bdcf93357aa5e41336f48c3dc709ac52da2bb167c5b8271d9"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:a26611d9987b230566f24a0a125f17fe0de6a6aff9f25c9f564aaa2721a5fb88"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:34315ff4fc374b285ad7f4a0bf7dcbfe769e1b104230d40f49f700d4ab6bbd84"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5f8ddd609f9e1af8c7bd6e2aca279c931aefecd148a14402d4e368f3171769fd"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:80d0a5615143c0b3225e5e3ef22c8d5d51f3f72ce0ea6fb84c943546c7b25b6c"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:92734d4d8d187a354a556626c221cd1a892a4e0802ccb2af432a1d85ec012194"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:613f19aa6e082cf96e17e3ffd89383343d0d589abda756b7764cf78361fd41dc"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:2b1a63e8224e401cafe7739f77efd3f9e7f5f2026bda4aead8e59afab537784f"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6cceb5473417d28edd20c6c984ab6fee6c6267d38d906823ebfe20b03d607dc2"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp313-cp313-win32.whl", hash = "sha256:d7de2637729c67d67cf87614b566626057e95c303bc0a55ffe391f5205e7003d"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp313-cp313-win_amd64.whl", hash = "sha256:572d7c822caf521f0525ba1bce1a622a0b85cf47ffbdae6c9c19e3b5ac3c4389"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp313-cp313-win_arm64.whl", hash = "sha256:a4474d924a47185a06411e0064b803c68be044be2d60e50e8bddcc2649957c1f"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:9cc6e6d9e571d2f863fa77700701dae73ed5f78881efc8b3f9a4398772ff53e8"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ef5960d965e67165d75b7c7ffc60a83ec5abfc5c11b764ec13ea54fbef8b4421"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b3694e3f87f8ac7ce279d4355645b3c878d24d1424581b46282f24b92f5a4ae2"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5d11595abf8dd942a77883a39d81433739b287b6aa71620f15164f8096221b30"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7bda6eebafd42133efdca535b04ccb338ab29467b3f7bf79569883676fc628db"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:bbc8c8650c6e51041ad1be191742b8b421d05bbd3410f43fa2a00c8db87678e8"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:22c6f0c2fbc31e76c3b8a86fba1a56eda6166e238c29cdd3d14befdb4a4e4815"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7edbed096e4a4798710ed6bc75dcaa2a21b68b6c356553ac4823c3658d53743a"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:7f9019c9cb613f084481bd6a100b12e1547cf2efe362d873c2e31e4035a6fa43"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:58c948d0d086229efc484fe2f30c2d382c86720f55cd9bc33591774348ad44e0"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:419a9d91bd238052642a51938af8ac05da5b3343becde08d5cdeab9046df9ee1"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:5273b9f0b5835ff0350c0828faea623c68bfa65b792720c453e22b25cc72930f"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:0e901eb1049fdb80f5bd11ed5ea1e498ec423102f7a9b9e4645d5b8204ff2815"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp314-cp314-win32.whl", hash = "sha256:b4ff1d35e8c5bd078be89349b6f3a845128e685e751b6ea1169cf2160b344c4d"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp314-cp314-win_amd64.whl", hash = "sha256:74119174722c4349af9708993118581686f343adc1c8c9c007d59be90d077f3f"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp314-cp314-win_arm64.whl", hash = "sha256:e5bcc1a1ae744e0bb59641171ae53743760130600da8db48cbb6e4918e186e4e"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:ad8faf8df23f0378c6d527d8b0b15ea4a2e23c89376877c598c4870d1b2c7866"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f5ea69428fa1b49573eef0cc44a1d43bebd45ad0c611eb7d7eac760c7ae771bc"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:06a7e86163334edfc5d20fe104db92fcd666e5a5df0977cb5680a506fe26cc8e"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e1f6e2f00a6b8edb562826e4632e26d063ac10307e80f7461f7de3ad8ef3f077"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:95b52c68d64c1878818687a473a10547b3292e82b6f6fe483808fb1468e2f52f"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:7504e9b7dc05f99a9bbb4525c67a2c155073b44d720470a148b34166a69c054e"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:172985e4ff804a7ad08eebec0a1640ece87ba5041d565fff23c8f99c1f389484"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:4be9f4830ba8741527693848403e2c457c16e499100963ec711b1c6f2049b7c7"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:79090741d842f564b1b2827c0b82d846405b744d31e84f18d7a7b41c20e473ff"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:87725cfb1a4f1f8c2fc9890ae2f42094120f4b44db9360be5d99a4c6b0e03a9e"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:fcce033e4021347d80ed9c66dcf1e7b1546319834b74445f561d2e2221de5659"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:ca0276464d148c72defa8bb4390cce01b4a0e425f3b50d1435aa6d7a18107602"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:197c1a244a274bb016dd8b79204850144ef77fe81c5b797dc389327adb552407"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp314-cp314t-win32.whl", hash = "sha256:2a24157fa36980478dd1770b585c0f30d19e18f4fb0c47c13aa568f871718579"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp314-cp314t-win_amd64.whl", hash = "sha256:cd5e2801c89992ed8c0a3f0293ae83c159a60d9a5d685005383ef4caca77f2c4"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp314-cp314t-win_arm64.whl", hash = "sha256:47955475ac79cc504ef2704b192364e51d0d473ad452caedd0002605f780101c"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:659a1e1b500fac8f2779dd9e1570464e012f43e580371470b45277a27baa7532"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f61aa92e4aad0be58eb6eb4e0c21acf32cf8065f4b2cae5665da756c4ceef982"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp38-cp38-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f50498891691e0864dc3da965f340fada0771f6142a378083dc4608f4ea513e2"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp38-cp38-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:bf625105bb9eef28a56a943fec8c8a98aeb80e7d7db99bd3c388137e6eb2d237"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2bd9d128ef93637a5d7a6af25363cf5dec3fa21cf80e68055aad627f280e8afa"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp38-cp38-manylinux_2_31_armv7l.whl", hash = "sha256:d08ec48f0a1c48d75d0356cea971921848fb620fdeba805b28f937e90691209f"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp38-cp38-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1ed80ff870ca6de33f4d953fda4d55654b9a2b340ff39ab32fa3adbcd718f264"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:f98059e4fcd3e3e4e2d632b7cf81c2faae96c43c60b569e9c621468082f1d104"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp38-cp38-musllinux_1_2_armv7l.whl", hash = "sha256:ab30e5e3e706e3063bc6de96b118688cb10396b70bb9864a430f67df98c61ecc"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:d5f5d1e9def3405f60e3ca8232d56f35c98fb7bf581efcc60051ebf53cb8b611"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp38-cp38-musllinux_1_2_riscv64.whl", hash = "sha256:461598cd852bfa5a61b09cae2b1c02e2efcd166ee5516e243d540ac24bfa68a7"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:71be7e0e01753a89cf024abf7ecb6bca2c81738ead80d43004d9b5e3f1244e64"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:df01808ee470038c3f8dc4f48620df7225c49c2d6639e38f96e6d6ac6e6f7b0e"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp38-cp38-win32.whl", hash = "sha256:69dd852c2f0ad631b8b60cfbe25a28c0058a894de5abb566619c205ce0550eae"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp38-cp38-win_amd64.whl", hash = "sha256:517ad0e93394ac532745129ceabdf2696b609ec9f87863d337140317ebce1c14"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:31215157227939b4fb3d740cd23fe27be0439afef67b785a1eb78a3ae69cba9e"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ecbbd45615a6885fe3240eb9db73b9e62518b611850fdf8ab08bd56de7ad2b17"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c45a03a4c69820a399f1dda9e1d8fbf3562eda46e7720458180302021b08f778"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e8aeb10fcbe92767f0fa69ad5a72deca50d0dca07fbde97848997d778a50c9fe"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:54fae94be3d75f3e573c9a1b5402dc593de19377013c9a0e4285e3d402dd3a2a"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp39-cp39-manylinux_2_31_armv7l.whl", hash = "sha256:2f7fdd9b6e6c529d6a2501a2d36b240109e78a8ceaef5687cfcfa2bbe671d297"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4d1d02209e06550bdaef34af58e041ad71b88e624f5d825519da3a3308e22687"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:8bc5f0687d796c05b1e28ab0d38a50e6309906ee09375dd3aff6a9c09dd6e8f4"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:ee4ec14bc1680d6b0afab9aea2ef27e26d2024f18b24a2d7155a52b60da7e833"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:d1a2ee9c1499fc8f86f4521f27a973c914b211ffa87322f4ee33bb35392da2c5"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:48696db7f18afb80a068821504296eb0787d9ce239b91ca15059d1d3eaacf13b"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:4f41da960b196ea355357285ad1316a00099f22d0929fe168343b99b254729c9"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:802168e03fba8bbc5ce0d866d589e4b1ca751d06edee69f7f3a19c5a9fe6b597"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp39-cp39-win32.whl", hash = "sha256:8761ac29b6c81574724322a554605608a9960769ea83d2c73e396f3df896ad54"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp39-cp39-win_amd64.whl", hash = "sha256:1cf0a70018692f85172348fe06d3a4b63f94ecb055e13a00c644d368eb82e5b8"},
|
||||||
|
{file = "charset_normalizer-3.4.6-cp39-cp39-win_arm64.whl", hash = "sha256:3516bbb8d42169de9e61b8520cbeeeb716f12f4ecfe3fd30a9919aa16c806ca8"},
|
||||||
|
{file = "charset_normalizer-3.4.6-py3-none-any.whl", hash = "sha256:947cf925bc916d90adba35a64c82aace04fa39b46b52d4630ece166655905a69"},
|
||||||
|
{file = "charset_normalizer-3.4.6.tar.gz", hash = "sha256:1ae6b62897110aa7c79ea2f5dd38d1abca6db663687c0b1ad9aed6f6bae3d9d6"},
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "colorama"
|
name = "colorama"
|
||||||
version = "0.4.6"
|
version = "0.4.6"
|
||||||
description = "Cross-platform colored terminal text."
|
description = "Cross-platform colored terminal text."
|
||||||
category = "dev"
|
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
|
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
|
||||||
|
groups = ["main"]
|
||||||
|
markers = "sys_platform == \"win32\""
|
||||||
|
files = [
|
||||||
|
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
|
||||||
|
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "distlib"
|
name = "h11"
|
||||||
version = "0.3.6"
|
version = "0.16.0"
|
||||||
description = "Distribution utilities"
|
description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1"
|
||||||
category = "dev"
|
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = "*"
|
python-versions = ">=3.8"
|
||||||
|
groups = ["main"]
|
||||||
[[package]]
|
files = [
|
||||||
name = "exceptiongroup"
|
{file = "h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86"},
|
||||||
version = "1.1.1"
|
{file = "h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1"},
|
||||||
description = "Backport of PEP 654 (exception groups)"
|
]
|
||||||
category = "dev"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.7"
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
test = ["pytest (>=6)"]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "filelock"
|
|
||||||
version = "3.12.2"
|
|
||||||
description = "A platform independent file lock."
|
|
||||||
category = "dev"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.7"
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
docs = ["furo (>=2023.5.20)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)", "sphinx (>=7.0.1)"]
|
|
||||||
testing = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "diff-cover (>=7.5)", "pytest-cov (>=4.1)", "pytest-mock (>=3.10)", "pytest-timeout (>=2.1)", "pytest (>=7.3.1)"]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "idna"
|
name = "idna"
|
||||||
version = "3.4"
|
version = "3.11"
|
||||||
description = "Internationalized Domain Names in Applications (IDNA)"
|
description = "Internationalized Domain Names in Applications (IDNA)"
|
||||||
category = "main"
|
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.5"
|
python-versions = ">=3.8"
|
||||||
|
groups = ["main"]
|
||||||
|
files = [
|
||||||
|
{file = "idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea"},
|
||||||
|
{file = "idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "importlib-metadata"
|
name = "loguru"
|
||||||
version = "6.7.0"
|
version = "0.7.3"
|
||||||
description = "Read metadata from Python packages"
|
description = "Python logging made (stupidly) simple"
|
||||||
category = "dev"
|
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = "<4.0,>=3.5"
|
||||||
|
groups = ["main"]
|
||||||
|
files = [
|
||||||
|
{file = "loguru-0.7.3-py3-none-any.whl", hash = "sha256:31a33c10c8e1e10422bfd431aeb5d351c7cf7fa671e3c4df004162264b28220c"},
|
||||||
|
{file = "loguru-0.7.3.tar.gz", hash = "sha256:19480589e77d47b8d85b2c827ad95d49bf31b0dcde16593892eb51dd18706eb6"},
|
||||||
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""}
|
colorama = {version = ">=0.3.4", markers = "sys_platform == \"win32\""}
|
||||||
zipp = ">=0.5"
|
win32-setctime = {version = ">=1.0.0", markers = "sys_platform == \"win32\""}
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
docs = ["sphinx (>=3.5)", "jaraco.packaging (>=9)", "rst.linker (>=1.9)", "furo", "sphinx-lint", "jaraco.tidelift (>=1.4)"]
|
dev = ["Sphinx (==8.1.3) ; python_version >= \"3.11\"", "build (==1.2.2) ; python_version >= \"3.11\"", "colorama (==0.4.5) ; python_version < \"3.8\"", "colorama (==0.4.6) ; python_version >= \"3.8\"", "exceptiongroup (==1.1.3) ; python_version >= \"3.7\" and python_version < \"3.11\"", "freezegun (==1.1.0) ; python_version < \"3.8\"", "freezegun (==1.5.0) ; python_version >= \"3.8\"", "mypy (==0.910) ; python_version < \"3.6\"", "mypy (==0.971) ; python_version == \"3.6\"", "mypy (==1.13.0) ; python_version >= \"3.8\"", "mypy (==1.4.1) ; python_version == \"3.7\"", "myst-parser (==4.0.0) ; python_version >= \"3.11\"", "pre-commit (==4.0.1) ; python_version >= \"3.9\"", "pytest (==6.1.2) ; python_version < \"3.8\"", "pytest (==8.3.2) ; python_version >= \"3.8\"", "pytest-cov (==2.12.1) ; python_version < \"3.8\"", "pytest-cov (==5.0.0) ; python_version == \"3.8\"", "pytest-cov (==6.0.0) ; python_version >= \"3.9\"", "pytest-mypy-plugins (==1.9.3) ; python_version >= \"3.6\" and python_version < \"3.8\"", "pytest-mypy-plugins (==3.1.0) ; python_version >= \"3.8\"", "sphinx-rtd-theme (==3.0.2) ; python_version >= \"3.11\"", "tox (==3.27.1) ; python_version < \"3.8\"", "tox (==4.23.2) ; python_version >= \"3.8\"", "twine (==6.0.1) ; python_version >= \"3.11\""]
|
||||||
perf = ["ipython"]
|
|
||||||
testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-ruff", "packaging", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)", "importlib-resources (>=1.3)"]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "iniconfig"
|
|
||||||
version = "2.0.0"
|
|
||||||
description = "brain-dead simple config-ini parsing"
|
|
||||||
category = "dev"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.7"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "isort"
|
|
||||||
version = "5.11.5"
|
|
||||||
description = "A Python utility / library to sort Python imports."
|
|
||||||
category = "dev"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.7.0"
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
pipfile-deprecated-finder = ["pipreqs", "requirementslib", "pip-shims (>=0.5.2)"]
|
|
||||||
requirements-deprecated-finder = ["pipreqs", "pip-api"]
|
|
||||||
colors = ["colorama (>=0.4.3,<0.5.0)"]
|
|
||||||
plugins = ["setuptools"]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "mypy-extensions"
|
|
||||||
version = "1.0.0"
|
|
||||||
description = "Type system extensions for programs checked with the mypy type checker."
|
|
||||||
category = "dev"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.5"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "observable"
|
name = "observable"
|
||||||
version = "1.0.3"
|
version = "1.0.3"
|
||||||
description = "minimalist event system"
|
description = "minimalist event system"
|
||||||
category = "main"
|
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = "*"
|
python-versions = "*"
|
||||||
|
groups = ["main"]
|
||||||
[[package]]
|
files = [
|
||||||
name = "packaging"
|
{file = "observable-1.0.3-py2.py3-none-any.whl", hash = "sha256:955a721a225fe3a1df28b58c0d7add38e08cd49afd88d14669b2884410f47d10"},
|
||||||
version = "23.1"
|
{file = "observable-1.0.3.tar.gz", hash = "sha256:97fe8e9d8c2a6185cee3661fa5fba9ce38c7ba388894132940cd6a81633626d9"},
|
||||||
description = "Core utilities for Python packages"
|
]
|
||||||
category = "dev"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.7"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pathspec"
|
|
||||||
version = "0.11.1"
|
|
||||||
description = "Utility library for gitignore style pattern matching of file paths."
|
|
||||||
category = "dev"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.7"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "platformdirs"
|
|
||||||
version = "3.8.0"
|
|
||||||
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
|
|
||||||
category = "dev"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.7"
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
typing-extensions = {version = ">=4.6.3", markers = "python_version < \"3.8\""}
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
docs = ["furo (>=2023.5.20)", "proselint (>=0.13)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)", "sphinx (>=7.0.1)"]
|
|
||||||
test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.10)", "pytest (>=7.3.1)"]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pluggy"
|
|
||||||
version = "1.2.0"
|
|
||||||
description = "plugin and hook calling mechanisms for python"
|
|
||||||
category = "dev"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.7"
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""}
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
dev = ["pre-commit", "tox"]
|
|
||||||
testing = ["pytest", "pytest-benchmark"]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pyproject-api"
|
|
||||||
version = "1.5.2"
|
|
||||||
description = "API to interact with the python pyproject.toml based projects"
|
|
||||||
category = "dev"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.7"
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
packaging = ">=23.1"
|
|
||||||
tomli = {version = ">=2.0.1", markers = "python_version < \"3.11\""}
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
docs = ["furo (>=2023.5.20)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)", "sphinx (>=7.0.1)"]
|
|
||||||
testing = ["covdefaults (>=2.3)", "importlib-metadata (>=6.6)", "pytest-cov (>=4.1)", "pytest-mock (>=3.10)", "pytest (>=7.3.1)", "setuptools (>=67.8)", "wheel (>=0.40)"]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pytest"
|
|
||||||
version = "7.4.0"
|
|
||||||
description = "pytest: simple powerful testing with Python"
|
|
||||||
category = "dev"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.7"
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
colorama = {version = "*", markers = "sys_platform == \"win32\""}
|
|
||||||
exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""}
|
|
||||||
importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""}
|
|
||||||
iniconfig = "*"
|
|
||||||
packaging = "*"
|
|
||||||
pluggy = ">=0.12,<2.0"
|
|
||||||
tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""}
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "python-engineio"
|
name = "python-engineio"
|
||||||
version = "3.14.2"
|
version = "4.13.1"
|
||||||
description = "Engine.IO server"
|
description = "Engine.IO server and client for Python"
|
||||||
category = "main"
|
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = "*"
|
python-versions = ">=3.8"
|
||||||
|
groups = ["main"]
|
||||||
|
files = [
|
||||||
|
{file = "python_engineio-4.13.1-py3-none-any.whl", hash = "sha256:f32ad10589859c11053ad7d9bb3c9695cdf862113bfb0d20bc4d890198287399"},
|
||||||
|
{file = "python_engineio-4.13.1.tar.gz", hash = "sha256:0a853fcef52f5b345425d8c2b921ac85023a04dfcf75d7b74696c61e940fd066"},
|
||||||
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
six = ">=1.9.0"
|
simple-websocket = ">=0.10.0"
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
asyncio_client = ["aiohttp (>=3.4)"]
|
asyncio-client = ["aiohttp (>=3.11)"]
|
||||||
client = ["requests (>=2.21.0)", "websocket-client (>=0.54.0)"]
|
client = ["requests (>=2.21.0)", "websocket-client (>=0.54.0)"]
|
||||||
|
dev = ["tox"]
|
||||||
|
docs = ["furo", "sphinx"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "python-socketio"
|
name = "python-socketio"
|
||||||
version = "4.6.0"
|
version = "5.16.1"
|
||||||
description = "Socket.IO server"
|
description = "Socket.IO server and client for Python"
|
||||||
category = "main"
|
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = "*"
|
python-versions = ">=3.8"
|
||||||
|
groups = ["main"]
|
||||||
|
files = [
|
||||||
|
{file = "python_socketio-5.16.1-py3-none-any.whl", hash = "sha256:a3eb1702e92aa2f2b5d3ba00261b61f062cce51f1cfb6900bf3ab4d1934d2d35"},
|
||||||
|
{file = "python_socketio-5.16.1.tar.gz", hash = "sha256:f863f98eacce81ceea2e742f6388e10ca3cdd0764be21d30d5196470edf5ea89"},
|
||||||
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
python-engineio = ">=3.13.0"
|
bidict = ">=0.21.0"
|
||||||
|
python-engineio = ">=4.11.0"
|
||||||
requests = {version = ">=2.21.0", optional = true, markers = "extra == \"client\""}
|
requests = {version = ">=2.21.0", optional = true, markers = "extra == \"client\""}
|
||||||
six = ">=1.9.0"
|
|
||||||
websocket-client = {version = ">=0.54.0", optional = true, markers = "extra == \"client\""}
|
websocket-client = {version = ">=0.54.0", optional = true, markers = "extra == \"client\""}
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
asyncio_client = ["aiohttp (>=3.4)", "websockets (>=7.0)"]
|
asyncio-client = ["aiohttp (>=3.4)"]
|
||||||
client = ["requests (>=2.21.0)", "websocket-client (>=0.54.0)"]
|
client = ["requests (>=2.21.0)", "websocket-client (>=0.54.0)"]
|
||||||
|
dev = ["tox"]
|
||||||
|
docs = ["furo", "sphinx"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "requests"
|
name = "requests"
|
||||||
version = "2.31.0"
|
version = "2.32.5"
|
||||||
description = "Python HTTP for Humans."
|
description = "Python HTTP for Humans."
|
||||||
category = "main"
|
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.9"
|
||||||
|
groups = ["main"]
|
||||||
|
files = [
|
||||||
|
{file = "requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6"},
|
||||||
|
{file = "requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf"},
|
||||||
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
certifi = ">=2017.4.17"
|
certifi = ">=2017.4.17"
|
||||||
charset-normalizer = ">=2,<4"
|
charset_normalizer = ">=2,<4"
|
||||||
idna = ">=2.5,<4"
|
idna = ">=2.5,<4"
|
||||||
urllib3 = ">=1.21.1,<3"
|
urllib3 = ">=1.21.1,<3"
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
socks = ["PySocks (>=1.5.6,!=1.5.7)"]
|
socks = ["PySocks (>=1.5.6,!=1.5.7)"]
|
||||||
use_chardet_on_py3 = ["chardet (>=3.0.2,<6)"]
|
use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "six"
|
name = "ruff"
|
||||||
version = "1.16.0"
|
version = "0.9.10"
|
||||||
description = "Python 2 and 3 compatibility utilities"
|
description = "An extremely fast Python linter and code formatter, written in Rust."
|
||||||
category = "main"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tomli"
|
|
||||||
version = "2.0.1"
|
|
||||||
description = "A lil' TOML parser"
|
|
||||||
category = "main"
|
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
|
groups = ["dev"]
|
||||||
|
files = [
|
||||||
|
{file = "ruff-0.9.10-py3-none-linux_armv6l.whl", hash = "sha256:eb4d25532cfd9fe461acc83498361ec2e2252795b4f40b17e80692814329e42d"},
|
||||||
|
{file = "ruff-0.9.10-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:188a6638dab1aa9bb6228a7302387b2c9954e455fb25d6b4470cb0641d16759d"},
|
||||||
|
{file = "ruff-0.9.10-py3-none-macosx_11_0_arm64.whl", hash = "sha256:5284dcac6b9dbc2fcb71fdfc26a217b2ca4ede6ccd57476f52a587451ebe450d"},
|
||||||
|
{file = "ruff-0.9.10-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:47678f39fa2a3da62724851107f438c8229a3470f533894b5568a39b40029c0c"},
|
||||||
|
{file = "ruff-0.9.10-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:99713a6e2766b7a17147b309e8c915b32b07a25c9efd12ada79f217c9c778b3e"},
|
||||||
|
{file = "ruff-0.9.10-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:524ee184d92f7c7304aa568e2db20f50c32d1d0caa235d8ddf10497566ea1a12"},
|
||||||
|
{file = "ruff-0.9.10-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:df92aeac30af821f9acf819fc01b4afc3dfb829d2782884f8739fb52a8119a16"},
|
||||||
|
{file = "ruff-0.9.10-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de42e4edc296f520bb84954eb992a07a0ec5a02fecb834498415908469854a52"},
|
||||||
|
{file = "ruff-0.9.10-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d257f95b65806104b6b1ffca0ea53f4ef98454036df65b1eda3693534813ecd1"},
|
||||||
|
{file = "ruff-0.9.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b60dec7201c0b10d6d11be00e8f2dbb6f40ef1828ee75ed739923799513db24c"},
|
||||||
|
{file = "ruff-0.9.10-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:d838b60007da7a39c046fcdd317293d10b845001f38bcb55ba766c3875b01e43"},
|
||||||
|
{file = "ruff-0.9.10-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:ccaf903108b899beb8e09a63ffae5869057ab649c1e9231c05ae354ebc62066c"},
|
||||||
|
{file = "ruff-0.9.10-py3-none-musllinux_1_2_i686.whl", hash = "sha256:f9567d135265d46e59d62dc60c0bfad10e9a6822e231f5b24032dba5a55be6b5"},
|
||||||
|
{file = "ruff-0.9.10-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:5f202f0d93738c28a89f8ed9eaba01b7be339e5d8d642c994347eaa81c6d75b8"},
|
||||||
|
{file = "ruff-0.9.10-py3-none-win32.whl", hash = "sha256:bfb834e87c916521ce46b1788fbb8484966e5113c02df216680102e9eb960029"},
|
||||||
|
{file = "ruff-0.9.10-py3-none-win_amd64.whl", hash = "sha256:f2160eeef3031bf4b17df74e307d4c5fb689a6f3a26a2de3f7ef4044e3c484f1"},
|
||||||
|
{file = "ruff-0.9.10-py3-none-win_arm64.whl", hash = "sha256:5fd804c0327a5e5ea26615550e706942f348b197d5475ff34c19733aee4b2e69"},
|
||||||
|
{file = "ruff-0.9.10.tar.gz", hash = "sha256:9bacb735d7bada9cfb0f2c227d3658fc443d90a727b47f206fb33f52f3c0eac7"},
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tox"
|
name = "simple-websocket"
|
||||||
version = "4.6.3"
|
version = "1.1.0"
|
||||||
description = "tox is a generic virtualenv management and test command line tool"
|
description = "Simple WebSocket server and client for Python"
|
||||||
category = "dev"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.7"
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
cachetools = ">=5.3.1"
|
|
||||||
chardet = ">=5.1"
|
|
||||||
colorama = ">=0.4.6"
|
|
||||||
filelock = ">=3.12.2"
|
|
||||||
importlib-metadata = {version = ">=6.6", markers = "python_version < \"3.8\""}
|
|
||||||
packaging = ">=23.1"
|
|
||||||
platformdirs = ">=3.5.3"
|
|
||||||
pluggy = ">=1"
|
|
||||||
pyproject-api = ">=1.5.2"
|
|
||||||
tomli = {version = ">=2.0.1", markers = "python_version < \"3.11\""}
|
|
||||||
typing-extensions = {version = ">=4.6.3", markers = "python_version < \"3.8\""}
|
|
||||||
virtualenv = ">=20.23.1"
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
docs = ["furo (>=2023.5.20)", "sphinx-argparse-cli (>=1.11.1)", "sphinx-autodoc-typehints (>=1.23.2,!=1.23.4)", "sphinx-copybutton (>=0.5.2)", "sphinx-inline-tabs (>=2023.4.21)", "sphinx (>=7.0.1)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"]
|
|
||||||
testing = ["build[virtualenv] (>=0.10)", "covdefaults (>=2.3)", "detect-test-pollution (>=1.1.1)", "devpi-process (>=0.3.1)", "diff-cover (>=7.6)", "distlib (>=0.3.6)", "flaky (>=3.7)", "hatch-vcs (>=0.3)", "hatchling (>=1.17.1)", "psutil (>=5.9.5)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)", "pytest-xdist (>=3.3.1)", "pytest (>=7.3.2)", "re-assert (>=1.1)", "time-machine (>=2.10)", "wheel (>=0.40)"]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "typed-ast"
|
|
||||||
version = "1.5.4"
|
|
||||||
description = "a fork of Python 2 and 3 ast modules with type comment support"
|
|
||||||
category = "dev"
|
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.6"
|
python-versions = ">=3.6"
|
||||||
|
groups = ["main"]
|
||||||
|
files = [
|
||||||
|
{file = "simple_websocket-1.1.0-py3-none-any.whl", hash = "sha256:4af6069630a38ed6c561010f0e11a5bc0d4ca569b36306eb257cd9a192497c8c"},
|
||||||
|
{file = "simple_websocket-1.1.0.tar.gz", hash = "sha256:7939234e7aa067c534abdab3a9ed933ec9ce4691b0713c78acb195560aa52ae4"},
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[package.dependencies]
|
||||||
name = "typing-extensions"
|
wsproto = "*"
|
||||||
version = "4.6.3"
|
|
||||||
description = "Backported and Experimental Type Hints for Python 3.7+"
|
[package.extras]
|
||||||
category = "dev"
|
dev = ["flake8", "pytest", "pytest-cov", "tox"]
|
||||||
optional = false
|
docs = ["sphinx"]
|
||||||
python-versions = ">=3.7"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "urllib3"
|
name = "urllib3"
|
||||||
version = "2.0.3"
|
version = "2.6.3"
|
||||||
description = "HTTP library with thread-safe connection pooling, file post, and more."
|
description = "HTTP library with thread-safe connection pooling, file post, and more."
|
||||||
category = "main"
|
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.9"
|
||||||
|
groups = ["main"]
|
||||||
|
files = [
|
||||||
|
{file = "urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4"},
|
||||||
|
{file = "urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed"},
|
||||||
|
]
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"]
|
brotli = ["brotli (>=1.2.0) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=1.2.0.0) ; platform_python_implementation != \"CPython\""]
|
||||||
secure = ["certifi", "cryptography (>=1.9)", "idna (>=2.0.0)", "pyopenssl (>=17.1.0)", "urllib3-secure-extra"]
|
h2 = ["h2 (>=4,<5)"]
|
||||||
socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"]
|
socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"]
|
||||||
zstd = ["zstandard (>=0.18.0)"]
|
zstd = ["backports-zstd (>=1.0.0) ; python_version < \"3.14\""]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "virtualenv"
|
|
||||||
version = "20.23.1"
|
|
||||||
description = "Virtual Python Environment builder"
|
|
||||||
category = "dev"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.7"
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
distlib = ">=0.3.6,<1"
|
|
||||||
filelock = ">=3.12,<4"
|
|
||||||
importlib-metadata = {version = ">=6.6", markers = "python_version < \"3.8\""}
|
|
||||||
platformdirs = ">=3.5.1,<4"
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
docs = ["furo (>=2023.5.20)", "proselint (>=0.13)", "sphinx-argparse (>=0.4)", "sphinx (>=7.0.1)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"]
|
|
||||||
test = ["covdefaults (>=2.3)", "coverage-enable-subprocess (>=1)", "coverage (>=7.2.7)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest-env (>=0.8.1)", "pytest-freezer (>=0.4.6)", "pytest-mock (>=3.10)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "pytest (>=7.3.1)", "setuptools (>=67.8)", "time-machine (>=2.9)"]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "websocket-client"
|
name = "websocket-client"
|
||||||
version = "1.6.1"
|
version = "1.9.0"
|
||||||
description = "WebSocket client for Python with low level API options"
|
description = "WebSocket client for Python with low level API options"
|
||||||
category = "main"
|
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.9"
|
||||||
|
groups = ["main"]
|
||||||
|
files = [
|
||||||
|
{file = "websocket_client-1.9.0-py3-none-any.whl", hash = "sha256:af248a825037ef591efbf6ed20cc5faa03d3b47b9e5a2230a529eeee1c1fc3ef"},
|
||||||
|
{file = "websocket_client-1.9.0.tar.gz", hash = "sha256:9e813624b6eb619999a97dc7958469217c3176312b3a16a4bd1bc7e08a46ec98"},
|
||||||
|
]
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
docs = ["Sphinx (>=3.4)", "sphinx-rtd-theme (>=0.5)"]
|
docs = ["Sphinx (>=6.0)", "myst-parser (>=2.0.0)", "sphinx_rtd_theme (>=1.1.0)"]
|
||||||
optional = ["python-socks", "wsaccel"]
|
optional = ["python-socks", "wsaccel"]
|
||||||
test = ["websockets"]
|
test = ["pytest", "websockets"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zipp"
|
name = "win32-setctime"
|
||||||
version = "3.15.0"
|
version = "1.2.0"
|
||||||
description = "Backport of pathlib-compatible object wrapper for zip files"
|
description = "A small Python utility to set file creation time on Windows"
|
||||||
category = "dev"
|
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.5"
|
||||||
|
groups = ["main"]
|
||||||
|
markers = "sys_platform == \"win32\""
|
||||||
|
files = [
|
||||||
|
{file = "win32_setctime-1.2.0-py3-none-any.whl", hash = "sha256:95d644c4e708aba81dc3704a116d8cbc974d70b3bdb8be1d150e36be6e9d1390"},
|
||||||
|
{file = "win32_setctime-1.2.0.tar.gz", hash = "sha256:ae1fdf948f5640aae05c511ade119313fb6a30d7eabe25fef9764dca5873c4c0"},
|
||||||
|
]
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
docs = ["sphinx (>=3.5)", "jaraco.packaging (>=9)", "rst.linker (>=1.9)", "furo", "sphinx-lint", "jaraco.tidelift (>=1.4)"]
|
dev = ["black (>=19.3b0) ; python_version >= \"3.6\"", "pytest (>=4.6.2)"]
|
||||||
testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "flake8 (<5)", "pytest-cov", "pytest-enabler (>=1.3)", "jaraco.itertools", "jaraco.functools", "more-itertools", "big-o", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)", "pytest-flake8"]
|
|
||||||
|
[[package]]
|
||||||
|
name = "wsproto"
|
||||||
|
version = "1.3.2"
|
||||||
|
description = "Pure-Python WebSocket protocol implementation"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.10"
|
||||||
|
groups = ["main"]
|
||||||
|
files = [
|
||||||
|
{file = "wsproto-1.3.2-py3-none-any.whl", hash = "sha256:61eea322cdf56e8cc904bd3ad7573359a242ba65688716b0710a5eb12beab584"},
|
||||||
|
{file = "wsproto-1.3.2.tar.gz", hash = "sha256:b86885dcf294e15204919950f666e06ffc6c7c114ca900b060d6e16293528294"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
h11 = ">=0.16.0,<1"
|
||||||
|
|
||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "1.1"
|
lock-version = "2.1"
|
||||||
python-versions = "^3.7"
|
python-versions = ">=3.10,<4.0.0"
|
||||||
content-hash = "9d75c174c1d055013bab4669a426bbbcd1d5fe31243e1569c8aff0524c143496"
|
content-hash = "62103257438754cd946c2a58245d2306c5c93ae9ee602400c83b08f241876ea8"
|
||||||
|
|
||||||
[metadata.files]
|
|
||||||
black = []
|
|
||||||
cachetools = []
|
|
||||||
certifi = []
|
|
||||||
chardet = []
|
|
||||||
charset-normalizer = []
|
|
||||||
click = []
|
|
||||||
colorama = []
|
|
||||||
distlib = []
|
|
||||||
exceptiongroup = []
|
|
||||||
filelock = []
|
|
||||||
idna = []
|
|
||||||
importlib-metadata = []
|
|
||||||
iniconfig = []
|
|
||||||
isort = []
|
|
||||||
mypy-extensions = []
|
|
||||||
observable = []
|
|
||||||
packaging = []
|
|
||||||
pathspec = []
|
|
||||||
platformdirs = []
|
|
||||||
pluggy = []
|
|
||||||
pyproject-api = []
|
|
||||||
pytest = []
|
|
||||||
python-engineio = []
|
|
||||||
python-socketio = []
|
|
||||||
requests = []
|
|
||||||
six = []
|
|
||||||
tomli = []
|
|
||||||
tox = []
|
|
||||||
typed-ast = []
|
|
||||||
typing-extensions = []
|
|
||||||
urllib3 = []
|
|
||||||
virtualenv = []
|
|
||||||
websocket-client = []
|
|
||||||
zipp = []
|
|
||||||
|
|||||||
131
pyproject.toml
131
pyproject.toml
@@ -1,41 +1,112 @@
|
|||||||
[tool.poetry]
|
[project]
|
||||||
name = "streamlabsio"
|
name = "streamlabsio"
|
||||||
version = "1.0.2"
|
version = "2.0.0"
|
||||||
description = "Get real time Twitch/Youtube events through Streamlabs SocketIO API"
|
description = "Get real time Twitch/Youtube events through Streamlabs SocketIO API"
|
||||||
authors = ["onyx-and-iris <code@onyxandiris.online>"]
|
authors = [{ name = "Onyx and Iris", email = "code@onyxandiris.online" }]
|
||||||
license = "MIT"
|
license = { text = "MIT" }
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
repository = "https://github.com/onyx-and-iris/streamlabs-socketio-py"
|
requires-python = ">=3.10,<4.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"observable (>=1.0.3,<2.0.0)",
|
||||||
|
"loguru (>=0.7.3,<0.8.0)",
|
||||||
|
"python-socketio[client] (>=5.16.1,<6.0.0)",
|
||||||
|
]
|
||||||
|
|
||||||
[tool.poetry.dependencies]
|
[tool.poetry.requires-plugins]
|
||||||
python = "^3.8"
|
poethepoet = "^0.42.0"
|
||||||
tomli = { version = "^2.0.1", python = "<3.11" }
|
|
||||||
python-engineio = "3.14.2"
|
|
||||||
python-socketio = { version = "4.6.0", extras = ["client"] }
|
|
||||||
observable = "^1.0.3"
|
|
||||||
|
|
||||||
[tool.poetry.dev-dependencies]
|
|
||||||
black = "^22.10.0"
|
|
||||||
isort = "^5.10.1"
|
|
||||||
tox = "^4.6.3"
|
|
||||||
pytest = "^7.4.0"
|
|
||||||
|
|
||||||
|
[tool.poetry.group.dev.dependencies]
|
||||||
|
ruff = "^0.9.2"
|
||||||
|
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = ["poetry-core>=1.0.0"]
|
requires = ["poetry-core>=2.0.0,<3.0.0"]
|
||||||
build-backend = "poetry.core.masonry.api"
|
build-backend = "poetry.core.masonry.api"
|
||||||
|
|
||||||
[tool.poetry.scripts]
|
[tool.poe]
|
||||||
debug = "scripts:ex_debug"
|
envfile = ".env"
|
||||||
|
|
||||||
[tool.tox]
|
[tool.poe.tasks]
|
||||||
legacy_tox_ini = """
|
events.script = "scripts:ex_events"
|
||||||
[tox]
|
block-forever.script = "scripts:ex_block_forever"
|
||||||
envlist = py38,py39,py310,py311
|
|
||||||
|
|
||||||
[testenv]
|
[tool.ruff]
|
||||||
allowlist_externals = poetry
|
exclude = [
|
||||||
commands =
|
".bzr",
|
||||||
poetry install -v
|
".direnv",
|
||||||
poetry run pytest tests/
|
".eggs",
|
||||||
"""
|
".git",
|
||||||
|
".git-rewrite",
|
||||||
|
".hg",
|
||||||
|
".mypy_cache",
|
||||||
|
".nox",
|
||||||
|
".pants.d",
|
||||||
|
".pytype",
|
||||||
|
".ruff_cache",
|
||||||
|
".svn",
|
||||||
|
".tox",
|
||||||
|
".venv",
|
||||||
|
"__pypackages__",
|
||||||
|
"_build",
|
||||||
|
"buck-out",
|
||||||
|
"build",
|
||||||
|
"dist",
|
||||||
|
"node_modules",
|
||||||
|
"venv",
|
||||||
|
]
|
||||||
|
|
||||||
|
# Same as Black.
|
||||||
|
line-length = 88
|
||||||
|
indent-width = 4
|
||||||
|
|
||||||
|
# Assume Python 3.10
|
||||||
|
target-version = "py310"
|
||||||
|
|
||||||
|
[tool.ruff.lint]
|
||||||
|
# Enable Pyflakes (`F`) and a subset of the pycodestyle (`E`) codes by default.
|
||||||
|
# Enable flake8-errmsg (EM) warnings.
|
||||||
|
# Enable flake8-bugbear (B) warnings.
|
||||||
|
# Unlike Flake8, Ruff doesn't enable pycodestyle warnings (`W`) or
|
||||||
|
# McCabe complexity (`C901`) by default.
|
||||||
|
select = ["E4", "E7", "E9", "EM", "F", "B"]
|
||||||
|
ignore = []
|
||||||
|
|
||||||
|
# Allow fix for all enabled rules (when `--fix`) is provided.
|
||||||
|
fixable = ["ALL"]
|
||||||
|
unfixable = ["B"]
|
||||||
|
|
||||||
|
# Allow unused variables when underscore-prefixed.
|
||||||
|
dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
|
||||||
|
|
||||||
|
|
||||||
|
[tool.ruff.format]
|
||||||
|
# Unlike Black, use single quotes for strings.
|
||||||
|
quote-style = "single"
|
||||||
|
|
||||||
|
# Like Black, indent with spaces, rather than tabs.
|
||||||
|
indent-style = "space"
|
||||||
|
|
||||||
|
# Like Black, respect magic trailing commas.
|
||||||
|
skip-magic-trailing-comma = false
|
||||||
|
|
||||||
|
# Like Black, automatically detect the appropriate line ending.
|
||||||
|
line-ending = "auto"
|
||||||
|
|
||||||
|
# Enable auto-formatting of code examples in docstrings. Markdown,
|
||||||
|
# reStructuredText code/literal blocks and doctests are all supported.
|
||||||
|
#
|
||||||
|
# This is currently disabled by default, but it is planned for this
|
||||||
|
# to be opt-out in the future.
|
||||||
|
docstring-code-format = false
|
||||||
|
|
||||||
|
# Set the line length limit used when formatting code snippets in
|
||||||
|
# docstrings.
|
||||||
|
#
|
||||||
|
# This only has an effect when the `docstring-code-format` setting is
|
||||||
|
# enabled.
|
||||||
|
docstring-code-line-length = "dynamic"
|
||||||
|
|
||||||
|
[tool.ruff.lint.mccabe]
|
||||||
|
max-complexity = 10
|
||||||
|
|
||||||
|
[tool.ruff.lint.per-file-ignores]
|
||||||
|
"__init__.py" = ["E402", "F401"]
|
||||||
|
|||||||
15
scripts.py
15
scripts.py
@@ -1,7 +1,16 @@
|
|||||||
import subprocess
|
import subprocess
|
||||||
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
def ex_debug():
|
def ex_events():
|
||||||
path = Path.cwd() / "examples" / "debug" / "."
|
scriptpath = Path.cwd() / 'examples' / 'events' / '.'
|
||||||
subprocess.run(["py", str(path)])
|
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)
|
||||||
|
|||||||
@@ -1 +1,7 @@
|
|||||||
from .client import connect
|
from loguru import logger
|
||||||
|
|
||||||
|
from .client import request_client_object as connect
|
||||||
|
|
||||||
|
__ALL__ = ['connect']
|
||||||
|
|
||||||
|
logger.disable('streamlabsio')
|
||||||
|
|||||||
@@ -1,93 +1,106 @@
|
|||||||
import logging
|
|
||||||
from pathlib import Path
|
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
import socketio
|
import socketio
|
||||||
|
from loguru import logger
|
||||||
from observable import Observable
|
from observable import Observable
|
||||||
|
|
||||||
from .error import SteamlabsSIOConnectionError
|
from .error import SteamlabsSIOConnectionError
|
||||||
from .models import as_dataclass
|
from .models import as_dataclass
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
class Client:
|
class Client:
|
||||||
def __init__(self, token=None, raw=False):
|
EVENT_TYPES: set[str] = (
|
||||||
self.logger = logger.getChild(self.__class__.__name__)
|
{'donation'} # streamlabs
|
||||||
self.token = token or self._token_from_toml()
|
| {'follow', 'subscription', 'host', 'bits', 'raid'} # twitch
|
||||||
self._raw = raw
|
| {'follow', 'subscription', 'superchat'} # youtube
|
||||||
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()
|
|
||||||
self.streamlabs = ("donation",)
|
|
||||||
self.twitch = ("follow", "subscription", "host", "bits", "raids")
|
|
||||||
self.youtube = ("follow", "subscription", "superchat")
|
|
||||||
|
|
||||||
def __enter__(self):
|
def __init__(self, *, token: str, raw: bool = False):
|
||||||
|
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.obs = Observable()
|
||||||
|
|
||||||
|
def __enter__(self) -> 'Client':
|
||||||
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('Connection to Streamlabs Socket API failed')
|
||||||
raise SteamlabsSIOConnectionError(
|
ERR_MSG = 'Failed to connect to Streamlabs Socket API. Please check your token and network connection.'
|
||||||
"no connection could be established to the Streamlabs SIO server"
|
raise SteamlabsSIOConnectionError(ERR_MSG) from e
|
||||||
) from e
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def _token_from_toml(self) -> str:
|
def __exit__(self, exc_type, exc_val, exc_tb) -> None:
|
||||||
try:
|
self._sio.disconnect()
|
||||||
import tomllib
|
|
||||||
except ModuleNotFoundError:
|
|
||||||
import tomli as tomllib
|
|
||||||
|
|
||||||
def get_filepath() -> Optional[Path]:
|
def wait(self, seconds: float | None = None) -> None:
|
||||||
filepaths = (
|
"""Exposes the wait and sleep methods of the socketio client to allow the user to keep the connection alive.
|
||||||
Path.cwd() / "config.toml",
|
|
||||||
Path.home() / ".config" / "streamlabsio" / "config.toml",
|
|
||||||
)
|
|
||||||
for filepath in filepaths:
|
|
||||||
if filepath.exists():
|
|
||||||
return filepath
|
|
||||||
|
|
||||||
try:
|
|
||||||
filepath = get_filepath()
|
|
||||||
if not filepath:
|
|
||||||
raise FileNotFoundError("config.toml was not found")
|
|
||||||
with open(filepath, "rb") as f:
|
|
||||||
conn = tomllib.load(f)
|
|
||||||
assert "token" in conn.get(
|
|
||||||
"streamlabs"
|
|
||||||
), "token not found in config.toml"
|
|
||||||
return conn["streamlabs"].get("token")
|
|
||||||
except (FileNotFoundError, tomllib.TOMLDecodeError) as e:
|
|
||||||
self.logger.error(f"{type(e).__name__}: {e}")
|
|
||||||
raise
|
|
||||||
|
|
||||||
def connect_handler(self):
|
Args:
|
||||||
self.logger.info("Connected to Streamlabs Socket API")
|
seconds (float | None): If None, the method will block indefinitely.
|
||||||
|
|
||||||
def event_handler(self, data):
|
Returns:
|
||||||
if "for" in data and data["type"] in set(
|
None
|
||||||
self.streamlabs + self.twitch + self.youtube
|
"""
|
||||||
):
|
if seconds is None:
|
||||||
message = data["message"][0] if isinstance(data["message"][0], dict) else {}
|
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 the callback functions.
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
"""
|
||||||
|
|
||||||
|
match data:
|
||||||
|
case {
|
||||||
|
'for': str() as target,
|
||||||
|
'type': str() as event_type,
|
||||||
|
'message': list() as message_list,
|
||||||
|
} if event_type in Client.EVENT_TYPES:
|
||||||
|
# The message type is expected to be a list, however, in practice, it often contains only one item.
|
||||||
|
# To ensure compatibility with the actual data structure,
|
||||||
|
# we will iterate over the message list and trigger events for each message item.
|
||||||
|
for message in message_list:
|
||||||
self.obs.trigger(
|
self.obs.trigger(
|
||||||
data["for"],
|
target,
|
||||||
data["type"],
|
event_type,
|
||||||
message
|
message if self._raw else as_dataclass(event_type, message),
|
||||||
if self._raw
|
|
||||||
else as_dataclass(data["type"], message),
|
|
||||||
)
|
)
|
||||||
self.logger.debug(data)
|
self._logger.debug(
|
||||||
|
f'Triggered event: {target} {event_type} {message}'
|
||||||
|
)
|
||||||
|
case _:
|
||||||
|
self._logger.debug(f'Unexpected event data: {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 request_client_object(*, token: str, raw: bool = False) -> Client:
|
||||||
SIO_cls = Client
|
"""Entry point for users to request a Client object.
|
||||||
return SIO_cls(**kwargs)
|
|
||||||
|
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)
|
||||||
|
|||||||
@@ -1,2 +1,6 @@
|
|||||||
class SteamlabsSIOConnectionError(Exception):
|
class SteamlabsSIOError(Exception):
|
||||||
|
"""Base StreamlabsSIO error class"""
|
||||||
|
|
||||||
|
|
||||||
|
class SteamlabsSIOConnectionError(SteamlabsSIOError):
|
||||||
"""Exception raised when connection errors occur"""
|
"""Exception raised when connection errors occur"""
|
||||||
|
|||||||
@@ -1,22 +1,30 @@
|
|||||||
|
import keyword
|
||||||
import re
|
import re
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
|
||||||
|
|
||||||
def to_snake_case(s):
|
def to_snake_case(s: str) -> str:
|
||||||
return re.sub(r"(?<!^)(?=[A-Z])", "_", s).lower()
|
return re.sub(r'(?<!^)(?=[A-Z])', '_', s).lower()
|
||||||
|
|
||||||
|
|
||||||
def as_dataclass(identifier, data):
|
def safe_field_name(name: str) -> str:
|
||||||
def attrs():
|
return name + '_' if keyword.iskeyword(name) else name
|
||||||
return list(to_snake_case(k) for k in data.keys())
|
|
||||||
|
|
||||||
return dataclass(
|
|
||||||
|
def as_dataclass(name: str, data: dict):
|
||||||
|
def attrs(self) -> list:
|
||||||
|
return list(self.__annotations__.keys())
|
||||||
|
|
||||||
|
dc_CLS = dataclass(
|
||||||
type(
|
type(
|
||||||
f"{identifier.capitalize()}Dataclass",
|
f'{name}Dataclass',
|
||||||
(),
|
(),
|
||||||
{
|
{
|
||||||
"attrs": attrs,
|
'__annotations__': {
|
||||||
**{to_snake_case(k): v for k, v in data.items()},
|
safe_field_name(to_snake_case(k)): type(v) for k, v in data.items()
|
||||||
|
},
|
||||||
|
'attrs': attrs,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
return dc_CLS(**{safe_field_name(to_snake_case(k)): v for k, v in data.items()})
|
||||||
|
|||||||
Reference in New Issue
Block a user