Files
Tha.Les cde1739c64 feat: mobile web UI + network access toggle (#231)
* feat: mobile web UI + network access toggle

Add a phone-optimized web UI and let other devices on the LAN reach a
StemDeck instance, so the app is usable end-to-end from a phone.

Mobile UI (static/mobile/, vanilla JS to match the stack):
- Library, Mixer, and Extract screens wired to the real API. Library lists
  /api/jobs with swipe-to-delete; Mixer reuses the desktop Web Audio engine
  (audioEngine.js, now accepting a shared gesture-unlocked AudioContext for
  iOS) with faders/mute/solo/seek, real analysis, and mixdown/MP4 export;
  Extract submits URL/upload and follows SSE progress.
- Served by a user-agent check on "/" (phones get mobile, everyone else the
  DAW; ?ui= overrides). Shared DOM-free helpers in static/js/shared/jobs.js.
- Ported from the design prototype kept under design/mobile/.

Network access (app/core/settings.py, app/main.py):
- Backend always binds 0.0.0.0; a runtime gate decides whether non-host
  requests are served (default off, opt-in). The host machine (loopback or
  its own LAN IP) is always allowed, so it can't be locked out.
- Settings dialog reorganized into General / Advanced tabs: General holds
  max track length (<=20 min) and MP4 video quality; Advanced holds the
  network toggle (with the LAN address list) and out-of-sync resync.
- Runtime settings (allow_network, max_duration_sec, video_max_height) are
  persisted and read live via GET/POST /api/settings, no restart needed.

Performance: stem MP3s are transcoded once and cached on disk (was re-encoded
on every request), so loading a track on mobile is fast and re-loads instant.

Desktop: start_backend binds 0.0.0.0; adds a local_ip command.

* chore: address code-quality bot — document suppressed excepts; untrack design refs

- _local_ips() and settings _load()/_save(): replace bare `except: pass` with
  an explanatory comment + logging.debug/warning(exc_info=True); behavior
  unchanged (still best-effort).
- _load(): handle the no-file case explicitly (FileNotFoundError) vs. logging
  genuinely corrupt files.
- Untrack design/ (the imported Claude Design prototype) and gitignore it — it's
  a local spec reference, not shipped code, and the static analyzer's "no-effect
  expression" flags on its <x-dc> template bindings were false positives.

---------

Co-authored-by: Thales <>
2026-06-27 19:04:28 +01:00

27 lines
1003 B
HTML

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, viewport-fit=cover, maximum-scale=1"
/>
<meta name="theme-color" content="#0b0b0d" />
<title>StemDeck</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap"
rel="stylesheet"
/>
<link rel="stylesheet" href="/mobile/styles.css" />
</head>
<body>
<!-- The whole UI is rendered by app.js into #app. This is a static
visual shell on mock data (issue: mobile redesign). Screens and
interactions are real; data is not yet wired to the API. -->
<div id="app" class="m-app"></div>
<script type="module" src="/mobile/app.js"></script>
</body>
</html>