diff --git a/README.md b/README.md index c6049ed..8fec9c7 100644 --- a/README.md +++ b/README.md @@ -137,7 +137,7 @@ Settings are stored in `~/.config/sendspin/`: | Setting | Type | Mode | Description | |---------|------|------|-------------| -| `player_volume` | integer (0-100) | TUI/daemon | Player output volume percentage | +| `player_volume` | integer (0-100) | TUI/daemon | Player output volume percentage (`--player-volume`) | | `player_muted` | boolean | TUI/daemon | Whether the player is muted | | `static_delay_ms` | float | TUI/daemon | Extra playback delay in milliseconds | | `last_server_url` | string | TUI/daemon | Server URL (used as default for `--url`) | diff --git a/sendspin/cli.py b/sendspin/cli.py index 0bead5b..2893a89 100644 --- a/sendspin/cli.py +++ b/sendspin/cli.py @@ -171,6 +171,13 @@ def _add_player_runtime_options(target: ArgumentTarget, *, suppress_defaults: bo default=default, help="Extra playback delay in milliseconds applied after clock sync", ) + target.add_argument( + "--player-volume", + type=int, + default=default, + metavar="{0-100}", + help="Initial player output volume percentage (0-100)", + ) target.add_argument( "--audio-device", type=str, @@ -403,6 +410,13 @@ def _build_parser() -> argparse.ArgumentParser: default=None, help="Extra playback delay in milliseconds applied after clock sync", ) + daemon_parser.add_argument( + "--player-volume", + type=int, + default=None, + metavar="{0-100}", + help="Initial player output volume percentage (0-100)", + ) daemon_parser.add_argument( "--audio-device", type=str, @@ -711,6 +725,7 @@ async def _run_daemon_mode( client_name=client_name, settings=settings, static_delay_ms=args.static_delay_ms, + player_volume=args.player_volume, listen_port=args.listen_port, use_mpris=args.use_mpris, preferred_format=_resolve_preferred_format(args.audio_format, audio_device), @@ -821,6 +836,8 @@ async def _run_client_mode(args: argparse.Namespace) -> int: args.audio_device = settings.audio_device if args.static_delay_ms is None and settings.static_delay_ms != 0.0: args.static_delay_ms = settings.static_delay_ms + if args.player_volume is None: + args.player_volume = settings.player_volume if args.log_level is None: args.log_level = settings.log_level or "INFO" if is_daemon and getattr(args, "listen_port", None) is None: @@ -911,6 +928,7 @@ async def _run_client_mode(args: argparse.Namespace) -> int: client_name=client_name, settings=settings, static_delay_ms=args.static_delay_ms, + player_volume=args.player_volume, use_mpris=args.use_mpris, preferred_format=_resolve_preferred_format(args.audio_format, audio_device), volume_controller=volume_controller, diff --git a/sendspin/daemon/daemon.py b/sendspin/daemon/daemon.py index 2faa15c..09878e2 100644 --- a/sendspin/daemon/daemon.py +++ b/sendspin/daemon/daemon.py @@ -45,6 +45,7 @@ class DaemonArgs: settings: ClientSettings url: str | None = None static_delay_ms: float | None = None + player_volume: int | None = None listen_port: int = 8928 use_mpris: bool = True preferred_format: SupportedAudioFormat | None = None @@ -139,9 +140,16 @@ def signal_handler() -> None: ) self._static_delay_ms = max(0.0, min(5000.0, delay)) + # CLI arg overrides settings for the initial player volume + volume = ( + self._args.player_volume + if self._args.player_volume is not None + else self._settings.player_volume + ) + self._audio_handler = AudioStreamHandler( audio_device=self._args.audio_device, - volume=self._settings.player_volume, + volume=max(0, min(100, volume)), muted=self._settings.player_muted, on_event=self._on_stream_event, on_format_change=self._handle_format_change, diff --git a/sendspin/tui/app.py b/sendspin/tui/app.py index ad6eb63..a2a51a1 100644 --- a/sendspin/tui/app.py +++ b/sendspin/tui/app.py @@ -241,6 +241,7 @@ class AppArgs: url: str | None = None url_from_settings: bool = False static_delay_ms: float | None = None + player_volume: int | None = None use_mpris: bool = True preferred_format: SupportedAudioFormat | None = None volume_controller: VolumeController | None = None @@ -467,9 +468,16 @@ def request_shutdown() -> None: ) self._applied_delay_ms = max(0.0, min(5000.0, delay)) + # CLI arg overrides settings for the initial player volume + volume = ( + args.player_volume + if args.player_volume is not None + else self._settings.player_volume + ) + self._audio_handler = AudioStreamHandler( audio_device=args.audio_device, - volume=self._settings.player_volume, + volume=max(0, min(100, volume)), muted=self._settings.player_muted, on_event=self._on_stream_event, on_format_change=self._handle_format_change,