diff --git a/src/web/server.py b/src/web/server.py index 762e791..db91b23 100644 --- a/src/web/server.py +++ b/src/web/server.py @@ -25,9 +25,8 @@ from typing import Any, Optional import uvicorn from fastapi import FastAPI, HTTPException, WebSocket, WebSocketDisconnect, Request -from fastapi.responses import HTMLResponse, JSONResponse +from fastapi.responses import HTMLResponse, JSONResponse, RedirectResponse from fastapi.staticfiles import StaticFiles -from fastapi.templating import Jinja2Templates from ..dsp.nam_host import NAMHost from ..dsp.ir_loader import IRLoader @@ -51,38 +50,14 @@ logger = logging.getLogger(__name__) # ── Cache buster version (bumped on deploy) ───────────────────────── # Increment this when template/static changes need to bypass browser cache -TEMPLATE_VERSION = "8" - # ── Defaults ───────────────────────────────────────────────────────────────── DEFAULT_HOST = "0.0.0.0" DEFAULT_PORT = 8080 -TEMPLATES_DIR = Path(__file__).resolve().parent / "templates" STATIC_DIR = Path(__file__).resolve().parent / "static" -# React UI dist — built frontend served at /ui/ -# Can be overridden via UI_DIST_DIR env var -_ui_dist_env = os.environ.get("UI_DIST_DIR") -if _ui_dist_env: - UI_DIST_DIR = Path(_ui_dist_env).resolve() -else: - # Priority: src/web/ui-dist is the canonical UI - _candidates = [ - Path(__file__).resolve().parent / "ui-dist", - Path(__file__).resolve().parent.parent.parent / "frontend-react" / "dist", - ] - UI_DIST_DIR = next((d for d in _candidates if d.is_dir()), None) - -# ── Channel support ────────────────────────────────────────────────────────────── - -VALID_CHANNELS: frozenset = frozenset({"guitar", "bass", "keys", "vocals", "backing_tracks"}) - -def _resolve_channel(channel: str = "guitar") -> str: - """Normalize a channel string; fall back to 'guitar' for invalid values.""" - if isinstance(channel, str) and channel.lower() in VALID_CHANNELS: - return channel.lower() - return "guitar" - +# v2 UI dist (the only UI we serve) +V2_DIST_DIR = Path(__file__).resolve().parent / "ui-v2-dist" # ── Channel mode persistence ──────────────────────────────────────────────── @@ -315,10 +290,6 @@ class WebServer: def _build_app(self) -> FastAPI: - templates = Jinja2Templates(directory=str(TEMPLATES_DIR)) - # Inject version into all templates (cache buster for CSS/JS) - templates.env.globals["version"] = TEMPLATE_VERSION - @asynccontextmanager async def lifespan(app: FastAPI): logger.info("Web server lifespan started") @@ -330,63 +301,34 @@ class WebServer: # Mount static files app.mount("/static", StaticFiles(directory=str(STATIC_DIR)), name="static") - # Mount React UI (if dist exists) - if UI_DIST_DIR and UI_DIST_DIR.is_dir(): - logger.info("Mounting React UI from %s at /ui", UI_DIST_DIR) - app.mount("/ui", StaticFiles(directory=str(UI_DIST_DIR), html=True), name="ui") - - # Mount V2 React UI (if dist exists) - V2_DIST_DIR = Path(__file__).resolve().parent / "ui-v2-dist" - if V2_DIST_DIR.is_dir(): - logger.info("Mounting V2 React UI from %s at /v2", V2_DIST_DIR) - app.mount("/v2", StaticFiles(directory=str(V2_DIST_DIR), html=True), name="ui-v2") - # ── HTML pages ────────────────────────────────────────────── @app.get("/", response_class=HTMLResponse) async def root(request: Request): - """Serve the v2 UI (or React SPA / legacy dashboard as fallback).""" - # Prefer the v2 UI if available - v2_dir = Path(__file__).resolve().parent / "ui-v2-dist" - if v2_dir.is_dir(): - v2_index = v2_dir / "index.html" - if v2_index.exists(): - content = v2_index.read_text() - return HTMLResponse(content) - # Fallback: React build - if UI_DIST_DIR and UI_DIST_DIR.is_dir(): - index_html = UI_DIST_DIR / "index.html" - if index_html.exists(): - content = index_html.read_text() - return HTMLResponse(content) - # Fallback: legacy dashboard (guitar channel state) - state = self._gather_state(channel="guitar") - ctx = {"request": request} - ctx.update(state) - return templates.TemplateResponse(request, "dashboard.html", ctx) + """Serve the v2 UI.""" + v2_index = V2_DIST_DIR / "index.html" + if v2_index.exists(): + content = v2_index.read_text() + return HTMLResponse(content) + return HTMLResponse("
UI build not found.
") - @app.get("/presets", response_class=HTMLResponse) - async def preset_manager(request: Request): - """Preset manager page — browse banks, load/save/edit.""" - return templates.TemplateResponse(request, "presets.html", {"request": request}) + # Legacy routes — redirect to the v2 SPA - @app.get("/models", response_class=HTMLResponse) - async def model_manager(request: Request): - """NAM model manager page.""" - return templates.TemplateResponse(request, "models.html", {"request": request}) + @app.get("/presets") + async def presets_redirect(): + return RedirectResponse(url="/") - @app.get("/irs", response_class=HTMLResponse) - async def ir_manager(request: Request): - """IR manager page.""" - return templates.TemplateResponse(request, "irs.html", {"request": request}) + @app.get("/models") + async def models_redirect(): + return RedirectResponse(url="/") - @app.get("/settings", response_class=HTMLResponse) - async def settings_page(request: Request): - """Settings page.""" - state = self._gather_state(channel="guitar") - ctx = {"request": request} - ctx.update(state) - return templates.TemplateResponse(request, "settings.html", ctx) + @app.get("/irs") + async def irs_redirect(): + return RedirectResponse(url="/") + + @app.get("/settings") + async def settings_redirect(): + return RedirectResponse(url="/") # ── REST API ──────────────────────────────────────────────── diff --git a/src/web/templates/base.html b/src/web/templates/base.html deleted file mode 100644 index 8910856..0000000 --- a/src/web/templates/base.html +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - -Connect to pedal to see active FX chain.
-Loading IR files...
-Upload .wav IR files to the pedal's IR directory.
- - -Search and download impulse responses directly from the Tone3000 community.
-Loading models...
-Upload .nam model files to the pedal's model directory.
- - -Search and download NAM models directly from the Tone3000 community.
-Loading presets...
-pedal.localhttp://pedal.local:8080—