cliamp is out of scope, which unblocks the music extraction

the two websocket providers exist for one thing: running the cliamp TUI on the
server and piping its terminal and audio to the browser, via a pulseaudio null
sink tapped by parec. a second, separate playback path — and the least important
part of music. wanted eventually, not tonight.

that removes the hardest of the three homeless parts entirely. no plugin can own
a socket yet, and now none needs to: both sockets are already inert, and
cliamp-ws.ts, pulse-audio.ts, asoundrc, the relay and the two providers all stay
exactly where they are. if the relay's import is the only thing keeping
api/music/router.ts alive, that stays too — a small documented seam.

what music actually is: the /music screen, the library, and the phone and tablet
apps that stream from it. that is what has to work.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-15 01:19:18 +00:00
co-authored by Claude Opus 5
parent 8545b427dd
commit b5db3c47e1
+24 -13
View File
@@ -125,12 +125,23 @@ avoid is not a wrong call; it is a tree left half-moved with a question attached
### What has no home yet ### What has no home yet
1. **Two websocket providers.** `cliamp` and `cliamp-audio`, upgraded at `/api/cliamp/ws` and 1. ~~**Two websocket providers.**~~ **OUT OF SCOPE — do not touch cliamp.**
`/api/cliamp/audio/ws` in `server.tsx` — the routes are **still live** while their handlers are
commented out, so they currently upgrade into nothing. **No plugin can own a socket**: `cliamp` and `cliamp-audio` exist for one thing: running the `cliamp` TUI player on the server and
`server.reload({ routes })` is proven and never called. Worse, the relay itself piping its terminal and its audio (a PulseAudio null sink tapped by `parec`) to the browser. It is a
(`src/servers/api/cliamp/relay.ts`, 110 lines) is *platform* code that imports `getMusicServerWsUrl` second, separate playback path and the owner's word is that it is the least important part of music —
from the music router — so deleting that router breaks the platform. fun, wanted eventually, not tonight.
**This is the whole reason the websocket gap does not block this extraction.** Both sockets are already
inert (routes upgrade into commented-out handlers). Leave `sidecar/music/cliamp-ws.ts`,
`sidecar/music/pulse-audio.ts`, `sidecar/music/asoundrc`, `src/servers/api/cliamp/relay.ts` and the two
providers in `server.tsx` exactly where they are, untouched. If the relay's import of
`getMusicServerWsUrl` is the only thing keeping `api/music/router.ts` alive, leave that file too and
say so — a small documented seam is fine.
What music actually is: the `/music` screen, the library, and the phone and tablet apps that stream
from it. That is what has to work.
2. **A global UI overlay.** `MusicPlayerHost` is rendered by `DashboardLayout` on **every route**, not 2. **A global UI overlay.** `MusicPlayerHost` is rendered by `DashboardLayout` on **every route**, not
inside a panel, and gates itself on `can('music')`. A plugin contributes panels and a layout; there is inside a panel, and gates itself on `can('music')`. A plugin contributes panels and a layout; there is
no "render this everywhere" slot, and inventing one is a platform change. no "render this everywhere" slot, and inventing one is a platform change.
@@ -139,9 +150,10 @@ avoid is not a wrong call; it is a tree left half-moved with a question attached
### What else differs ### What else differs
- **External binaries**: `cliamp`, `ffmpeg`, `ffprobe`, `parec`, `pulseaudio`, `pactl`. `pulse-audio.ts` - **External binaries**: with cliamp out of scope, what the plugin still needs is `ffmpeg` and `ffprobe`,
starts a daemon and loads a null sink at boot. A manifest has no way to declare a host dependency. for tag reading, cover compression and poster frames. A manifest has no way to declare a host
- **A non-TS asset**: `sidecar/music/asoundrc`, loaded via `import.meta.dir`. It must travel. dependency; note it and move on. (`cliamp`, `parec`, `pulseaudio`, `pactl` and `asoundrc` stay behind
with cliamp.)
- **Range requests**: `stream-audio.ts` does 206 / `Content-Range` / 416 and a custom `X-Audio-Duration`; - **Range requests**: `stream-audio.ts` does 206 / `Content-Range` / 416 and a custom `X-Audio-Duration`;
the proxy runs at `timeoutSeconds: 1800` for reindexes. Verify `Range` survives the hop. the proxy runs at `timeoutSeconds: 1800` for reindexes. Verify `Range` survives the hop.
- **Cross-capability**: `MusicBrowser` calls `/file-browser/ls`, not the music sidecar. - **Cross-capability**: `MusicBrowser` calls `/file-browser/ls`, not the music sidecar.
@@ -178,16 +190,15 @@ in the platform is worth far more than a perfect design that did not land.
| Part | Close the gap | Leave it behind | | Part | Close the gap | Leave it behind |
| --- | --- | --- | | --- | --- | --- |
| websockets | wire `server.reload({ routes })` — already proven, never called — so a manifest can declare ws providers | leave `cliamp`/`cliamp-audio` and the relay in the platform, note it in the manifest | | ~~websockets~~ | — | **out of scope, see above. Do not spend a minute on cliamp.** |
| global overlay | add one slot the shell renders from installed plugins | leave `MusicPlayerHost` in `DashboardLayout`, gated on the permission as it already is | | global overlay | add one slot the shell renders from installed plugins | leave `MusicPlayerHost` in `DashboardLayout`, gated on the permission as it already is |
| widget | let a plugin contribute `widgetRegistryMetas` | leave `widgets/MusicPlayer` where it is | | widget | let a plugin contribute `widgetRegistryMetas` | leave `widgets/MusicPlayer` where it is |
Whatever you pick, the plugin must **install, enable, disable and uninstall cleanly** at the end. A piece Whatever you pick, the plugin must **install, enable, disable and uninstall cleanly** at the end. A piece
left in the platform is a documented seam; a piece left dangling is a bug. left in the platform is a documented seam; a piece left dangling is a bug.
`assertCapabilityTotality` is worth fixing on the way past if you touch the websocket path — the cliamp `assertCapabilityTotality` is **not** part of this. It is worth fixing eventually and the cliamp routes
routes are the live example of the drift it cannot currently see (routes upgrading into commented-out are the live example of the drift it cannot see, but both are someone else's evening.
handlers). Not required.
**Do not** invent music's per-user visibility model during the move. Extract with the semantics it has, or **Do not** invent music's per-user visibility model during the move. Extract with the semantics it has, or
the two changes tangle and a bug in either is a bug in both. the two changes tangle and a bug in either is a bug in both.