Files
mesh-catalog/modules/plex/module.json
T
jschoubben 4213fa7a2d plex: provide its API to the mesh as plex-api
kometa, tautulli and ombi reached plex by a hand-typed address - a public
name, a HAL network gateway - which the mesh cannot keep true. Plex now
provides plex-api at mesh scope and serves the server's port and scheme, so
the mesh tells each consumer where it is.

The port is written out rather than inferred: plex listens on five ports
(the server and four discovery ones), and the mesh only infers a provision's
port when a module listens on exactly one.

No grants and no provisioner: the credential is the server owner's
X-Plex-Token, which plex.tv issues and the mesh cannot mint. The operator
accepts it as the pair credential for each consumer (ADR 0092); each
consumer's step checks it against the server and writes nothing it refuses.
2026-09-30 12:55:24 +02:00

218 lines
4.5 KiB
JSON

{
"module": "plex",
"version": "1",
"provides": [
{
"name": "plex-api",
"scope": "mesh"
}
],
"serves": {
"plex-api": {
"scheme": "http",
"port": 32400
}
},
"capabilities": [
"container-runtime"
],
"emits": [
"playback.started",
"playback.stopped",
"item.added"
],
"consumes": [
"*.download.completed"
],
"own-secrets": {
"broker": "/var/lib/mesh/plex/broker"
},
"listens": [
{
"name": "stream",
"port": 32400,
"protocol": "tcp",
"from": "mesh",
"why": "the server itself: the apps, streaming and the web player, direct and through its route"
},
{
"name": "gdm-1",
"port": 32410,
"protocol": "udp",
"from": "mesh",
"why": "G'Day Mate discovery: players on the same network find the server without signing in"
},
{
"name": "gdm-2",
"port": 32412,
"protocol": "udp",
"from": "mesh",
"why": "G'Day Mate discovery"
},
{
"name": "gdm-3",
"port": 32413,
"protocol": "udp",
"from": "mesh",
"why": "G'Day Mate discovery"
},
{
"name": "gdm-4",
"port": 32414,
"protocol": "udp",
"from": "mesh",
"why": "G'Day Mate discovery"
}
],
"accesses": [
{
"path": "/services/media/movies",
"mode": "read"
},
{
"path": "/services/media/series",
"mode": "read"
},
{
"path": "/services/media/anime",
"mode": "read"
},
{
"path": "/services/media/music",
"mode": "read"
},
{
"path": "/services/media/audiobooks",
"mode": "read"
},
{
"path": "/services/media/sport-games",
"mode": "read"
},
{
"path": "/services/media/live-shows",
"mode": "read"
},
{
"path": "/services/media/formula-1",
"mode": "read"
}
],
"resources": [
{
"id": "mesh-state",
"type": "directory",
"path": "/var/lib/mesh/plex",
"mode": "0700"
},
{
"id": "state",
"type": "directory",
"mode": "0700",
"place": "."
},
{
"id": "config",
"type": "directory",
"mode": "0755",
"owner": "1000:1000"
},
{
"id": "data",
"type": "directory",
"mode": "0755",
"owner": "1000:1000"
},
{
"id": "transcode",
"type": "directory",
"mode": "0755",
"owner": "1000:1000"
},
{
"id": "server-env",
"type": "file",
"path": "${dir:state}/server.env",
"mode": "0600",
"content": "ADVERTISE_IP=https://${bound:route:name}/\n"
},
{
"id": "server",
"type": "container",
"name": "plex",
"image": "plexinc/pms-docker@sha256:e0ab27395614a8e1a4fdf84c6bc60ac664915cfdde70c52d030c7728a1c48e14",
"network": "host",
"env": {
"PLEX_UID": "1000",
"PLEX_GID": "1000",
"TZ": "Etc/UTC"
},
"env-file": [
"${dir:state}/server.env"
],
"volumes": [
"${dir:config}:/config",
"${dir:data}:/data",
"${dir:transcode}:/transcode",
"/services/media/movies:/movies:ro",
"/services/media/series:/series:ro",
"/services/media/anime:/anime:ro",
"/services/media/music:/music:ro",
"/services/media/audiobooks:/audiobooks:ro",
"/services/media/sport-games:/sport-games:ro",
"/services/media/live-shows:/live-shows:ro",
"/services/media/formula-1:/formula-1:ro"
]
},
{
"id": "runtime",
"type": "container",
"name": "mesh-plex",
"network": "host",
"volumes": [
"/var/lib/mesh/plex/broker:/run/secrets/broker:ro",
"${dir:config}:/var/lib/plex/config:ro"
],
"env": {
"MESH_BROKER_FILE": "/run/secrets/broker",
"MESH_PLEX_URL": "http://127.0.0.1:${port:32400}",
"MESH_PLEX_DATA_DIR": "/var/lib/plex"
},
"artifact": "runtime"
}
],
"requires": [
"route"
],
"contributes": {
"route": {
"label": "plex",
"endpoint": "stream"
}
},
"binds": {
"route": "${dir:state}/route.json"
},
"build": {
"on": [
{
"arg": "BUILD_BASE",
"module": "mesh-tools",
"artifact": "build"
},
{
"arg": "RUNTIME_BASE",
"module": "mesh-tools",
"artifact": "runtime"
}
],
"artifacts": [
{
"name": "runtime",
"kind": "image",
"from": "Dockerfile"
}
]
}
}