import type { PluginManifest } from '@@/plugins/manifest'; /** * Soulseek — search and download from the Soulseek network, through your own slskd daemon. * * ── What this plugin is, and what it is not ── * * It does not install or supervise slskd, and it shares no files itself. You point it at a daemon and it * speaks slskd's API on your behalf, holding the API key server-side so no device ever carries it. * * ── Where the connection lives ── * * In `service_connections`, a CORE table — the same one Transmission uses, keyed `(user_id, service)` * and already encrypted at rest. That table was designed for exactly this shape and says so: services * the owner has exactly ONE of. Nobody has two Soulseek daemons, so there is no label, no `is_active` * and no switcher. * * It does mean this plugin depends on a core facility it does not own — `'slskd'` is a member of the * platform's `ServiceName` union, which a plugin cannot extend. Recorded in PLUGIN.md rather than * hidden, because it is the one part of this extraction that is not self-contained. * * ── What it DOES own ── * * Three tables, in `db/schema.ts`: favourites, and the two halves of the cached browse tree. Those are * Officer's own features — slskd has no concept of either — and they are served by the sidecar's * `/_officer/*` routes rather than proxied upstream. * * ── No `osDependencies` ── * * Nothing shells out. The sidecar speaks slskd's HTTP API over `fetch`. */ export const manifest: PluginManifest = { publisher: 'officerdev', version: '2026.08.27.01', platform: '>=1.0.0', label: 'Soulseek', summary: 'Search and download from the Soulseek network, via your own slskd daemon', /** a daemon you run, for finding music. */ tags: ['Homelab', 'Fun'], icon: 'Music2', color: '#22c55e', permissions: [ { key: 'soulseek', label: 'Soulseek', description: 'Search and download from the Soulseek network', }, ], };