jellyfin, extracted from the platform as a plugin
Eighth plugin out, and the second resurrection: like soulseek, hono.ts carried the router import and its mount commented out since 2026-08-13, with the permission reduced to api: [], so the server booted clean while every panel request 404'd. jellyfin_servers was also absent from the drizzle barrel, so bun db:push would have dropped it. Easier than soulseek in one specific way: mountPrefix derives /jellyfin from the appName, which is exactly what the router already hardcoded, so no frontend call site needed repointing. Soulseek needed 47 because its appName and its old prefix differed. The frontend also already routed through one helper, so there were five call sites rather than forty-seven. Self-contained, unlike transmission and soulseek: jellyfin_servers is a registry this plugin owns outright — label, URL, encrypted token, one active — because more than one Jellyfin is a thing someone has, and more than one Transmission is not. Carries its own .prettierignore for the vendored hls.mjs, rather than leaving a stale rule behind in the platform naming a path that no longer exists.
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
# Jellyfin — the extraction record
|
||||
|
||||
Extracted from the platform on **2026-08-19**, the eighth plugin out, immediately after soulseek.
|
||||
`plugins/EXTRACTING-A-PLUGIN.md` is the runbook.
|
||||
|
||||
## Also a resurrection
|
||||
|
||||
Like soulseek, and for the same reason: `hono.ts` carried both the router import and its
|
||||
`PROTECTED_MOUNTS` entry commented out (`// plugin — switched off 2026-08-13`), and the permission had
|
||||
been reduced to `api: []`. So `assertPermissionTotality` was satisfied, the server booted clean, and
|
||||
every request from the panels 404'd. It had been dead for six days.
|
||||
|
||||
The same data hazard applied: `schema.ts` had `export * from './jellyfin/schema'` commented out, so
|
||||
`jellyfin_servers` was absent from the drizzle barrel and `bun db:push` would have dropped it.
|
||||
|
||||
## What moved
|
||||
|
||||
| Was | Is now |
|
||||
| --------------------------------------------------------- | --------------- |
|
||||
| `src/servers/sidecar/jellyfin/*` (5 files) | `sidecar/*` |
|
||||
| `src/servers/api/jellyfin/router.ts` | `api/router.ts` |
|
||||
| `src/databases/officer_db/src/jellyfin/*` (3 files) | `db/*` |
|
||||
| `src/workspaces/officerdev/src/apps/Jellyfin/*` (20 files, incl. `vendor/`) | `web/*` |
|
||||
| `src/apps/officer-web/Screens/Dashboard/Jellyfin/*` | `web/layout.ts` |
|
||||
|
||||
## Easier than soulseek, in one specific way
|
||||
|
||||
The mount prefix is unchanged. `mountPrefix` derives `/jellyfin` from the appName, which is what the
|
||||
router was already hardcoding — so **no frontend call site had to be repointed**. Soulseek needed 47,
|
||||
because its appName (`soulseek`) and its old prefix (`slskd`) differed.
|
||||
|
||||
The frontend also already routed everything through one helper (`useJellyfinData.ts`), so there were
|
||||
five call sites in total rather than forty-seven spread across every panel.
|
||||
|
||||
## It owns its data, unlike transmission and soulseek
|
||||
|
||||
`jellyfin_servers` is a **registry** — label, URL, encrypted token, one active — and it moved into this
|
||||
plugin whole. That is the right shape here for the same reason `service_connections` is the right shape
|
||||
there: more than one Jellyfin is a thing someone actually has, and more than one Transmission is not.
|
||||
|
||||
So this plugin is self-contained. No core table, no platform union to extend.
|
||||
|
||||
## Fixtures: fixed properly this time
|
||||
|
||||
`jellyfin` was the canonical app-store test fixture, and extracting it broke **18 tests**. That is the
|
||||
fourth extraction in a row to break the same files — photos and transmission on 2026-08-18, slskd
|
||||
earlier on 2026-08-19, jellyfin an hour later.
|
||||
|
||||
`installer.test.ts` now builds **literal** fixtures and asks the catalogue nothing:
|
||||
|
||||
```ts
|
||||
const fullInstall: CatalogueEntry = { id: 'test-full', members: 'accounts', modes: [...], ... };
|
||||
```
|
||||
|
||||
Those tests pin `planSteps` and `runInstall` — installer *logic*. A service leaving for `plugins/` says
|
||||
nothing about whether the installer still plans the right steps, so it should never have been able to
|
||||
break them. `catalogue.test.ts` remains the place where real entries are asserted well-formed.
|
||||
|
||||
`members.test.ts`, `catalogue.test.ts` and `preflight.test.ts` were re-anchored to `memos`, which has
|
||||
jellyfin's exact shape (`members: 'accounts'`, `modes: ['existing', 'provisioned']`).
|
||||
|
||||
## Carried its own ignore rule
|
||||
|
||||
`.prettierignore` in the platform named `src/workspaces/officerdev/src/apps/Jellyfin/vendor/hls.mjs`.
|
||||
That path no longer exists, so the rule moved into this repo's own `.prettierignore` rather than being
|
||||
left behind as a stale line matching nothing.
|
||||
|
||||
## Not carried over
|
||||
|
||||
`composeTemplate: 'jellyfin'` and `modes: ['existing', 'provisioned']` died with the catalogue entry.
|
||||
Like every plugin so far, this is **point-at-your-own-server only** until plugin Docker provisioning
|
||||
exists.
|
||||
Reference in New Issue
Block a user