mirror of
https://github.com/onyx-and-iris/vban-cli.git
synced 2026-04-16 02:23:30 +00:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c660778698 | |||
| 5460965945 | |||
| d03049e713 | |||
| 1dd518095a |
@@ -74,13 +74,16 @@ For every command and subcommand there exists a `--help` flag for further usage
|
|||||||
2. Packet structure with [ident:1][ident-1] is emitted by the VBAN server only on pdirty events. This means we do not receive the initial state of those parameters on initial subscription. Therefore any commands which are intended to fetch the value of parameters defined in packet [ident:1][ident-1] will not work in this CLI.
|
2. Packet structure with [ident:1][ident-1] is emitted by the VBAN server only on pdirty events. This means we do not receive the initial state of those parameters on initial subscription. Therefore any commands which are intended to fetch the value of parameters defined in packet [ident:1][ident-1] will not work in this CLI.
|
||||||
3. Packet structure with [ident:1][ident-1] defines parameteric EQ data only for the [first channel][ident-1-peq].
|
3. Packet structure with [ident:1][ident-1] defines parameteric EQ data only for the [first channel][ident-1-peq].
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Further Notes
|
## Further Notes
|
||||||
|
|
||||||
I've made the effort to set up the basic skeletal structure of the CLI as well as demonstrate how to combine subcommand groups with subcommand groups so more can be implemented, it just needs doing. There may be restrictions on some things however, for example, retrieving values is only possible for parameters [defined in the protocol](https://github.com/onyx-and-iris/Voicemeeter-SDK/blob/3be2c1c36563afbd6df3da8436406c77d2cc1f10/VoicemeeterRemote.h#L787). Setting parameters can be done for anything possible by a string request.
|
I've made the effort to set up the basic skeletal structure of the CLI as well as demonstrate how to combine subcommand groups with subcommand groups so more can be implemented, it just needs doing. There may be restrictions on some things however, for example, retrieving values is only possible for parameters [defined in the protocol](https://github.com/onyx-and-iris/Voicemeeter-SDK/blob/3be2c1c36563afbd6df3da8436406c77d2cc1f10/VoicemeeterRemote.h#L787). Setting parameters can be done for anything possible by a string request.
|
||||||
|
|
||||||
|
Shell completion scripts are available (for zsh, bash and fish) but I haven't tested them
|
||||||
|
|
||||||
|
Some of the help output needs improving for commands that branch off positional arguments.
|
||||||
|
|
||||||
If there's something missing that you would like to see added the best bet is to submit a PR. You may raise an issue and if it's quick and simple to do I may (or may not) do it.
|
If there's something missing that you would like to see added the best bet is to submit a PR. You may raise an issue and if it's quick and simple to do I may (or may not) do it.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -1,11 +1,15 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "vban-cli"
|
name = "vban-cli"
|
||||||
version = "0.3.0"
|
version = "0.4.1"
|
||||||
description = "A command-line interface for Voicemeeter leveraging VBAN."
|
description = "A command-line interface for Voicemeeter leveraging VBAN."
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
license = { text = "LICENSE" }
|
license = { text = "LICENSE" }
|
||||||
requires-python = ">=3.13"
|
requires-python = ">=3.13"
|
||||||
dependencies = ["cyclopts>=4.6.0", "vban-cmd>=2.6.0"]
|
dependencies = [
|
||||||
|
"cyclopts>=4.6.0",
|
||||||
|
"loguru>=0.7.3",
|
||||||
|
"vban-cmd>=2.6.0",
|
||||||
|
]
|
||||||
classifiers = [
|
classifiers = [
|
||||||
"Development Status :: 3 - Alpha",
|
"Development Status :: 3 - Alpha",
|
||||||
"Programming Language :: Python",
|
"Programming Language :: Python",
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ app = App(
|
|||||||
)
|
)
|
||||||
app.command(strip.app.meta, name='strip')
|
app.command(strip.app.meta, name='strip')
|
||||||
app.command(bus.app.meta, name='bus')
|
app.command(bus.app.meta, name='bus')
|
||||||
|
app.register_install_completion_command()
|
||||||
|
|
||||||
|
|
||||||
@Parameter(name='*')
|
@Parameter(name='*')
|
||||||
@@ -32,17 +33,17 @@ def launcher(
|
|||||||
*tokens: Annotated[str, Parameter(show=False, allow_leading_hyphen=True)],
|
*tokens: Annotated[str, Parameter(show=False, allow_leading_hyphen=True)],
|
||||||
vban_config: Annotated[VBANConfig, Parameter()] = VBANConfig(),
|
vban_config: Annotated[VBANConfig, Parameter()] = VBANConfig(),
|
||||||
):
|
):
|
||||||
|
command, bound, _ = app.parse_args(tokens)
|
||||||
|
if tokens[0] == '--install-completion':
|
||||||
|
return command(*bound.args, **bound.kwargs)
|
||||||
|
|
||||||
with vban_cmd.api(
|
with vban_cmd.api(
|
||||||
vban_config.kind,
|
vban_config.kind,
|
||||||
ip=vban_config.host,
|
ip=vban_config.host,
|
||||||
port=vban_config.port,
|
port=vban_config.port,
|
||||||
streamname=vban_config.streamname,
|
streamname=vban_config.streamname,
|
||||||
) as client:
|
) as client:
|
||||||
additional_kwargs = {}
|
return command(*bound.args, **bound.kwargs, ctx=Context(client=client))
|
||||||
command, bound, _ = app.parse_args(tokens)
|
|
||||||
additional_kwargs['ctx'] = Context(client=client)
|
|
||||||
|
|
||||||
return command(*bound.args, **bound.kwargs, **additional_kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
def run():
|
def run():
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ def launcher(
|
|||||||
"""Control the bus parameters."""
|
"""Control the bus parameters."""
|
||||||
additional_kwargs = {}
|
additional_kwargs = {}
|
||||||
command, bound, _ = app.parse_args(tokens)
|
command, bound, _ = app.parse_args(tokens)
|
||||||
|
if tokens[0] == 'eq':
|
||||||
|
additional_kwargs['eq_kind'] = app.name[0]
|
||||||
if index is not None:
|
if index is not None:
|
||||||
additional_kwargs['index'] = index
|
additional_kwargs['index'] = index
|
||||||
if ctx is not None:
|
if ctx is not None:
|
||||||
|
|||||||
@@ -5,28 +5,30 @@ from cyclopts import App, Argument, Parameter
|
|||||||
from .context import Context
|
from .context import Context
|
||||||
from .help import CustomHelpFormatter
|
from .help import CustomHelpFormatter
|
||||||
|
|
||||||
|
cell_app = App(name='cell', help_formatter=CustomHelpFormatter())
|
||||||
|
|
||||||
app = App(name='eq', help_formatter=CustomHelpFormatter())
|
app = App(name='eq', help_formatter=CustomHelpFormatter())
|
||||||
|
app.command(cell_app.meta, name='cell')
|
||||||
|
|
||||||
|
|
||||||
@app.meta.default
|
@app.meta.default
|
||||||
def launcher(
|
def launcher(
|
||||||
band: Annotated[int, Argument()] = None,
|
|
||||||
*tokens: Annotated[str, Parameter(show=False, allow_leading_hyphen=True)],
|
*tokens: Annotated[str, Parameter(show=False, allow_leading_hyphen=True)],
|
||||||
|
eq_kind: Annotated[str, Parameter(show=False)] = None,
|
||||||
index: Annotated[int, Argument()] = None,
|
index: Annotated[int, Argument()] = None,
|
||||||
ctx: Annotated[Context, Parameter(show=False)] = None,
|
ctx: Annotated[Context, Parameter(show=False)] = None,
|
||||||
):
|
):
|
||||||
"""Control the EQ parameters.
|
"""Control the EQ parameters."""
|
||||||
|
|
||||||
Only channel 0 is supported, see https://github.com/onyx-and-iris/vban-cli?tab=readme-ov-file#implementation-notes - 3.
|
|
||||||
"""
|
|
||||||
additional_kwargs = {}
|
additional_kwargs = {}
|
||||||
command, bound, _ = app.parse_args(tokens)
|
command, bound, _ = app.parse_args(tokens)
|
||||||
if index is not None:
|
match eq_kind:
|
||||||
additional_kwargs['index'] = index
|
case 'strip':
|
||||||
if band is not None:
|
target = ctx.client.strip[index].eq
|
||||||
additional_kwargs['band'] = band
|
case 'bus':
|
||||||
if ctx is not None:
|
target = ctx.client.bus[index].eq
|
||||||
additional_kwargs['ctx'] = ctx
|
case _:
|
||||||
|
raise ValueError(f'Invalid eq_kind: {eq_kind}')
|
||||||
|
additional_kwargs['target'] = target
|
||||||
|
|
||||||
return command(*bound.args, **bound.kwargs, **additional_kwargs)
|
return command(*bound.args, **bound.kwargs, **additional_kwargs)
|
||||||
|
|
||||||
@@ -35,9 +37,7 @@ def launcher(
|
|||||||
def on(
|
def on(
|
||||||
new_state: Annotated[bool, Argument()] = None,
|
new_state: Annotated[bool, Argument()] = None,
|
||||||
*,
|
*,
|
||||||
index: Annotated[int, Parameter(show=False)] = None,
|
target: Annotated[object, Parameter(show=False)] = None,
|
||||||
band: Annotated[int, Parameter(show=False)] = None,
|
|
||||||
ctx: Annotated[Context, Parameter(show=False)] = None,
|
|
||||||
):
|
):
|
||||||
"""Get or set the on state of the specified EQ band.
|
"""Get or set the on state of the specified EQ band.
|
||||||
|
|
||||||
@@ -48,6 +48,43 @@ def on(
|
|||||||
"""
|
"""
|
||||||
if new_state is None:
|
if new_state is None:
|
||||||
# See https://github.com/onyx-and-iris/vban-cli?tab=readme-ov-file#implementation-notes - 2.
|
# See https://github.com/onyx-and-iris/vban-cli?tab=readme-ov-file#implementation-notes - 2.
|
||||||
# console.out.print(ctx.client.strip[index].eq.channel[0].cell[band].on)
|
# console.out.print(target.on)
|
||||||
return
|
return
|
||||||
ctx.client.strip[index].eq.channel[0].cell[band].on = new_state
|
target.on = new_state
|
||||||
|
|
||||||
|
|
||||||
|
@cell_app.meta.default
|
||||||
|
def cell_launcher(
|
||||||
|
band: Annotated[int, Argument()] = None,
|
||||||
|
*tokens: Annotated[str, Parameter(show=False, allow_leading_hyphen=True)],
|
||||||
|
target: Annotated[object, Parameter(show=False)] = None,
|
||||||
|
):
|
||||||
|
"""Control the EQ Cell parameters.
|
||||||
|
|
||||||
|
Only channel 0 is supported, see https://github.com/onyx-and-iris/vban-cli?tab=readme-ov-file#implementation-notes - 3.
|
||||||
|
"""
|
||||||
|
additional_kwargs = {}
|
||||||
|
command, bound, _ = app.parse_args(tokens)
|
||||||
|
additional_kwargs['target'] = target.channel[0].cell[band]
|
||||||
|
|
||||||
|
return command(*bound.args, **bound.kwargs, **additional_kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
@cell_app.command(name='on')
|
||||||
|
def cell_on(
|
||||||
|
new_state: Annotated[bool, Argument()] = None,
|
||||||
|
*,
|
||||||
|
target: Annotated[object, Parameter(show=False)] = None,
|
||||||
|
):
|
||||||
|
"""Get or set the on state of the specified EQ cell.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
new_state : bool
|
||||||
|
If provided, sets the on state to this value. If not provided, the current on state is printed.
|
||||||
|
"""
|
||||||
|
if new_state is None:
|
||||||
|
# See https://github.com/onyx-and-iris/vban-cli?tab=readme-ov-file#implementation-notes - 2.
|
||||||
|
# console.out.print(target.on)
|
||||||
|
return
|
||||||
|
target.on = new_state
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ def launcher(
|
|||||||
"""Control the strip parameters."""
|
"""Control the strip parameters."""
|
||||||
additional_kwargs = {}
|
additional_kwargs = {}
|
||||||
command, bound, _ = app.parse_args(tokens)
|
command, bound, _ = app.parse_args(tokens)
|
||||||
|
if tokens[0] == 'eq':
|
||||||
|
additional_kwargs['eq_kind'] = app.name[0]
|
||||||
if index is not None:
|
if index is not None:
|
||||||
additional_kwargs['index'] = index
|
additional_kwargs['index'] = index
|
||||||
if ctx is not None:
|
if ctx is not None:
|
||||||
|
|||||||
35
uv.lock
generated
35
uv.lock
generated
@@ -11,6 +11,15 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373", size = 67615, upload-time = "2025-10-06T13:54:43.17Z" },
|
{ url = "https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373", size = 67615, upload-time = "2025-10-06T13:54:43.17Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "colorama"
|
||||||
|
version = "0.4.6"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cyclopts"
|
name = "cyclopts"
|
||||||
version = "4.6.0"
|
version = "4.6.0"
|
||||||
@@ -44,6 +53,19 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/02/10/5da547df7a391dcde17f59520a231527b8571e6f46fc8efb02ccb370ab12/docutils-0.22.4-py3-none-any.whl", hash = "sha256:d0013f540772d1420576855455d050a2180186c91c15779301ac2ccb3eeb68de", size = 633196, upload-time = "2025-12-18T19:00:18.077Z" },
|
{ url = "https://files.pythonhosted.org/packages/02/10/5da547df7a391dcde17f59520a231527b8571e6f46fc8efb02ccb370ab12/docutils-0.22.4-py3-none-any.whl", hash = "sha256:d0013f540772d1420576855455d050a2180186c91c15779301ac2ccb3eeb68de", size = 633196, upload-time = "2025-12-18T19:00:18.077Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "loguru"
|
||||||
|
version = "0.7.3"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
||||||
|
{ name = "win32-setctime", marker = "sys_platform == 'win32'" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/3a/05/a1dae3dffd1116099471c643b8924f5aa6524411dc6c63fdae648c4f1aca/loguru-0.7.3.tar.gz", hash = "sha256:19480589e77d47b8d85b2c827ad95d49bf31b0dcde16593892eb51dd18706eb6", size = 63559, upload-time = "2024-12-06T11:20:56.608Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0c/29/0348de65b8cc732daa3e33e67806420b2ae89bdce2b04af740289c5c6c8c/loguru-0.7.3-py3-none-any.whl", hash = "sha256:31a33c10c8e1e10422bfd431aeb5d351c7cf7fa671e3c4df004162264b28220c", size = 61595, upload-time = "2024-12-06T11:20:54.538Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "markdown-it-py"
|
name = "markdown-it-py"
|
||||||
version = "4.0.0"
|
version = "4.0.0"
|
||||||
@@ -102,16 +124,18 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vban-cli"
|
name = "vban-cli"
|
||||||
version = "0.3.0"
|
version = "0.4.1"
|
||||||
source = { editable = "." }
|
source = { editable = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "cyclopts" },
|
{ name = "cyclopts" },
|
||||||
|
{ name = "loguru" },
|
||||||
{ name = "vban-cmd" },
|
{ name = "vban-cmd" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.metadata]
|
[package.metadata]
|
||||||
requires-dist = [
|
requires-dist = [
|
||||||
{ name = "cyclopts", specifier = ">=4.6.0" },
|
{ name = "cyclopts", specifier = ">=4.6.0" },
|
||||||
|
{ name = "loguru", specifier = ">=0.7.3" },
|
||||||
{ name = "vban-cmd", directory = "../vban-cmd-python" },
|
{ name = "vban-cmd", directory = "../vban-cmd-python" },
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -122,3 +146,12 @@ source = { directory = "../vban-cmd-python" }
|
|||||||
|
|
||||||
[package.metadata]
|
[package.metadata]
|
||||||
requires-dist = [{ name = "tomli", marker = "python_full_version < '3.11'", specifier = ">=2.0.1,<3.0" }]
|
requires-dist = [{ name = "tomli", marker = "python_full_version < '3.11'", specifier = ">=2.0.1,<3.0" }]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "win32-setctime"
|
||||||
|
version = "1.2.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/b3/8f/705086c9d734d3b663af0e9bb3d4de6578d08f46b1b101c2442fd9aecaa2/win32_setctime-1.2.0.tar.gz", hash = "sha256:ae1fdf948f5640aae05c511ade119313fb6a30d7eabe25fef9764dca5873c4c0", size = 4867, upload-time = "2024-12-07T15:28:28.314Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e1/07/c6fe3ad3e685340704d314d765b7912993bcb8dc198f0e7a89382d37974b/win32_setctime-1.2.0-py3-none-any.whl", hash = "sha256:95d644c4e708aba81dc3704a116d8cbc974d70b3bdb8be1d150e36be6e9d1390", size = 4083, upload-time = "2024-12-07T15:28:26.465Z" },
|
||||||
|
]
|
||||||
|
|||||||
Reference in New Issue
Block a user