From a2e71413384b9d6c74244ad59d34ebf9fc1751c2 Mon Sep 17 00:00:00 2001 From: AskaEth Date: Sun, 26 Jul 2026 18:41:35 +0800 Subject: [PATCH] feat: #2 G-force circle dashboard + .tsr export/import - g_force dashboard: acceleration vector on 2G ring, lat/long G readout - .tsr files export/import via API and UI - Composite dashboard reverted (G-force is standalone) --- dashboards/g_force/index.html | 90 ++++++++++++++++++++++++++++++++ dashboards/g_force/manifest.json | 14 +++++ server/api.py | 20 +++++++ 3 files changed, 124 insertions(+) create mode 100644 dashboards/g_force/index.html create mode 100644 dashboards/g_force/manifest.json diff --git a/dashboards/g_force/index.html b/dashboards/g_force/index.html new file mode 100644 index 0000000..ef7d2e4 --- /dev/null +++ b/dashboards/g_force/index.html @@ -0,0 +1,90 @@ + + + + + +TurboSu - G力 + + + +
+ + + diff --git a/dashboards/g_force/manifest.json b/dashboards/g_force/manifest.json new file mode 100644 index 0000000..e0809c4 --- /dev/null +++ b/dashboards/g_force/manifest.json @@ -0,0 +1,14 @@ +{ + "id": "g_force", + "name": "G 力圆图", + "category": "physics", + "description": "加速度向量实时可视化,圆心偏移表示纵向/横向G力方向和大小", + "author": "Yei.J. (AskaEth)", + "version": "1.0.0", + "supported_games": "all", + "config": { + "icon": "🎯", + "aspect_ratio": "1:1", + "render_mode": "contain" + } +} diff --git a/server/api.py b/server/api.py index 9e59282..b9e2d2b 100644 --- a/server/api.py +++ b/server/api.py @@ -469,3 +469,23 @@ async def api_start_playback(data: dict): async def api_stop_playback(): _get_player().stop() return {"ok": True, "playing": False} + + +@router.get("/recording/{filename}/export") +async def api_export_recording(filename: str): + from fastapi.responses import FileResponse + from server.recorder import RECORDINGS_DIR + path = RECORDINGS_DIR / filename + if not path.exists(): + raise HTTPException(404, "Recording not found") + return FileResponse(path, media_type="application/octet-stream", filename=filename) + + +@router.post("/recording/import") +async def api_import_recording(file: UploadFile = File(...)): + from server.recorder import RECORDINGS_DIR + if not file.filename or not file.filename.endswith('.tsr'): + raise HTTPException(400, "Only .tsr files are accepted") + dest = RECORDINGS_DIR / file.filename + dest.write_bytes(await file.read()) + return {"ok": True}