name: jellystack

networks:
  media_network:
    name: media_network
    driver: bridge
    attachable: true

services:
  # Gluetun - Manage VPN
  gluetun:
    image: qmcgaw/gluetun:latest
    container_name: gluetun
    hostname: gluetun
    cap_add:
      - NET_ADMIN
    restart: always
    secrets:
      - wireguard_private_key
    env_file: ./env/gluetun.env
    volumes:
      - wireguard:/gluetun
    networks:
      - media_network
    ports:
      - 8100:8000 # Remote Control VPN
      - 2648:2648/tcp # cross-seed
      - 8989:8989 # sonarr
      - 8081:8081 # medusa
      - 7878:7878 # radarr
      - 9696:9696 # prowlarr
      - 8686:8686 # lidarr
      - 6767:6767 # bazarr
      - 9080:9080/tcp # qBit
      - 8694:8694/tcp # qBit
      - 6881:6881/udp # qBit
      - 8080:8080 # SABnzbd
      - 5656:5656/tcp # kapowarr
      # - 5004:5004/tcp # cabernet
      # - 6077:6077/tcp # cabernet
      - 7474:7474 # autobrr
      - 8191:8191/tcp # flaresolverr
    devices:
      - /dev/net/tun:/dev/net/tun

  # Qbittorent - torrenting software
  qbittorrent:
    image: lscr.io/linuxserver/qbittorrent:latest
    container_name: qbittorrent
    network_mode: "service:gluetun"
    restart: always
    env_file: ./env/dnl.env
    volumes:
      - qbittorent:/config
      - torrents:/data/torrents
    healthcheck:
      test: curl -f http://localhost:9080 || exit 1
      interval: 10s
      timeout: 3s
      start_period: 60s
    depends_on:
      gluetun:
        condition: service_healthy
        restart: true

  # SABnzbd
  sabnzbd:
    image: lscr.io/linuxserver/sabnzbd:latest
    container_name: sabnzbd
    restart: always
    network_mode: "service:gluetun"
    depends_on:
      gluetun:
        condition: service_healthy
        restart: true
    volumes:
      - sabnzbd:/config
      - usenet:/downloads
      - media:/data
    env_file: ./env/dnl.env

  # Sonarr - Find shows automatically
  sonarr:
    image: lscr.io/linuxserver/sonarr:latest
    container_name: sonarr
    network_mode: "service:gluetun"
    restart: always
    env_file: ./env/arr.env
    volumes:
      - sonarr:/config
      - media:/data
      - tv-shows:/data/tv-shows
      - downloads:/downloads
    healthcheck:
      test: curl -f http://localhost:8989/ping || exit 1
      interval: 10s
      timeout: 3s
      start_period: 60s
    depends_on:
      gluetun:
        condition: service_healthy
        restart: true
      qbittorrent:
        condition: service_healthy
        restart: true

  # Radarr - Find movies automatically
  radarr:
    image: lscr.io/linuxserver/radarr:latest
    container_name: radarr
    network_mode: "service:gluetun"
    restart: always
    env_file: ./env/arr.env
    volumes:
      - radarr:/config
      - media:/data
      - movies:/data/movies
      - downloads:/downloads
    healthcheck:
      test: curl -f http://localhost:7878/ping || exit 1
      interval: 10s
      timeout: 3s
      start_period: 60s
    depends_on:
      gluetun:
        condition: service_healthy
        restart: true
      qbittorrent:
        condition: service_healthy
        restart: true

  # Prowlarr - Manages Sonarr, Radarr and download client
  prowlarr:
    image: lscr.io/linuxserver/prowlarr:latest
    container_name: prowlarr
    network_mode: "service:gluetun"
    restart: always
    env_file: ./env/arr.env
    volumes:
      - prowlarr:/config
    healthcheck:
      test: curl -f http://localhost:9696/ping || exit 1
      interval: 10s
      timeout: 3s
      start_period: 60s
    depends_on:
      gluetun:
        condition: service_healthy
        restart: true
      qbittorrent:
        condition: service_healthy
        restart: true
      sonarr:
        condition: service_healthy
        restart: true
      radarr:
        condition: service_healthy
        restart: true

  # Bazarr - Subtitles. Try to use SRT format if you can rather than PGS due to performance issues
  bazarr:
    container_name: bazarr
    image: lscr.io/linuxserver/bazarr:latest
    restart: always
    network_mode: "service:gluetun"
    env_file: ./env/arr.env
    volumes:
      - bazarr:/config
      - media:/data/media
    healthcheck:
      test: curl -f http://localhost:6767 || exit 1
      interval: 10s
      timeout: 3s
      start_period: 60s
    depends_on:
      gluetun:
        condition: service_healthy
        restart: true

  # Unpacker - Used to unzip zipped files
  unpackerr:
    image: golift/unpackerr:latest
    container_name: unpackerr
    restart: always
    env_file: ./env/arr.env
    networks:
      - media_network
    volumes:
      - unpackerr:/config
      - media:/data
      - downloads:/downloads
    depends_on:
      sonarr:
        condition: service_healthy
        restart: true
      radarr:
        condition: service_healthy
        restart: true

  # Jellyfin - Media server
  jellyfin:
    image: ghcr.io/linuxserver/jellyfin:latest
    container_name: jellyfin
    hostname: jellyfin
    restart: always
    privileged: true
    env_file: ./env/jfn.env
    volumes:
      - jellyfin:/config
      - cache:/cache
      - media:/media
    networks:
      - media_network
    ports:
      - 8096:8096
      - 8920:8920
    devices:
      - /dev/dri:/dev/dri # Required for jellyfin HW transcoding / QuickSynci
      - /dev/dma_heap:/dev/dma_heap
      - /dev/fb0:/dev/fb0
      - /dev/mali0:/dev/mali0
      - /dev/rga:/dev/rga
      - /dev/mpp_service:/dev/mpp_service
    healthcheck:
      test: curl -i http://localhost:8096/health || exit 1
      interval: 10s
      timeout: 3s
      start_period: 60s

