Add phone remote control: pair a phone with a 6-digit code or QR to drive a desktop instance's playback, queue, volume, sleep timer and service mode

This commit is contained in:
Jonathan Sykes
2026-09-18 20:19:00 +08:00
parent 524db986d2
commit b82f17cd46
9 changed files with 1300 additions and 4 deletions

View File

@@ -98,6 +98,27 @@ JSON shapes mirror the Tauri Rust bridge exactly — don't change one side alone
forever and Chrome killed the tab ("Target crashed" in Playwright, no JS
error). Never cap with a loop whose exit depends on a deferred removal.
## Phone remote (`server/remote.js`, `Remote` in app.js)
- Desktop tab playing to a TV = **host**; phone = **remote**. Both are browser
tabs of this app, so the server relays over `/ws/remote` (Bun `server.upgrade`
in the `Bun.serve` fetch wrapper, before Hono). Mockup:
`docs/mockups/mock-06-remote-control.html` (it assumed a LAN host + mDNS; the web
app can't do that, so it's a server relay + a 6-digit code instead).
- Host secret lives in the desktop's localStorage (`ytpRemoteHost`); room id =
hash(secret). Pairing (`POST /api/remote/pair`) is a one-time 6-digit code
(10 min) → phone gets `token = HMAC(secret, remoteId)` (`ytpRemotePair`).
**Nothing about phones is stored server-side**: tokens are re-checked against
the connected host's secret, so server restarts / desktop reloads keep phones
paired, and "Unpair all" (new secret) revokes every phone at once.
- The host pushes `state` (≤1/s, deduped) and `queue` (`{items, idx}` of the live
`queue`/`queueIndex`); commands are whitelisted server-side (`REMOTE_COMMANDS`)
and run by `runCommand()` on the host with the same functions the UI uses.
- `REMOTE_SAME_NETWORK=1` = pairing requires the phone and desktop to share a
public IP (first `X-Forwarded-For` hop). Off by default — verify that the
VPS→homelab Traefik chain forwards the real client IP before turning it on.
- QR: `GET /api/remote/qr/:code` (server-side SVG via `qrcode`) encodes
`<origin>/?pair=<code>`; the app consumes and strips `?pair=` at boot.
## Local dev
```bash