From 4fc3dc015af3ecdcd9a2c196a32e5229655edfd3 Mon Sep 17 00:00:00 2001 From: onyx-and-iris Date: Tue, 10 Jun 2025 14:03:26 +0100 Subject: [PATCH] add audio subcommand group minor bump --- pyproject.toml | 2 +- src/slobs_cli/__init__.py | 3 +- src/slobs_cli/audio.py | 129 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 132 insertions(+), 2 deletions(-) create mode 100644 src/slobs_cli/audio.py diff --git a/pyproject.toml b/pyproject.toml index 12efbe8..d70e31d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "slobs-cli" -version = "0.4.0" +version = "0.5.0" description = "A command line application for Streamlabs Desktop" authors = [{ name = "onyx-and-iris", email = "code@onyxandiris.online" }] dependencies = ["pyslobs>=2.0.4", "asyncclick>=8.1.8"] diff --git a/src/slobs_cli/__init__.py b/src/slobs_cli/__init__.py index 1790eb6..0891f24 100644 --- a/src/slobs_cli/__init__.py +++ b/src/slobs_cli/__init__.py @@ -1,6 +1,7 @@ +from .audio import audio from .cli import cli from .record import record from .scene import scene from .stream import stream -__all__ = ["cli", "scene", "stream", "record"] +__all__ = ["cli", "scene", "stream", "record", "audio"] diff --git a/src/slobs_cli/audio.py b/src/slobs_cli/audio.py new file mode 100644 index 0000000..3a596c4 --- /dev/null +++ b/src/slobs_cli/audio.py @@ -0,0 +1,129 @@ +import asyncclick as click +from anyio import create_task_group +from pyslobs import AudioService + +from .cli import cli + + +@cli.group() +def audio(): + """Audio management commands.""" + + +@audio.command() +@click.pass_context +async def list(ctx: click.Context): + """List all audio sources.""" + + conn = ctx.obj["connection"] + as_ = AudioService(conn) + + async def _run(): + sources = await as_.get_sources() + if not sources: + conn.close() + click.Abort(click.style("No audio sources found.", fg="red")) + + for source in sources: + model = await source.get_model() + click.echo( + f"Source ID: {source.source_id}, Name: {model.name}, Muted: {model.muted}" + ) + conn.close() + + async with create_task_group() as tg: + tg.start_soon(conn.background_processing) + tg.start_soon(_run) + + +@audio.command() +@click.argument("source_name") +@click.pass_context +async def mute(ctx: click.Context, source_name: str): + """Mute an audio source by name.""" + + conn = ctx.obj["connection"] + as_ = AudioService(conn) + + async def _run(): + sources = await as_.get_sources() + for source in sources: + model = await source.get_model() + if model.name.lower() == source_name.lower(): + break + else: + conn.close() + raise click.Abort( + click.style(f"Source '{source_name}' not found.", fg="red") + ) + + await source.set_muted(True) + click.echo(f"Muted audio source: {source_name}") + conn.close() + + async with create_task_group() as tg: + tg.start_soon(conn.background_processing) + tg.start_soon(_run) + + +@audio.command() +@click.argument("source_name") +@click.pass_context +async def unmute(ctx: click.Context, source_name: str): + """Unmute an audio source by name.""" + + conn = ctx.obj["connection"] + as_ = AudioService(conn) + + async def _run(): + sources = await as_.get_sources() + for source in sources: + model = await source.get_model() + if model.name.lower() == source_name.lower(): + break + else: + conn.close() + raise click.Abort( + click.style(f"Source '{source_name}' not found.", fg="red") + ) + + await source.set_muted(False) + click.echo(f"Unmuted audio source: {source_name}") + conn.close() + + async with create_task_group() as tg: + tg.start_soon(conn.background_processing) + tg.start_soon(_run) + + +@audio.command() +@click.argument("source_name") +@click.pass_context +async def toggle(ctx: click.Context, source_name: str): + """Toggle mute state of an audio source by name.""" + + conn = ctx.obj["connection"] + as_ = AudioService(conn) + + async def _run(): + sources = await as_.get_sources() + for source in sources: + model = await source.get_model() + if model.name.lower() == source_name.lower(): + if model.muted: + await source.set_muted(False) + click.echo(f"Unmuted audio source: {source_name}") + else: + await source.set_muted(True) + click.echo(f"Muted audio source: {source_name}") + conn.close() + break + else: + conn.close() + raise click.Abort( + click.style(f"Source '{source_name}' not found.", fg="red") + ) + + async with create_task_group() as tg: + tg.start_soon(conn.background_processing) + tg.start_soon(_run)