mirror of
https://github.com/onyx-and-iris/slobs-cli.git
synced 2025-08-07 04:11:45 +00:00
Compare commits
3 Commits
e7a561c7b4
...
51923dc8a8
Author | SHA1 | Date | |
---|---|---|---|
51923dc8a8 | |||
37364e7243 | |||
377a9df824 |
@ -19,7 +19,7 @@ For an outline of past/future changes refer to: [CHANGELOG](CHANGELOG.md)
|
|||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
- Python 3.10 or greater
|
- Python 3.11 or greater
|
||||||
- [Streamlabs Desktop][sl-desktop]
|
- [Streamlabs Desktop][sl-desktop]
|
||||||
- A websocket token: Settings > Remote Control > API Token
|
- A websocket token: Settings > Remote Control > API Token
|
||||||
|
|
||||||
|
17
pdm.lock
generated
17
pdm.lock
generated
@ -5,7 +5,7 @@
|
|||||||
groups = ["default", "dev"]
|
groups = ["default", "dev"]
|
||||||
strategy = ["inherit_metadata"]
|
strategy = ["inherit_metadata"]
|
||||||
lock_version = "4.5.0"
|
lock_version = "4.5.0"
|
||||||
content_hash = "sha256:b032bb4d22d3d3b10233c543cd182ac8e7ec052aa9dc03a3034a967066e85db2"
|
content_hash = "sha256:6f29a16938942eb7911abc4c1505647bb80b5275cb45ac72f9166b53ae6c0ef1"
|
||||||
|
|
||||||
[[metadata.targets]]
|
[[metadata.targets]]
|
||||||
requires_python = ">=3.10"
|
requires_python = ">=3.10"
|
||||||
@ -238,6 +238,21 @@ files = [
|
|||||||
{file = "pytest-8.4.0.tar.gz", hash = "sha256:14d920b48472ea0dbf68e45b96cd1ffda4705f33307dcc86c676c1b5104838a6"},
|
{file = "pytest-8.4.0.tar.gz", hash = "sha256:14d920b48472ea0dbf68e45b96cd1ffda4705f33307dcc86c676c1b5104838a6"},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pytest-randomly"
|
||||||
|
version = "3.16.0"
|
||||||
|
requires_python = ">=3.9"
|
||||||
|
summary = "Pytest plugin to randomly order tests and control random.seed."
|
||||||
|
groups = ["dev"]
|
||||||
|
dependencies = [
|
||||||
|
"importlib-metadata>=3.6; python_version < \"3.10\"",
|
||||||
|
"pytest",
|
||||||
|
]
|
||||||
|
files = [
|
||||||
|
{file = "pytest_randomly-3.16.0-py3-none-any.whl", hash = "sha256:8633d332635a1a0983d3bba19342196807f6afb17c3eef78e02c2f85dade45d6"},
|
||||||
|
{file = "pytest_randomly-3.16.0.tar.gz", hash = "sha256:11bf4d23a26484de7860d82f726c0629837cf4064b79157bd18ec9d41d7feb26"},
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sniffio"
|
name = "sniffio"
|
||||||
version = "1.3.1"
|
version = "1.3.1"
|
||||||
|
@ -3,7 +3,7 @@ name = "slobs-cli"
|
|||||||
description = "A command line application for Streamlabs Desktop"
|
description = "A command line application for Streamlabs Desktop"
|
||||||
authors = [{ name = "onyx-and-iris", email = "code@onyxandiris.online" }]
|
authors = [{ name = "onyx-and-iris", email = "code@onyxandiris.online" }]
|
||||||
dependencies = ["pyslobs>=2.0.4", "asyncclick>=8.1.8"]
|
dependencies = ["pyslobs>=2.0.4", "asyncclick>=8.1.8"]
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.11"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
license = { text = "MIT" }
|
license = { text = "MIT" }
|
||||||
dynamic = ["version"]
|
dynamic = ["version"]
|
||||||
@ -27,9 +27,15 @@ path = "src/slobs_cli/__about__.py"
|
|||||||
cli.cmd = "slobs-cli {args}"
|
cli.cmd = "slobs-cli {args}"
|
||||||
cli.env_file = ".env"
|
cli.env_file = ".env"
|
||||||
|
|
||||||
|
pre_test.cmd = "python tests/setup.py"
|
||||||
test.cmd = "pytest {args}"
|
test.cmd = "pytest {args}"
|
||||||
test.env_file = ".env"
|
test.env_file = ".env"
|
||||||
post_test.cmd = "python tests/teardown.py"
|
post_test.cmd = "python tests/teardown.py"
|
||||||
|
|
||||||
[dependency-groups]
|
[dependency-groups]
|
||||||
dev = ["tox-pdm>=0.7.2", "pytest>=8.4.0", "virtualenv-pyenv>=0.5.0"]
|
dev = [
|
||||||
|
"tox-pdm>=0.7.2",
|
||||||
|
"pytest>=8.4.0",
|
||||||
|
"virtualenv-pyenv>=0.5.0",
|
||||||
|
"pytest-randomly>=3.16.0",
|
||||||
|
]
|
||||||
|
@ -1 +1 @@
|
|||||||
__version__ = "0.7.6"
|
__version__ = "0.7.8"
|
||||||
|
@ -19,8 +19,8 @@ async def start(ctx: click.Context):
|
|||||||
ss = StreamingService(conn)
|
ss = StreamingService(conn)
|
||||||
|
|
||||||
async def _run():
|
async def _run():
|
||||||
current_state = await ss.get_model()
|
model = await ss.get_model()
|
||||||
active = current_state.recording_status != "offline"
|
active = model.recording_status != "offline"
|
||||||
|
|
||||||
if active:
|
if active:
|
||||||
conn.close()
|
conn.close()
|
||||||
@ -45,8 +45,8 @@ async def stop(ctx: click.Context):
|
|||||||
ss = StreamingService(conn)
|
ss = StreamingService(conn)
|
||||||
|
|
||||||
async def _run():
|
async def _run():
|
||||||
current_state = await ss.get_model()
|
model = await ss.get_model()
|
||||||
active = current_state.recording_status != "offline"
|
active = model.recording_status != "offline"
|
||||||
|
|
||||||
if not active:
|
if not active:
|
||||||
conn.close()
|
conn.close()
|
||||||
@ -71,8 +71,8 @@ async def status(ctx: click.Context):
|
|||||||
ss = StreamingService(conn)
|
ss = StreamingService(conn)
|
||||||
|
|
||||||
async def _run():
|
async def _run():
|
||||||
current_state = await ss.get_model()
|
model = await ss.get_model()
|
||||||
active = current_state.recording_status != "offline"
|
active = model.recording_status != "offline"
|
||||||
|
|
||||||
if active:
|
if active:
|
||||||
click.echo("Recording is currently active.")
|
click.echo("Recording is currently active.")
|
||||||
@ -95,8 +95,8 @@ async def toggle(ctx: click.Context):
|
|||||||
ss = StreamingService(conn)
|
ss = StreamingService(conn)
|
||||||
|
|
||||||
async def _run():
|
async def _run():
|
||||||
current_state = await ss.get_model()
|
model = await ss.get_model()
|
||||||
active = current_state.recording_status != "offline"
|
active = model.recording_status != "offline"
|
||||||
|
|
||||||
if active:
|
if active:
|
||||||
await ss.toggle_recording()
|
await ss.toggle_recording()
|
||||||
|
@ -19,8 +19,8 @@ async def start(ctx: click.Context):
|
|||||||
ss = StreamingService(conn)
|
ss = StreamingService(conn)
|
||||||
|
|
||||||
async def _run():
|
async def _run():
|
||||||
current_state = await ss.get_model()
|
model = await ss.get_model()
|
||||||
active = current_state.replay_buffer_status != "offline"
|
active = model.replay_buffer_status != "offline"
|
||||||
|
|
||||||
if active:
|
if active:
|
||||||
conn.close()
|
conn.close()
|
||||||
@ -44,8 +44,8 @@ async def stop(ctx: click.Context):
|
|||||||
ss = StreamingService(conn)
|
ss = StreamingService(conn)
|
||||||
|
|
||||||
async def _run():
|
async def _run():
|
||||||
current_state = await ss.get_model()
|
model = await ss.get_model()
|
||||||
active = current_state.replay_buffer_status != "offline"
|
active = model.replay_buffer_status != "offline"
|
||||||
|
|
||||||
if not active:
|
if not active:
|
||||||
conn.close()
|
conn.close()
|
||||||
@ -71,8 +71,8 @@ async def status(ctx: click.Context):
|
|||||||
ss = StreamingService(conn)
|
ss = StreamingService(conn)
|
||||||
|
|
||||||
async def _run():
|
async def _run():
|
||||||
current_state = await ss.get_model()
|
model = await ss.get_model()
|
||||||
active = current_state.replay_buffer_status != "offline"
|
active = model.replay_buffer_status != "offline"
|
||||||
if active:
|
if active:
|
||||||
click.echo("Replay buffer is currently active.")
|
click.echo("Replay buffer is currently active.")
|
||||||
else:
|
else:
|
||||||
|
@ -77,9 +77,9 @@ async def switch(ctx: click.Context, scene_name: str, preview: bool = False):
|
|||||||
scenes = await ss.get_scenes()
|
scenes = await ss.get_scenes()
|
||||||
for scene in scenes:
|
for scene in scenes:
|
||||||
if scene.name == scene_name:
|
if scene.name == scene_name:
|
||||||
current_state = await ts.get_model()
|
model = await ts.get_model()
|
||||||
|
|
||||||
if current_state.studio_mode:
|
if model.studio_mode:
|
||||||
await ss.make_scene_active(scene.id)
|
await ss.make_scene_active(scene.id)
|
||||||
if preview:
|
if preview:
|
||||||
click.echo(
|
click.echo(
|
||||||
@ -104,13 +104,13 @@ async def switch(ctx: click.Context, scene_name: str, preview: bool = False):
|
|||||||
click.echo(
|
click.echo(
|
||||||
f"Switched to scene: {click.style(scene.name, fg='blue')} (ID: {scene.id}) in active mode."
|
f"Switched to scene: {click.style(scene.name, fg='blue')} (ID: {scene.id}) in active mode."
|
||||||
)
|
)
|
||||||
|
conn.close()
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
conn.close()
|
conn.close()
|
||||||
raise click.ClickException(
|
raise click.ClickException(
|
||||||
click.style(f"Scene '{scene_name}' not found.", fg="red")
|
click.style(f"Scene '{scene_name}' not found.", fg="red")
|
||||||
)
|
)
|
||||||
conn.close()
|
|
||||||
|
|
||||||
async with create_task_group() as tg:
|
async with create_task_group() as tg:
|
||||||
tg.start_soon(conn.background_processing)
|
tg.start_soon(conn.background_processing)
|
||||||
|
@ -19,8 +19,8 @@ async def start(ctx: click.Context):
|
|||||||
ss = StreamingService(conn)
|
ss = StreamingService(conn)
|
||||||
|
|
||||||
async def _run():
|
async def _run():
|
||||||
current_state = await ss.get_model()
|
model = await ss.get_model()
|
||||||
active = current_state.streaming_status != "offline"
|
active = model.streaming_status != "offline"
|
||||||
|
|
||||||
if active:
|
if active:
|
||||||
conn.close()
|
conn.close()
|
||||||
@ -44,8 +44,8 @@ async def stop(ctx: click.Context):
|
|||||||
ss = StreamingService(conn)
|
ss = StreamingService(conn)
|
||||||
|
|
||||||
async def _run():
|
async def _run():
|
||||||
current_state = await ss.get_model()
|
model = await ss.get_model()
|
||||||
active = current_state.streaming_status != "offline"
|
active = model.streaming_status != "offline"
|
||||||
|
|
||||||
if not active:
|
if not active:
|
||||||
conn.close()
|
conn.close()
|
||||||
@ -69,8 +69,8 @@ async def status(ctx: click.Context):
|
|||||||
ss = StreamingService(conn)
|
ss = StreamingService(conn)
|
||||||
|
|
||||||
async def _run():
|
async def _run():
|
||||||
current_state = await ss.get_model()
|
model = await ss.get_model()
|
||||||
active = current_state.streaming_status != "offline"
|
active = model.streaming_status != "offline"
|
||||||
|
|
||||||
if active:
|
if active:
|
||||||
click.echo("Stream is currently active.")
|
click.echo("Stream is currently active.")
|
||||||
@ -92,8 +92,8 @@ async def toggle(ctx: click.Context):
|
|||||||
ss = StreamingService(conn)
|
ss = StreamingService(conn)
|
||||||
|
|
||||||
async def _run():
|
async def _run():
|
||||||
current_state = await ss.get_model()
|
model = await ss.get_model()
|
||||||
active = current_state.streaming_status != "offline"
|
active = model.streaming_status != "offline"
|
||||||
|
|
||||||
await ss.toggle_streaming()
|
await ss.toggle_streaming()
|
||||||
if active:
|
if active:
|
||||||
|
@ -19,8 +19,8 @@ async def enable(ctx: click.Context):
|
|||||||
ts = TransitionsService(conn)
|
ts = TransitionsService(conn)
|
||||||
|
|
||||||
async def _run():
|
async def _run():
|
||||||
current_state = await ts.get_model()
|
model = await ts.get_model()
|
||||||
if current_state.studio_mode:
|
if model.studio_mode:
|
||||||
conn.close()
|
conn.close()
|
||||||
raise click.Abort(click.style("Studio mode is already enabled.", fg="red"))
|
raise click.Abort(click.style("Studio mode is already enabled.", fg="red"))
|
||||||
|
|
||||||
@ -42,8 +42,8 @@ async def disable(ctx: click.Context):
|
|||||||
ts = TransitionsService(conn)
|
ts = TransitionsService(conn)
|
||||||
|
|
||||||
async def _run():
|
async def _run():
|
||||||
current_state = await ts.get_model()
|
model = await ts.get_model()
|
||||||
if not current_state.studio_mode:
|
if not model.studio_mode:
|
||||||
conn.close()
|
conn.close()
|
||||||
raise click.Abort(click.style("Studio mode is already disabled.", fg="red"))
|
raise click.Abort(click.style("Studio mode is already disabled.", fg="red"))
|
||||||
|
|
||||||
@ -65,8 +65,8 @@ async def status(ctx: click.Context):
|
|||||||
ts = TransitionsService(conn)
|
ts = TransitionsService(conn)
|
||||||
|
|
||||||
async def _run():
|
async def _run():
|
||||||
current_state = await ts.get_model()
|
model = await ts.get_model()
|
||||||
if current_state.studio_mode:
|
if model.studio_mode:
|
||||||
click.echo("Studio mode is currently enabled.")
|
click.echo("Studio mode is currently enabled.")
|
||||||
else:
|
else:
|
||||||
click.echo("Studio mode is currently disabled.")
|
click.echo("Studio mode is currently disabled.")
|
||||||
@ -86,8 +86,8 @@ async def toggle(ctx: click.Context):
|
|||||||
ts = TransitionsService(conn)
|
ts = TransitionsService(conn)
|
||||||
|
|
||||||
async def _run():
|
async def _run():
|
||||||
current_state = await ts.get_model()
|
model = await ts.get_model()
|
||||||
if current_state.studio_mode:
|
if model.studio_mode:
|
||||||
await ts.disable_studio_mode()
|
await ts.disable_studio_mode()
|
||||||
click.echo("Studio mode disabled successfully.")
|
click.echo("Studio mode disabled successfully.")
|
||||||
else:
|
else:
|
||||||
@ -109,8 +109,8 @@ async def force_transition(ctx: click.Context):
|
|||||||
ts = TransitionsService(conn)
|
ts = TransitionsService(conn)
|
||||||
|
|
||||||
async def _run():
|
async def _run():
|
||||||
current_state = await ts.get_model()
|
model = await ts.get_model()
|
||||||
if not current_state.studio_mode:
|
if not model.studio_mode:
|
||||||
conn.close()
|
conn.close()
|
||||||
raise click.Abort(click.style("Studio mode is not enabled.", fg="red"))
|
raise click.Abort(click.style("Studio mode is not enabled.", fg="red"))
|
||||||
|
|
||||||
|
32
tests/setup.py
Normal file
32
tests/setup.py
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
import anyio
|
||||||
|
from anyio import create_task_group
|
||||||
|
from pyslobs import ConnectionConfig, ScenesService, SlobsConnection
|
||||||
|
|
||||||
|
|
||||||
|
async def setup(conn: SlobsConnection):
|
||||||
|
ss = ScenesService(conn)
|
||||||
|
await ss.create_scene("slobs-test-scene-1")
|
||||||
|
await ss.create_scene("slobs-test-scene-2")
|
||||||
|
await ss.create_scene("slobs-test-scene-3")
|
||||||
|
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
conn = SlobsConnection(
|
||||||
|
ConnectionConfig(
|
||||||
|
domain=os.environ["SLOBS_DOMAIN"],
|
||||||
|
port=59650,
|
||||||
|
token=os.environ["SLOBS_TOKEN"],
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
async with create_task_group() as tg:
|
||||||
|
tg.start_soon(conn.background_processing)
|
||||||
|
tg.start_soon(setup, conn)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
anyio.run(main)
|
@ -2,17 +2,23 @@ import os
|
|||||||
|
|
||||||
import anyio
|
import anyio
|
||||||
from anyio import create_task_group
|
from anyio import create_task_group
|
||||||
from pyslobs import ConnectionConfig, SlobsConnection, StreamingService
|
from pyslobs import ConnectionConfig, ScenesService, SlobsConnection, StreamingService
|
||||||
|
|
||||||
|
|
||||||
async def cleanup(conn: SlobsConnection):
|
async def cleanup(conn: SlobsConnection):
|
||||||
|
ss = ScenesService(conn)
|
||||||
|
scenes = await ss.get_scenes()
|
||||||
|
for scene in scenes:
|
||||||
|
if scene.name.startswith("slobs-test-scene-"):
|
||||||
|
await ss.remove_scene(scene.id)
|
||||||
|
|
||||||
ss = StreamingService(conn)
|
ss = StreamingService(conn)
|
||||||
current_state = await ss.get_model()
|
model = await ss.get_model()
|
||||||
if current_state.streaming_status != "offline":
|
if model.streaming_status != "offline":
|
||||||
await ss.toggle_streaming()
|
await ss.toggle_streaming()
|
||||||
if current_state.replay_buffer_status != "offline":
|
if model.replay_buffer_status != "offline":
|
||||||
await ss.stop_replay_buffer()
|
await ss.stop_replay_buffer()
|
||||||
if current_state.recording_status != "offline":
|
if model.recording_status != "offline":
|
||||||
await ss.toggle_recording()
|
await ss.toggle_recording()
|
||||||
|
|
||||||
conn.close()
|
conn.close()
|
||||||
|
4
tox.ini
4
tox.ini
@ -1,9 +1,11 @@
|
|||||||
[tox]
|
[tox]
|
||||||
env_list = py{310,311,312}
|
env_list = py{311,312,313}
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
passenv = *
|
passenv = *
|
||||||
setenv = VIRTUALENV_DISCOVERY=pyenv
|
setenv = VIRTUALENV_DISCOVERY=pyenv
|
||||||
groups = dev
|
groups = dev
|
||||||
commands =
|
commands =
|
||||||
|
python tests/setup.py
|
||||||
pytest tests
|
pytest tests
|
||||||
|
python tests/teardown.py
|
Loading…
x
Reference in New Issue
Block a user