/*
* SysDeck - Jellyfin Panel (v0.0.35)
* Author: Jeremy Anderson (https://dcos.net)
*
* v0.0.35 directive: "next we will integrate a jellyfin management
* module where it starts, stops, and loads the admin panel in the
* module." Jellyfin ships a single systemd unit (jellyfin.service)
* and serves a full admin web UI on http://127.0.0.1:8096. The
* bridge starts/stops/restarts the service via systemctl; the panel
* iframes the running admin UI — same pattern as the v0.0.34 Glances
* integration.
*
* The panel surfaces:
* - Service summary card: status badge, version, port, uptime
* - Service controls: Start / Stop / Restart (polkit prompts)
* - Admin UI iframe: loads http://127.0.0.1:8096 when running
* - Library list: best-effort GET /Library/VirtualFolders
* - Install hint when jellyfin is not installed
*
* Jellyfin is GPL-2.0 licensed by the Jellyfin contributors. The
* bridge helper invokes it as a separate process via subprocess —
* the suite (MIT) and Jellyfin (GPL-2.0) remain independent
* programs. No Jellyfin code is bundled.
*
* Bridge surface (see shared/bridge.js → bridge.jellyfin):
* summary() → {available, status, version, port, url, ...}
* status() → service state dict
* start() → {action, rc, success, output, stderr}
* stop() → same shape
* restart() → same shape
* webStatus() → {running, url, port, ...}
* libraries() → {libraries: [...], count: N}
*/
export async function mount(panel, { bridge, EventBus }) {
panel.innerHTML = renderSkeleton();
const [summary, webStatus, libraries] = await Promise.all([
safe(bridge.jellyfin.summary(), {}),
safe(bridge.jellyfin.webStatus(), {}),
safe(bridge.jellyfin.libraries(), { libraries: [], count: 0 }),
]);
const running = webStatus?.running === true || summary?.status === 'running';
const available = webStatus?.available !== false && summary?.available !== false;
const webUrl = webStatus?.url || summary?.url || 'http://127.0.0.1:8096';
panel.innerHTML = `
Self-hosted media streaming · movies · TV · music
· GPL-2.0 · Jellyfin contributors
${available
? (running
? ` · running`
: ` · stopped`)
: ` · not installed`}
Jellyfin Media Server
${escapeHtml(summary?.reason || 'Jellyfin is not installed.')}
${summary?.install ? `${escapeHtml(summary.install)}
Jellyfin is GPL-2.0 licensed by the Jellyfin contributors — https://jellyfin.org/
${escapeHtml(summary?.service || 'jellyfin.service')}| Status | ${statusBadge(summary?.status)} |
|---|---|
| ActiveState | ${escapeHtml(summary?.active || '—')} |
| SubState | ${escapeHtml(summary?.sub || '—')} |
| Uptime | ${running ? escapeHtml(uptime) : '—'} |
| Version | ${escapeHtml(summary?.version || '—')} |
| Port | ${summary?.port || 8096} |
| URL | ${escapeHtml(webUrl)} |
The bridge runs systemctl start/stop/restart jellyfin.service
via the cockpit superuser channel (polkit org.sysdeck.jellyfin.modify).
${escapeHtml(libraries.error)}
| Name | Type | Paths |
|---|---|---|
| ${escapeHtml(lib.name)} | ${escapeHtml(lib.type || 'mixed')} | ${escapeHtml((lib.paths || []).join(' · ') || '—')} |
| No libraries configured. Open the admin panel above to add media folders. | ||