Compare commits

...

2 Commits

Author SHA1 Message Date
1dd6992129 add output to scene switch command
add unit test

patch bump
2025-05-19 01:45:31 +01:00
81762508a7 add env var and defaults to --help
move Settings into settings module

patch bump
2025-05-19 01:42:59 +01:00
5 changed files with 70 additions and 46 deletions

View File

@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: 2025-present onyx-and-iris <code@onyxandiris.online> # SPDX-FileCopyrightText: 2025-present onyx-and-iris <code@onyxandiris.online>
# #
# SPDX-License-Identifier: MIT # SPDX-License-Identifier: MIT
__version__ = "0.10.3" __version__ = "0.10.5"

View File

@ -1,11 +1,9 @@
"""Command line interface for the OBS WebSocket API.""" """Command line interface for the OBS WebSocket API."""
from pathlib import Path from typing import Annotated
from typing import Annotated, Optional
import obsws_python as obsws import obsws_python as obsws
import typer import typer
from pydantic_settings import BaseSettings, SettingsConfigDict
from . import ( from . import (
group, group,
@ -16,31 +14,13 @@ from . import (
scene, scene,
scenecollection, scenecollection,
sceneitem, sceneitem,
settings,
stream, stream,
studiomode, studiomode,
virtualcam, virtualcam,
) )
from .alias import AliasGroup from .alias import AliasGroup
class Settings(BaseSettings):
"""Settings for the OBS WebSocket client."""
model_config = SettingsConfigDict(
env_file=(
'.env',
Path.home() / '.config' / 'obsws-cli' / 'obsws.env',
),
env_file_encoding='utf-8',
env_prefix='OBS_',
)
HOST: str = 'localhost'
PORT: int = 4455
PASSWORD: str = '' # No password by default
TIMEOUT: int = 5 # Timeout for requests in seconds
app = typer.Typer(cls=AliasGroup) app = typer.Typer(cls=AliasGroup)
for module in ( for module in (
group, group,
@ -61,31 +41,26 @@ for module in (
@app.callback() @app.callback()
def main( def main(
ctx: typer.Context, ctx: typer.Context,
host: Annotated[Optional[str], typer.Option(help='WebSocket host')] = None, host: Annotated[
port: Annotated[Optional[int], typer.Option(help='WebSocket port')] = None, str,
password: Annotated[Optional[str], typer.Option(help='WebSocket password')] = None, typer.Option(
timeout: Annotated[Optional[int], typer.Option(help='WebSocket timeout')] = None, envvar='OBS_HOST', help='WebSocket host', show_default='localhost'
),
] = settings.get('HOST'),
port: Annotated[
int, typer.Option(envvar='OBS_PORT', help='WebSocket port', show_default=4455)
] = settings.get('PORT'),
password: Annotated[
str,
typer.Option(envvar='OBS_PASSWORD', help='WebSocket password', show_default=''),
] = settings.get('PASSWORD'),
timeout: Annotated[
int,
typer.Option(envvar='OBS_TIMEOUT', help='WebSocket timeout', show_default=5),
] = settings.get('TIMEOUT'),
): ):
"""obsws_cli is a command line interface for the OBS WebSocket API.""" """obsws_cli is a command line interface for the OBS WebSocket API."""
settings = Settings() ctx.obj = ctx.with_resource(obsws.ReqClient(**ctx.params))
# Allow overriding settings with command line options
if host:
settings.HOST = host
if port:
settings.PORT = port
if password:
settings.PASSWORD = password
if timeout:
settings.TIMEOUT = timeout
ctx.obj = ctx.with_resource(
obsws.ReqClient(
host=settings.HOST,
port=settings.PORT,
password=settings.PASSWORD,
timeout=settings.TIMEOUT,
)
)
@app.command() @app.command()

View File

@ -65,5 +65,7 @@ def switch(
if preview: if preview:
ctx.obj.set_current_preview_scene(scene_name) ctx.obj.set_current_preview_scene(scene_name)
typer.echo(f'Switched to preview scene: {scene_name}')
else: else:
ctx.obj.set_current_program_scene(scene_name) ctx.obj.set_current_program_scene(scene_name)
typer.echo(f'Switched to program scene: {scene_name}')

31
obsws_cli/settings.py Normal file
View File

@ -0,0 +1,31 @@
"""module for settings management."""
from pathlib import Path
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
"""Settings for the OBS WebSocket client."""
model_config = SettingsConfigDict(
env_file=(
'.env',
Path.home() / '.config' / 'obsws-cli' / 'obsws.env',
),
env_file_encoding='utf-8',
env_prefix='OBS_',
)
HOST: str = 'localhost'
PORT: int = 4455
PASSWORD: str = '' # No password by default
TIMEOUT: int = 5 # Timeout for requests in seconds
_settings = Settings().model_dump()
def get(key: str) -> str:
"""Get a setting by key."""
return _settings.get(key)

View File

@ -20,3 +20,19 @@ def test_scene_current():
result = runner.invoke(app, ['scene', 'current']) result = runner.invoke(app, ['scene', 'current'])
assert result.exit_code == 0 assert result.exit_code == 0
assert 'pytest' in result.stdout assert 'pytest' in result.stdout
def test_scene_switch():
"""Test the scene switch command."""
result = runner.invoke(app, ['studiomode', 'status'])
assert result.exit_code == 0
enabled = 'Studio mode is enabled.' in result.stdout
if enabled:
result = runner.invoke(app, ['scene', 'switch', 'pytest', '--preview'])
assert result.exit_code == 0
assert 'Switched to preview scene: pytest' in result.stdout
else:
result = runner.invoke(app, ['scene', 'switch', 'pytest'])
assert result.exit_code == 0
assert 'Switched to program scene: pytest' in result.stdout