3 Commits
v0.8.0 ... main

Author SHA1 Message Date
f794464170 upd docstrings and openapi tags
patch bump
2026-04-06 22:05:28 +01:00
0a4175e690 patch bump 2026-04-06 21:53:36 +01:00
c24c05a3ff as sync... oops 2026-04-06 21:53:00 +01:00
7 changed files with 33 additions and 24 deletions

View File

@@ -1,6 +1,6 @@
[project] [project]
name = "vmr-http" name = "vmr-http"
version = "0.8.0" version = "0.8.2"
description = "HTTP API for controlling Voicemeeter" description = "HTTP API for controlling Voicemeeter"
readme = "README.md" readme = "README.md"
authors = [{ name = "onyx-and-iris", email = "code@onyxandiris.online" }] authors = [{ name = "onyx-and-iris", email = "code@onyxandiris.online" }]

View File

@@ -24,7 +24,16 @@ app = FastAPI(
description='A REST API for controlling Voicemeeter.', description='A REST API for controlling Voicemeeter.',
openapi_tags=[ openapi_tags=[
{'name': 'strip', 'description': 'Endpoints for controlling strip parameters.'}, {'name': 'strip', 'description': 'Endpoints for controlling strip parameters.'},
{'name': 'strip gainlayer', 'description': 'Endpoints for controlling strip gain layer parameters.'},
{'name': 'strip comp', 'description': 'Endpoints for controlling strip compressor parameters.'},
{'name': 'strip gate', 'description': 'Endpoints for controlling strip gate parameters.'},
{'name': 'strip eq', 'description': 'Endpoints for controlling strip equalizer parameters.'},
{'name': 'strip denoiser', 'description': 'Endpoints for controlling strip denoiser parameters.'},
{'name': 'bus', 'description': 'Endpoints for controlling bus parameters.'}, {'name': 'bus', 'description': 'Endpoints for controlling bus parameters.'},
{'name': 'bus mode', 'description': 'Endpoints for controlling bus mode parameters.'},
{'name': 'bus eq', 'description': 'Endpoints for controlling bus equalizer parameters.'},
{'name': 'command', 'description': 'Endpoints for executing Voicemeeter commands.'},
{'name': 'healthcheck', 'description': 'Endpoint for checking the health of the service.'},
], ],
) )
app.include_router(strip.router, prefix='/strip/{index}') app.include_router(strip.router, prefix='/strip/{index}')
@@ -32,7 +41,7 @@ app.include_router(bus.router, prefix='/bus/{index}')
app.include_router(command.router, prefix='/command') app.include_router(command.router, prefix='/command')
@app.get('/health') @app.get('/health', tags=['healthcheck'])
def health_check(voicemeeter=Depends(get_voicemeeter_client)): def health_check(voicemeeter=Depends(get_voicemeeter_client)):
"""Health check endpoint to verify the service is running.""" """Health check endpoint to verify the service is running."""
try: try:

View File

@@ -13,10 +13,10 @@ class EQParams(BaseModel):
class EQChannelCellParams(BaseModel): class EQChannelCellParams(BaseModel):
"""Parameters for an equalizer channel.""" """Parameters for an equalizer channel cell."""
on: Optional[bool] = Field(None, description='Whether the equalizer channel is enabled or not.') on: Optional[bool] = Field(None, description='Whether the equalizer channel cell is enabled or not.')
type: Optional[int] = Field(None, ge=0, le=6, description='Type of the equalizer channel.') type: Optional[int] = Field(None, ge=0, le=6, description='Type of the equalizer channel cell.')
f: Optional[float] = Field(None, ge=20.0, le=20000.0, description='Frequency of the equalizer channel.') f: Optional[float] = Field(None, ge=20.0, le=20000.0, description='Frequency of the equalizer channel cell.')
gain: Optional[float] = Field(None, ge=-36.0, le=18.0, description='Gain of the equalizer channel.') gain: Optional[float] = Field(None, ge=-36.0, le=18.0, description='Gain of the equalizer channel cell.')
q: Optional[float] = Field(None, ge=0.3, le=100.0, description='Q factor of the equalizer channel.') q: Optional[float] = Field(None, ge=0.3, le=100.0, description='Q factor of the equalizer channel cell.')

View File