# Seer - Allows users to request media on their own
  seerr:
    container_name: seerr
    image: ghcr.io/seerr-team/seerr:latest
    init: true
    restart: always
    environment:
      - LOG_LEVEL=debug
      - PORT=5055
    networks:
      - media_network
    ports:
      - 5055:5055
    volumes:
      - seerr:/app/config
      # - media:/data/media
    healthcheck:
      test: wget --no-verbose --tries=1 --spider http://localhost:5055/api/v1/status || exit 1
      start_period: 20s
      timeout: 3s
      interval: 15s
      retries: 3
    depends_on:
      jellyfin:
        condition: service_healthy
        restart: true

  # Wizarr - Create a share links that you can send to users to invite them to your media server
  wizarr:
    container_name: wizarr
    image: ghcr.io/wizarrrr/wizarr:latest
    restart: always
    volumes:
      - wizarr:/data/database
    networks:
      - media_network
    ports:
      - 5690:5690

  # Tdarr - Transcode videos from one format to another like x265 or H.265
  tdarr:
    container_name: tdarr
    image: ghcr.io/haveagitgat/tdarr:latest
    privileged: true
    restart: always
    environment:
      - PUID=1002
      - PGID=1002
      - TZ=Europe/Paris
      - UMASK_SET=002
      - nodeName=ServerNode
      - serverIP=0.0.0.0
      - serverPort=8266
      - webUIPort=8265
      - internalNode=true
      - inContainer=true
      - ffmpegVersion=6
    volumes:
      - tdarr:/app/configs
      - tdarr_server:/app/server
      - tdarr_logs:/app/logs
      - media:/data/media
      - transcode_cache:/temp
    networks:
      - media_network
    ports:
      - 8265:8265 # webUI port
      - 8266:8266 # server port
    devices:
      - /dev/dri:/dev/dri # Required for HW transcoding /share QuickSyncinc
      - /dev/dma_heap:/dev/dma_heap
      - /dev/mali0:/dev/mali0
      - /dev/rga:/dev/rga
      - /dev/mpp_service:/dev/mpp_service

  tdarr-node:
    container_name: tdarr-node
    image: ghcr.io/haveagitgat/tdarr_node:latest
    restart: always
    network_mode: service:tdarr
    environment:
      - TZ=Europe/Paris
      - PUID=1002
      - PGID=1002
      - UMASK_SET=002
      - nodeName=MainNode
      - serverIP=0.0.0.0
      - serverPort=8266
      - inContainer=true
    volumes:
      - tdarr:/app/configs
      - tdarr_logs:/app/logs
      - media:/data/media
      - transcode_cache:/temp

  music-grabber:
    image: g33kphr33k/musicgrabber:latest
    container_name: music-grabber
    restart: always
    shm_size: '2gb'
    ports:
      - "38274:8080"
    volumes:
      - music:/music
      - music-grabber:/data
    environment:
      - MUSIC_DIR=/music
      - DB_PATH=/data/music_grabber.db
      # Optional: serve behind a reverse-proxy subpath (proxy must strip the prefix)
      # - ROOT_PATH=/musicgrabber
      - ENABLE_MUSICBRAINZ=true
      - DEFAULT_CONVERT_TO_FLAC=true
      # Optional: Run as specific user (like *arr stack) for correct file permissions
      - PUID=1000
      - PGID=1000
      # Optional: Custom bind address/port (useful for IPv6 or non-standard setups)
      - LISTEN_ADDR=0.0.0.0
      - LISTEN_PORT=8080
      # Optional: Navidrome auto-rescan
      - NAVIDROME_URL=http://navidrome:4533
      - NAVIDROME_USER=admin
      - NAVIDROME_PASS=sandstorm-outcast-treat
      # Optional: Jellyfin auto-rescan
      - JELLYFIN_URL=https://jellyfin.delmar.bzh
      - JELLYFIN_API_KEY=65e51490397749d6945c4561a53e012a
      # AcoustID API key for audio fingerprinting (https://acoustid.org/api-key)
      - ACOUSTID_API_KEY=4b5DGYGrih
      # Optional: Notifications
      - NOTIFY_ON=playlists,bulk,errors
      # - TELEGRAM_WEBHOOK_URL=https://api.telegram.org/bot{token}/sendMessage?chat_id={chat_id}
      # - WEBHOOK_URL=https://your-webhook-endpoint.com/hook
      - APPRISE_URL=gotify://gotify.delmar.bzh/A-4Fe2UBRbV5J_J
      - SMTP_HOST=pro1.mail.ovh.net
      - SMTP_PORT=587
      - SMTP_USER=admin@delmar.bzh
      - SMTP_PASS=sxS4GA8rBfmFkCFL
      - SMTP_TO=jme69@delmar.bzh
      # Optional: Use a Monochrome mirror instead of the default instance
      # - MONOCHROME_API_URL=https://api.monochrome.tf

  navidrome:
    image: deluan/navidrome:latest
    container_name: navidrome
    user: 1000:1000
    ports:
      - "4533:4533"
    restart: always
    environment:
      # Optional: put your config options customization here. Examples:
      - ND_LOGLEVEL=debug
    volumes:
      - navidrome:/data:rw
      - music:/music:ro

