Add GoXLR utility plugin

This commit is contained in:
2026-06-09 22:06:31 +02:00
parent bb5571784a
commit 58fe9548a6
4 changed files with 593 additions and 0 deletions
+120
View File
@@ -11,6 +11,7 @@ from backend.services.actions import ActionEngine
from backend.services.pico import parse_pico_line
from backend.services.plugins import PluginContext, PluginManager
from plugins.clipboard_tools import ClipboardToolsPlugin
from plugins.goxlr import GoXLRPlugin
from plugins.http_requests import HTTPRequestsPlugin
from plugins.wled import WLEDPlugin
@@ -371,6 +372,125 @@ def test_wled_mega_update_combines_effect_color_range_and_extra_json(tmp_path: P
]
def test_goxlr_plugin_resolves_first_device_and_sets_volume(tmp_path: Path):
received = []
class Handler(BaseHTTPRequestHandler):
def do_POST(self):
length = int(self.headers.get("Content-Length", "0"))
payload = json.loads(self.rfile.read(length).decode("utf-8"))
received.append(payload)
self.send_response(200)
self.end_headers()
if payload == "GetStatus":
self.wfile.write(b'{"Status":{"mixers":{"SERIAL123":{"hardware":{"device_type":"Mini"}}}}}')
return
self.wfile.write(b'"Ok"')
def log_message(self, *_args):
return None
server = ThreadingHTTPServer(("127.0.0.1", 0), Handler)
thread = threading.Thread(target=server.serve_forever, daemon=True)
thread.start()
try:
db = Database(tmp_path / "streamdeck.sqlite")
GoXLRPlugin().execute_action(
PluginContext(DummyApp(db)),
"set_volume",
{
"base_url": f"http://127.0.0.1:{server.server_port}",
"channel": "Chat",
"volume": 180,
"timeout": 3,
},
None,
)
finally:
server.shutdown()
thread.join(timeout=5)
assert received == [
"GetStatus",
{"Command": ["SERIAL123", {"SetVolume": ["Chat", 180]}]},
]
def test_goxlr_plugin_load_profile_uses_explicit_serial(tmp_path: Path):
received = []
class Handler(BaseHTTPRequestHandler):
def do_POST(self):
length = int(self.headers.get("Content-Length", "0"))
received.append(json.loads(self.rfile.read(length).decode("utf-8")))
self.send_response(200)
self.end_headers()
self.wfile.write(b'"Ok"')
def log_message(self, *_args):
return None
server = ThreadingHTTPServer(("127.0.0.1", 0), Handler)
thread = threading.Thread(target=server.serve_forever, daemon=True)
thread.start()
try:
db = Database(tmp_path / "streamdeck.sqlite")
GoXLRPlugin().execute_action(
PluginContext(DummyApp(db)),
"load_profile",
{
"base_url": f"127.0.0.1:{server.server_port}",
"device_serial": "MIXER-42",
"profile_name": "Headphones",
"persist": True,
"timeout": 3,
},
None,
)
finally:
server.shutdown()
thread.join(timeout=5)
assert received == [
{"Command": ["MIXER-42", {"LoadProfile": ["Headphones", True]}]},
]
def test_goxlr_plugin_raw_request_surfaces_api_error(tmp_path: Path):
class Handler(BaseHTTPRequestHandler):
def do_POST(self):
self.send_response(200)
self.end_headers()
self.wfile.write(b'{"Error":"No such device"}')
def log_message(self, *_args):
return None
server = ThreadingHTTPServer(("127.0.0.1", 0), Handler)
thread = threading.Thread(target=server.serve_forever, daemon=True)
thread.start()
try:
db = Database(tmp_path / "streamdeck.sqlite")
try:
GoXLRPlugin().execute_action(
PluginContext(DummyApp(db)),
"send_raw_request",
{
"base_url": f"http://127.0.0.1:{server.server_port}",
"payload_json": '{"Command":["SERIAL123",{"SetFXEnabled":true}]}',
"timeout": 3,
},
None,
)
except RuntimeError as exc:
assert "No such device" in str(exc)
else:
raise AssertionError("Expected GoXLR API error to raise.")
finally:
server.shutdown()
thread.join(timeout=5)
def test_clipboard_plugin_copy_renders_event_tokens(tmp_path: Path):
db = Database(tmp_path / "streamdeck.sqlite")
plugin = ClipboardToolsPlugin()