@@ -15,42 +15,42 @@ router = APIRouter(tags=['command'])
@router.post('/show') @router.post('/show')
async def show_command(voicemeeter=Depends(get_voicemeeter_client)): def show_command(voicemeeter=Depends(get_voicemeeter_client)):
"""Show the Voicemeeter application.""" """Show the Voicemeeter application."""
voicemeeter.command.show() voicemeeter.command.show()
return {'status': 'Voicemeeter shown'} return {'status': 'Voicemeeter shown'}
@router.post('/hide') @router.post('/hide')
async def hide_command(voicemeeter=Depends(get_voicemeeter_client)): def hide_command(voicemeeter=Depends(get_voicemeeter_client)):
"""Hide the Voicemeeter application.""" """Hide the Voicemeeter application."""
voicemeeter.command.hide() voicemeeter.command.hide()
return {'status': 'Voicemeeter hidden'} return {'status': 'Voicemeeter hidden'}
@router.post('/shutdown') @router.post('/shutdown')
async def shutdown_command(voicemeeter=Depends(get_voicemeeter_client)): def shutdown_command(voicemeeter=Depends(get_voicemeeter_client)):
"""Shutdown the Voicemeeter application.""" """Shutdown the Voicemeeter application."""
voicemeeter.command.shutdown() voicemeeter.command.shutdown()
return {'status': 'Voicemeeter shutdown'} return {'status': 'Voicemeeter shutdown'}
@router.post('/restart') @router.post('/restart')
async def restart_command(voicemeeter=Depends(get_voicemeeter_client)): def restart_command(voicemeeter=Depends(get_voicemeeter_client)):
"""Restart the Voicemeeter application.""" """Restart the Voicemeeter engine."""
voicemeeter.command.restart() voicemeeter.command.restart()
return {'status': 'Voicemeeter restarted'} return {'status': 'Voicemeeter restarted'}
@router.post('/lock') @router.post('/lock')
async def lock_command(voicemeeter=Depends(get_voicemeeter_client)): def lock_command(voicemeeter=Depends(get_voicemeeter_client)):
"""Lock the Voicemeeter application.""" """Lock the Voicemeeter application."""
voicemeeter.command.lock = True voicemeeter.command.lock = True
return {'status': 'Voicemeeter locked'} return {'status': 'Voicemeeter locked'}
@router.post('/unlock') @router.post('/unlock')
async def unlock_command(voicemeeter=Depends(get_voicemeeter_client)): def unlock_command(voicemeeter=Depends(get_voicemeeter_client)):
"""Unlock the Voicemeeter application.""" """Unlock the Voicemeeter application."""
voicemeeter.command.lock = False voicemeeter.command.lock = False
return {'status': 'Voicemeeter unlocked'} return {'status': 'Voicemeeter unlocked'}

View File

@@ -77,7 +77,7 @@ def create_router(eq_kind: str) -> APIRouter:
@router.patch('') @router.patch('')
@router.put('') @router.put('')
def update_eq_params(index: int, params: EQParams, voicemeeter=Depends(get_voicemeeter_client)): def update_eq_params(index: int, params: EQParams, voicemeeter=Depends(get_voicemeeter_client)):
"""Update one or more equalizer parameters for the specified index.""" """Update one or more equalizer parameters for the specified channel index (strip or bus)."""
eq = target_cls(voicemeeter, index).eq eq = target_cls(voicemeeter, index).eq
updated = {} updated = {}
for key, value in params.model_dump(exclude_unset=True).items(): for key, value in params.model_dump(exclude_unset=True).items():
@@ -87,12 +87,12 @@ def create_router(eq_kind: str) -> APIRouter:
@router.get('/on') @router.get('/on')
def get_eq_on(index: int, voicemeeter=Depends(get_voicemeeter_client)): def get_eq_on(index: int, voicemeeter=Depends(get_voicemeeter_client)):
"""Get the current equalizer on status for the specified index.""" """Get the current equalizer on status for the specified channel index (strip or bus)."""
return {'on': target_cls(voicemeeter, index).eq.on} return {'on': target_cls(voicemeeter, index).eq.on}
@router.get('/ab') @router.get('/ab')
def get_eq_ab(index: int, voicemeeter=Depends(get_voicemeeter_client)): def get_eq_ab(index: int, voicemeeter=Depends(get_voicemeeter_client)):
"""Get the current equalizer A/B status for the specified index.""" """Get the current equalizer A/B status for the specified channel index (strip or bus)."""
return {'ab': target_cls(voicemeeter, index).eq.ab} return {'ab': target_cls(voicemeeter, index).eq.ab}
return router return router

View File

@@ -9,19 +9,19 @@ router = APIRouter()
@router.patch('') @router.patch('')
@router.put('') @router.put('')
def update_strip_comp_params( def update_strip_gainlayer_params(
index: int, index: int,
gainlayer_index: int, gainlayer_index: int,
level: float = Body(..., ge=-60.0, le=12.0, embed=True), level: float = Body(..., ge=-60.0, le=12.0, embed=True),
voicemeeter=Depends(get_voicemeeter_client), voicemeeter=Depends(get_voicemeeter_client),
): ):
"""Update one or more compressor parameters for the specified strip index.""" """Update one or more gain layer parameters for the specified strip index."""
gainlayer = voicemeeter.strip[index].gainlayer[gainlayer_index] gainlayer = voicemeeter.strip[index].gainlayer[gainlayer_index]
gainlayer.gain = level gainlayer.gain = level
return {'gain_layer': {'level': gainlayer.gain}} return {'gainlayer': {'level': gainlayer.gain}}
@router.get('/level') @router.get('/level')
def get_strip_gain_layer_level(index: int, gainlayer_index: int, voicemeeter=Depends(get_voicemeeter_client)): def get_strip_gainlayer_level(index: int, gainlayer_index: int, voicemeeter=Depends(get_voicemeeter_client)):
"""Get the current gain layer level for the specified strip index.""" """Get the current gain layer level for the specified strip index."""
return {'gain_layer': {'level': voicemeeter.strip[index].gainlayer[gainlayer_index].gain}} return {'gainlayer': {'level': voicemeeter.strip[index].gainlayer[gainlayer_index].gain}}

2
uv.lock generated
View File

@@ -1151,7 +1151,7 @@ wheels = [
[[package]] [[package]]
name = "vmr-http" name = "vmr-http"
version = "0.8.0" version = "0.8.2"
source = { editable = "." } source = { editable = "." }
dependencies = [ dependencies = [
{ name = "fastapi" }, { name = "fastapi" },