diff --git a/stacks/streaming/docker-compose.yml b/stacks/streaming/docker-compose.yml new file mode 100644 index 0000000..ac6cb95 --- /dev/null +++ b/stacks/streaming/docker-compose.yml @@ -0,0 +1,93 @@ +# streaming stack — Jellyfin and its satellites. +# +# Storage split is deliberate: SQLite config on the root SSD, all bulk data +# (metadata, trickplay, cache, transcodes) on /storage1. The root disk is only +# 194G and has filled twice; nothing here may grow unbounded on it. +# +# Trickplay gets an explicit sub-bind because Jellyfin 10.11 moved it to +# /config/data/trickplay and it is NOT relocatable from the UI. +# +# Transcodes are disk-backed, not tmpfs: jellyfin#16608 means Remux and +# DirectStream jobs finish before the segment cleaner's first check, orphaning +# segments. Plex already writes transcodes to virtiofs at a 48% transcode rate. +# +# Env convention: every service gets stack.env via env_file; var names there are +# exactly what the containers read. No ${VAR} interpolation, no Portainer UI +# env vars. + +services: + jellyfin: + container_name: jellyfin + image: lscr.io/linuxserver/jellyfin:latest + restart: unless-stopped + networks: [streaming, edge] + env_file: + - stack.env + environment: + - JELLYFIN_PublishedServerUrl=https://jellyfin.ginnoir.com + volumes: + - /etc/localtime:/etc/localtime:ro + - /config/jellyfin:/config + - /storage1/labdata/jellyfin/metadata:/config/metadata + - /storage1/labdata/jellyfin/cache:/config/cache + - /storage1/labdata/jellyfin/trickplay:/config/data/trickplay + - /storage1/labdata/jellyfin/transcodes:/transcode + - /storage1/Movies:/data/movies:ro + - /storage1/TV:/data/tv:ro + - /storage1/Anime:/data/anime:ro + ports: + - "8096:8096" + + jellystat-db: + container_name: jellystat-db + image: postgres:16-alpine + restart: unless-stopped + networks: [streaming] + env_file: + - stack.env + labels: + - "com.centurylabs.watchtower.enable=false" + volumes: + - /config/jellystat-db:/var/lib/postgresql/data + + jellystat: + container_name: jellystat + image: cyfershepard/jellystat:latest + restart: unless-stopped + networks: [streaming, edge] + depends_on: + - jellystat-db + env_file: + - stack.env + volumes: + - /config/jellystat:/app/backend/backup-data + ports: + - "3009:3000" + + wizarr: + container_name: wizarr + image: ghcr.io/wizarrrr/wizarr:latest + restart: unless-stopped + networks: [streaming, edge] + env_file: + - stack.env + volumes: + - /config/wizarr:/data/database + ports: + - "5690:5690" + + jellyplex-watched: + container_name: jellyplex-watched + image: luigi311/jellyplex-watched:latest + restart: unless-stopped + networks: [streaming, edge] + env_file: + - stack.env + +networks: + streaming: + name: streaming + driver: bridge + edge: + name: edge + external: true diff --git a/stacks/streaming/stack.env b/stacks/streaming/stack.env new file mode 100644 index 0000000..feb006c --- /dev/null +++ b/stacks/streaming/stack.env @@ -0,0 +1,31 @@ +# streaming stack config — injected into every service via env_file. +# Var names are exactly what the containers read; no ${VAR} interpolation, +# no Portainer UI env vars needed. + +# --- shared --- +TZ=America/Chicago +PUID=1000 +PGID=1000 + +# --- jellystat-db (postgres:16-alpine) --- +POSTGRES_DB=jfstat +POSTGRES_USER=jellystat +POSTGRES_PASSWORD=bf2d47d8e1a87baf2b4942704a5acfaf5c2aad336fdd480e + +# --- jellystat --- +POSTGRES_IP=jellystat-db +POSTGRES_PORT=5432 +JWT_SECRET=0dd9fcdb632277b76977dbada8226e547cc773e1deafc8d778d4038f8d59393b + +# --- jellyplex-watched --- +# Plex is host-native, not containerised, so it is reached on the LAN IP. +PLEX_URL=http://192.168.1.69:32400 +PLEX_TOKEN=hM9aycswHKSsUrxiHqwq +JELLYFIN_BASEURL=http://jellyfin:8096 +JELLYFIN_TOKEN= +SYNC_FROM_PLEX_TO_JELLYFIN=True +SYNC_FROM_JELLYFIN_TO_PLEX=True +# Start in dry-run. Task 16 flips this to False after the mapping is verified. +DRYRUN=True +SLEEP_DURATION=21600 +LOG_LEVEL=INFO