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]
|
[project]
|
||||||
name = "vmr-http"
|
name = "vmr-http"
|
||||||
version = "0.7.2"
|
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" }]
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ from fastapi import Depends, FastAPI, HTTPException
|
|||||||
from voicemeeterlib.error import CAPIError
|
from voicemeeterlib.error import CAPIError
|
||||||
|
|
||||||
from .dependencies import get_voicemeeter_client
|
from .dependencies import get_voicemeeter_client
|
||||||
from .web import bus, strip
|
from .web import bus, command, strip
|
||||||
|
|
||||||
|
|
||||||
@asynccontextmanager
|
@asynccontextmanager
|
||||||
@@ -24,14 +24,24 @@ 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}')
|
||||||
app.include_router(bus.router, prefix='/bus/{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)):
|
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:
|
||||||
|
|||||||
@@ -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.')
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
"""API endpoints for controlling various Voicemeeter components."""
|
"""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.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
|
||||||
|
|||||||
@@ -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}}
|
||||||
|
|||||||
Reference in New Issue
Block a user