volumes:
  wireguard:
    driver: local
    driver_opts:
      type: "none"
      o: "bind"
      device: "./config/wireguard"
  qbittorent:
    driver: local
    driver_opts:
      type: "none"
      o: "bind"
      device: "./config/qbittorent"
  sabnzbd:
    driver: local
    driver_opts:
      type: "none"
      o: "bind"
      device: "./config/sabnzbd"
  sabnzbd_backups:
    driver: local
    driver_opts:
      type: "none"
      o: "bind"
      device: "./config/sabnzbd/backups"
  nzb_files:
    driver: local
    driver_opts:
      type: "none"
      o: "bind"
      device: "./config/sabnzbd/Downloads/nzb_files"
  sonarr:
    driver: local
    driver_opts:
      type: "none"
      o: "bind"
      device: "./config/sonarr"
  radarr:
    driver: local
    driver_opts:
      type: "none"
      o: "bind"
      device: "./config/radarr"
  prowlarr:
    driver: local
    driver_opts:
      type: "none"
      o: "bind"
      device: "./config/prowlarr"
  bazarr:
    driver: local
    driver_opts:
      type: "none"
      o: "bind"
      device: "./config/bazarr"
  unpackerr:
    driver: local
    driver_opts:
      type: "none"
      o: "bind"
      device: "./config/unpackerr"
  jellyfin:
    driver: local
    driver_opts:
      type: "none"
      o: "bind"
      device: "./config/jellyfin"
  navidrome:
    driver: local
    driver_opts:
      type: "none"
      o: "bind"
      device: "./config/navidrome"
  music-grabber:
    driver: local
    driver_opts:
      type: "none"
      o: "bind"
      device: "./config/music-grabber"
  tdarr:
    driver: local
    driver_opts:
      type: "none"
      o: "bind"
      device: "./config/tdarr"
  tdarr_server:
    driver: local
    driver_opts:
      type: "none"
      o: "bind"
      device: "./config/tdarr_server"
  tdarr_logs:
    driver: local
    driver_opts:
      type: "none"
      o: "bind"
      device: "./config/tdarr_logs"
  transcode_cache:
    driver: local
    driver_opts:
      type: "none"
      o: "bind"
      device: "./config/tdarr_cache"
  cache:
    driver: local
    driver_opts:
      type: "none"
      o: "bind"
      device: "./config/cache"
  seerr:
    driver: local
    driver_opts:
      type: "none"
      o: "bind"
      device: "./config/seerr"
  wizarr:
    driver: local
    driver_opts:
      type: "none"
      o: "bind"
      device: "./config/wizarr/data/database"
  media:
    driver: local
    driver_opts:
      type: "nfs"
      o: "addr=192.168.1.15,nolock,soft,rw"
      device: "/srv/nfs4/media"
  tv-shows:
    driver: local
    driver_opts:
      type: "nfs"
      o: "addr=192.168.1.15,nolock,soft,rw"
      device: "/srv/nfs4/media/tv-shows"
  movies:
    driver: local
    driver_opts:
      type: "nfs"
      o: "addr=192.168.1.15,nolock,soft,rw"
      device: "/srv/nfs4/media/movies"
  music:
    driver: local
    driver_opts:
      type: "nfs"
      o: "addr=192.168.1.15,nolock,soft,rw"
      device: "/srv/nfs4/media/music"
  downloads:
    driver: local
    driver_opts:
      type: "nfs"
      o: "addr=192.168.1.15,nolock,soft,rw"
      device: "/srv/nfs4/media/downloads"
  torrents:
    driver: local
    driver_opts:
      type: "nfs"
      o: "addr=192.168.1.15,nolock,soft,rw"
      device: "/srv/nfs4/downloads/torrents"
  usenet:
    driver: local
    driver_opts:
      type: "nfs"
      o: "addr=192.168.1.15,nolock,soft,rw"
      device: "/srv/nfs4/downloads/usenet"

secrets:
  wireguard_private_key:
    file: ./secrets/wireguard_private_key.secret
  bittorrent-user:
    file: ./secrets/bittorrent-user.secret
  bittorrent-password:
    file: ./secrets/bittorrent-password.secret
  radarr-api:
    file: ./secrets/radarr-api.secret
  sonarr-api:
    file: ./secrets/sonarr-api.secret
