the player moves to the plugin, and src/ has no music code left
officerdev/src/MusicPlayer/ → plugins/music/web/. Engine, state, bar, favourites, lyrics toggle and the library vocabulary — ten files. The barrel stops exporting a player it no longer has, and DashboardLayout stops rendering one. The reasoning that kept it was removed rather than refuted. It stayed because the dashboard widget imported useMusicPlayer from officerdev and the platform cannot import from a plugin, so the state had to stay whatever was decided about the UI. The owner moved the widget into the plugin in the previous commit, and the constraint went with it: the whole remaining dependency became one line, DashboardLayout.tsx:66. MusicPlayerHost is mounted inside the MusicDetail panel. That reads odd until you notice it already returned null on /music — the mini bar is the transport there, and the host existed purely to own the GaplessEngine. In the panel it does exactly that, and the bar code stays intact for whenever there is a slot. [phase 2] Leaving /music unmounts the host and playback stops. Deferred on the owner's call; the bar was "navigating away must not break the application", and that holds: seekPlayer is optional-chained so a call with no host registered is a no-op, registerPlayerSeek clears only its own registration, the host's cleanup destroys the engine and nulls its ref, and the queue is global state so returning to /music remounts and reloads. Solving it properly needs either a shell slot a plugin can contribute to — which reopens "there is no way to export a component" — or the engine hoisted to module scope, which keeps the rule and loses only the off-route controls. Also: the parked widget now imports the player as a sibling rather than through officerdev, and shared.ts stopped being a re-export shim now that the real file is in the plugin. Verified: tsgo clean, 797 tests / 787 pass / same 7. Server restarts, mounts /example /music /offscale, / and /music both 200, and the player is in the built bundle (music.volume, music:lyrics, now-playing?device=web all present — GaplessEngine is a class name and the production build is minified, so grepping for it proves nothing). Not verified by me: what it looks like in a browser. That needs your eyes.
This commit is contained in:
+12
-18
@@ -8,36 +8,30 @@ import type { PluginManifest } from '@@/plugins/manifest';
|
||||
// He was right — one of the three "seams" turned out to be dead code holding the door open.
|
||||
//
|
||||
// api/router.ts the sidecar proxy, built here — thin, and it must never grow music knowledge
|
||||
// cliamp/ the second playback path, parked
|
||||
// widgets/ the dashboard widget, parked
|
||||
// sidecar/ the whole /api/music contract: indexing, streaming, per-user state
|
||||
// db/ music_favorites, _playlists, _playlist_items, _now_playing
|
||||
// web/ the library panels; the shell renders the Workspace
|
||||
//
|
||||
// ── What stayed in the platform, and why ── (one item, down from three)
|
||||
// ── What stayed in the platform, and why ── (nothing. All three moved here.)
|
||||
//
|
||||
// 1. ~~cliamp~~ — MOVED HERE, all of it, into `./cliamp/`. The sidecar halves, the relay, the file
|
||||
// browser's panel and its `Play` action. `src/servers/sidecar/music/`, `src/servers/api/cliamp/` and
|
||||
// `src/servers/api/music/` no longer exist, and `server.tsx` has no cliamp anything. It is PARKED, not
|
||||
// working: bringing it back needs a plugin to own a websocket, which is a platform gap.
|
||||
//
|
||||
// 2. The dashboard widget (`src/workspaces/widgets/MusicPlayer/`). Plugins cannot contribute widgets and
|
||||
// the mechanism was not worth inventing for one.
|
||||
// 2. ~~The dashboard widget~~ — MOVED HERE, to `./widgets/`, and unregistered from WidgetRegistry.
|
||||
// Parked: plugins cannot contribute widgets and that mechanism is not built.
|
||||
//
|
||||
// 3. The global player overlay (`officerdev/src/MusicPlayer/`, mounted by `DashboardLayout`). This was
|
||||
// the one open judgement call and it is decided: THE PLAYER STAYS IN THE PLATFORM. Two reasons, and
|
||||
// the second is the one that settles it.
|
||||
// 3. ~~The global player overlay~~ — MOVED HERE, to `./web/`. It stayed while the widget pinned
|
||||
// `useMusicPlayer` in `officerdev`; once the widget left, the only platform dependency was one line
|
||||
// in DashboardLayout. `MusicPlayerHost` now mounts inside the MusicDetail panel, where it owns the
|
||||
// audio engine and renders nothing — which is what it already did on /music.
|
||||
//
|
||||
// - Moving it needs a shell slot that renders a plugin-provided component on every route. That is
|
||||
// exactly the escape hatch this system deleted on purpose — "there is no way to export a component"
|
||||
// is what makes "every plugin route is a Workspace" a property of the shape rather than a rule
|
||||
// someone has to remember. Reopening it for one plugin is a bad trade.
|
||||
// - It would not even work. The widget above imports `useMusicPlayer` and `PlayerTrack` from
|
||||
// `officerdev`, and the platform cannot import from a plugin — so the player STATE stays whatever
|
||||
// is decided about the UI. Splitting the engine from the state it drives would leave the same seam
|
||||
// in a worse place, and two copies of that state would mean two engines.
|
||||
//
|
||||
// The overlay gates on `can('music')`, which resolves against the permission below — registered at
|
||||
// install and gone at uninstall. So the seam switches itself off with the plugin, with no code path
|
||||
// that knows why.
|
||||
// `[phase 2]` Leaving /music stops playback. Giving audio a life outside the route needs a shell slot
|
||||
// a plugin can contribute to, or the engine hoisted to module scope. Deferred deliberately; nothing
|
||||
// breaks meanwhile.
|
||||
//
|
||||
// ── Host dependencies ──
|
||||
//
|
||||
|
||||
Reference in New Issue
Block a user