mirror of
https://github.com/onyx-and-iris/vmr-http.git
synced 2026-04-07 02:13:31 +00:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f794464170 | |||
| 0a4175e690 | |||
| c24c05a3ff | |||
| f44da13de9 |
@@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "vmr-http"
|
||||
version = "0.7.2"
|
||||
version = "0.8.2"
|
||||
description = "HTTP API for controlling Voicemeeter"
|
||||
readme = "README.md"
|
||||
authors = [{ name = "onyx-and-iris", email = "code@onyxandiris.online" }]
|
||||
|
||||
@@ -7,7 +7,7 @@ from fastapi import Depends, FastAPI, HTTPException
|
||||
from voicemeeterlib.error import CAPIError
|
||||
|
||||
from .dependencies import get_voicemeeter_client
|
||||
from .web import bus, strip
|
||||
from .web import bus, command, strip
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
@@ -24,14 +24,24 @@ app = FastAPI(
|
||||
description='A REST API for controlling Voicemeeter.',
|
||||
openapi_tags=[
|
||||
{'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 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(bus.router, prefix='/bus/{index}')
|
||||
app.include_router(command.router, prefix='/command')
|
||||
|
||||
|
||||
@app.get('/health')
|
||||
@app.get('/health', tags=['healthcheck'])
|
||||
def health_check(voicemeeter=Depends(get_voicemeeter_client)):
|
||||
"""Health check endpoint to verify the service is running."""
|
||||
try:
|
||||
|
||||
@@ -13,10 +13,10 @@ class EQParams(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.')
|
||||
type: Optional[int] = Field(None, ge=0, le=6, description='Type of the equalizer channel.')
|
||||
f: Optional[float] = Field(None, ge=20.0, le=20000.0, description='Frequency of the equalizer channel.')
|
||||
gain: Optional[float] = Field(None, ge=-36.0, le=18.0, description='Gain of the equalizer channel.')
|
||||
q: Optional[float] = Field(None, ge=0.3, le=100.0, description='Q factor of the equalizer channel.')
|
||||
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 cell.')
|
||||
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 cell.')
|
||||
q: Optional[float] = Field(None, ge=0.3, le=100.0, description='Q factor of the equalizer channel cell.')
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
"""API endpoints for controlling various Voicemeeter components."""
|
||||
|
||||
from . import bus, strip
|
||||
from . import bus, command, strip
|
||||
|
||||
__all__ = ['bus', 'strip']
|
||||
__all__ = ['bus', 'command', 'strip']
|
||||
|
||||
5
src/vmr_http/web/command/__init__.py
Normal file
5
src/vmr_http/web/command/__init__.py
Normal file
@@ -0,0 +1,5 @@
|
||||
"""module for command-related endpoints."""
|
||||
|
||||
from .command import router
|
||||
|
||||
__all__ = ['router']
|
||||
56
src/vmr_http/web/command/command.py
Normal file
56
src/vmr_http/web/command/command.py
Normal file
@@ -0,0 +1,56 @@
|
||||
"""module for command related endpoints."""
|
||||
|
||||
from fastapi import APIRouter, Depends
|
||||
|
||||
from vmr_http.dependencies import get_voicemeeter_client
|
||||
|
||||
router = APIRouter(tags=['command'])
|
||||
|
||||
|
||||
###
|
||||
# Although these endpoints are technically modifying the state of the Voicemeeter application,
|
||||
# they are commands that trigger an action rather than resource updates.
|
||||
# Therefore, they are implemented as POST.
|
||||
###
|
||||
|
||||
|
||||
@router.post('/show')
|
||||
def show_command(voicemeeter=Depends(get_voicemeeter_client)):
|
||||
"""Show the Voicemeeter application."""
|
||||
voicemeeter.command.show()
|
||||
return {'status': 'Voicemeeter shown'}
|
||||
|
||||
|
||||
@router.post('/hide')
|
||||
def hide_command(voicemeeter=Depends(get_voicemeeter_client)):
|
||||
"""Hide the Voicemeeter application."""
|
||||
voicemeeter.command.hide()
|
||||
return {'status': 'Voicemeeter hidden'}
|
||||
|
||||
|
||||
@router.post('/shutdown')
|
||||
def shutdown_command(voicemeeter=Depends(get_voicemeeter_client)):
|
||||
"""Shutdown the Voicemeeter application."""
|
||||
voicemeeter.command.shutdown()
|
||||
return {'status': 'Voicemeeter shutdown'}
|
||||
|
||||
|
||||
@router.post('/restart')
|
||||
def restart_command(voicemeeter=Depends(get_voicemeeter_client)):
|
||||
"""Restart the Voicemeeter engine."""
|
||||
voicemeeter.command.restart()
|
||||
return {'status': 'Voicemeeter restarted'}
|
||||
|
||||
|
||||
@router.post('/lock')
|
||||
def lock_command(voicemeeter=Depends(get_voicemeeter_client)):
|
||||
"""Lock the Voicemeeter application."""
|
||||
voicemeeter.command.lock = True
|
||||
return {'status': 'Voicemeeter locked'}
|
||||
|
||||
|
||||
@router.post('/unlock')
|
||||
def unlock_command(voicemeeter=Depends(get_voicemeeter_client)):
|
||||
"""Unlock the Voicemeeter application."""
|
||||
voicemeeter.command.lock = False
|
||||
return {'status': 'Voicemeeter unlocked'}
|
||||
@@ -77,7 +77,7 @@ def create_router(eq_kind: str) -> APIRouter:
|
||||
@router.patch('')
|
||||
@router.put('')
|
||||
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
|
||||
updated = {}
|
||||
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')
|
||||
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}
|
||||
|
||||
@router.get('/ab')
|
||||
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 router
|
||||
|
||||
@@ -9,19 +9,19 @@ router = APIRouter()
|
||||
|
||||
@router.patch('')
|
||||
@router.put('')
|
||||
def update_strip_comp_params(
|
||||
def update_strip_gainlayer_params(
|
||||
index: int,
|
||||
gainlayer_index: int,
|
||||
level: float = Body(..., ge=-60.0, le=12.0, embed=True),
|
||||
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.gain = level
|
||||
return {'gain_layer': {'level': gainlayer.gain}}
|
||||
return {'gainlayer': {'level': gainlayer.gain}}
|
||||
|
||||
|
||||
@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."""
|
||||
return {'gain_layer': {'level': voicemeeter.strip[index].gainlayer[gainlayer_index].gain}}
|
||||
return {'gainlayer': {'level': voicemeeter.strip[index].gainlayer[gainlayer_index].gain}}
|
||||
|
||||
Reference in New Issue
Block a user