No description
  • Go 78.7%
  • Python 10.5%
  • Nix 6.9%
  • Shell 2.8%
  • Dockerfile 1.1%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-09-06 16:46:39 +01:00
.forgejo/workflows ci: publish container image to forgejo registry 2026-08-27 17:57:11 +01:00
cmd/plexdrome feat: add opensubsonic plex compatibility adapter 2026-08-27 16:07:10 +01:00
internal fix: coalesce media library scans 2026-08-28 15:34:25 +01:00
tools/synthseek-capture chore: isolate synthseek capture lab 2026-08-27 15:50:24 +01:00
.dockerignore feat: add opensubsonic plex compatibility adapter 2026-08-27 16:07:10 +01:00
.gitignore chore: isolate synthseek capture lab 2026-08-27 15:50:24 +01:00
Dockerfile ci: publish container image to forgejo registry 2026-08-27 17:57:11 +01:00
flake.lock feat: add opensubsonic plex compatibility adapter 2026-08-27 16:07:10 +01:00
flake.nix feat: add opensubsonic plex compatibility adapter 2026-08-27 16:07:10 +01:00
go.mod feat: add opensubsonic plex compatibility adapter 2026-08-27 16:07:10 +01:00
LICENSE docs: adopt EUPL-1.2 license 2026-09-06 16:46:39 +01:00
README.md docs: adopt EUPL-1.2 license 2026-09-06 16:46:39 +01:00

plexdrome

Copyright © 2026 Nimmo. Licensed under the European Union Public Licence (EUPL), version 1.2.

This licence applies to the original source code, documentation, and capture tooling in this repository. Third-party software, container base images, and Nixpkgs inputs remain under their respective upstream licences.

Minimal Plex compatibility layer for Synthseek, backed by an OpenSubsonic server. Lightweight Music Server (LMS) is the initial deployment target; the adapter boundary remains server-neutral for future backend changes.

Run

Plexdrome is configured entirely through environment variables. At minimum it needs a private Plex token and stable machine identifier, plus an OpenSubsonic endpoint and either an API key or user credentials:

export PLEXDROME_PLEX_TOKEN='…'
export PLEXDROME_MACHINE_ID='…'
export OPEN_SUBSONIC_URL='http://navidrome:4533'
export OPEN_SUBSONIC_API_KEY='…'
nix run .

It listens on :32400 by default. Set PLEXDROME_LISTEN_ADDR to override it. The supported Plex-facing contract is deliberately small: identity and library discovery, scan requests, track search, and playlist create/read/append/rename. /healthz checks process health; /readyz verifies OpenSubsonic connectivity.

Variable Purpose
PLEXDROME_PLEX_TOKEN Required shared token accepted from Synthseek.
PLEXDROME_MACHINE_ID Required stable identifier used in Synthseek playlist URIs.
OPEN_SUBSONIC_URL Required private URL for Navidrome, LMS, or another OpenSubsonic server.
OPEN_SUBSONIC_API_KEY Required LMS per-user API token (sent as OpenSubsonic apiKey).
OPEN_SUBSONIC_USERNAME, OPEN_SUBSONIC_PASSWORD Optional conventional/salted-token fallback for compatible backends.
PLEXDROME_SCAN_MODE auto (default) asks the backend to scan; noop acknowledges scans without a backend operation.

Logs contain only request method, path, status, latency, and backend operation outcome; query values and authentication material are never logged. A backend playlist marked readonly is rejected with 409, while an unsupported scan is an acknowledged no-op so completed imports are not retried indefinitely.

Deployment

Place Plexdrome and Synthseek on the same internal Docker network on Chaos and configure Synthseek with http://plexdrome:32400 plus the configured Plex token. Do not publish the port unless you need a short-lived diagnostic tunnel. Set OPEN_SUBSONIC_URL to Vega's private endpoint; no music mount is required. The image runs as a non-root user and only needs outbound access to that backend.

Use /healthz for container liveness (it never contacts the backend) and /readyz for readiness (it calls OpenSubsonic ping). A readiness failure usually means private-network reachability or OpenSubsonic credentials need attention. The intentionally unsupported Plex surface includes OAuth, plex.tv discovery, media streaming, and all unobserved routes.

Build the OCI image locally with nix build .#container; the result is a Docker image archive suitable for docker load.

Image distribution

Every push to main builds and publishes the image through Forgejo Actions:

docker pull git.nimmog.uk/nimmo/plexdrome:latest

The same build also receives sha-<full-commit-id>, which is immutable and appropriate when a deployment needs a precise rollback target. NixOS and ordinary Docker hosts consume these identical registry references; the Nix container archive is retained for offline/local use.

Capture tooling

The disposable Synthseek/Plex traffic-capture harness is isolated from the product under tools/synthseek-capture. It is kept for re-running contract discovery when Synthseek changes.

From the repository root:

nix run ./tools/synthseek-capture

See the tool's README for its lifecycle, security model, and capture workflow.