Puckanet *arr Guide Crest

Puckanet Media Automation Blueprint

Complete *arr Stack, Usenet vs BitTorrent, Tdarr Flows & Homelab Hardening
🚀 Production Guide ⚡ Usenet + VPN Torrenting 🛡️ NFSv4.1 Hardened 🔒 Tailnet-Only Mesh 🍿 SeerrNG Integrated

⚡ The 30-Second Mental Model

Automating a modern home media library means retiring manual browser searches, raw torrent clients, and chaotic folders in favor of a decoupled, containerized pipeline. Instead of managing individual files, you define quality rules and let software automatically discover, verify, download, rename, transcode, and catalog movies and shows.

1. Discovery / Request
SeerrNG
Friends & family request media via unified web UI (Authentik OIDC)
▼
2. Orchestration (*Arrs)
Radarr (Movies), Sonarr (TV) & Kapowarr (Comics)
Monitors releases, scores qualities & dispatches grabs
3. Indexer Proxy
Prowlarr
Unified search across Usenet indexers & torrent trackers
▼
4A. Usenet Pipeline (Speed)
SABnzbd (Direct SSL Port 563)
Usenet Provider + Indexer (100+ MB/s)
4B. BitTorrent Pipeline (Coverage)
Gluetun + qBittorrent
Strict WireGuard VPN network binding & killswitch
▼
5. Central Storage & Hardlink Ingestion
NAS Share (NFSv4.1)
Atomic rename with [tmdbid-#####] folders & zero-copy hardlinks
▼
6. Transcode & Cleanup
Tdarr Cluster
Hardware NVENC H.265 compression & bad subtitle stream stripping
7. Metadata & Presentation
TinyMediaManager + Jellyfin / BookOrbit
Surgical NFO/artwork scraping & client streaming
💡

Why this architecture works

Every tier is completely replaceable. If a torrent tracker goes down, Usenet takes over. If a download fails, Sonarr/Radarr tries another release. If your media server changes from Plex to Jellyfin, all your local NFO metadata and organized folders stay completely intact.

📦 Component Directory & Source Repositories

Every tool in our production stack is open-source or community-driven. Bookmark these upstream repositories for documentation, updates, and issue trackers:

SeerrNG Frontend
Unified discovery and media request portal. Fully integrated with Authentik OIDC (Tier 1 Seamless Auto-Login) and syncing requests directly with Jellyfin, Radarr, and Sonarr.
Radarr Movies
Movie automation, monitoring upcoming theater/digital release dates, quality profiles, and atomic disk organizing.
GitHub: Radarr/Radarr ↗
Sonarr Television
Smart TV series & anime tracker. Automates season downloads, monitored episode states, and multi-episode renaming.
GitHub: Sonarr/Sonarr ↗
Prowlarr Indexers
Indexer proxy and tracker manager. Add your Usenet indexers and BitTorrent trackers in one place; Prowlarr syncs them to all *arrs.
GitHub: Prowlarr/Prowlarr ↗
Gluetun VPN Gateway
Ultra-lightweight WireGuard and OpenVPN client in Docker. Acts as the network namespace sandbox for torrent clients.
GitHub: qdm12/gluetun ↗
qBittorrent Torrents
The undisputed standard BitTorrent client for headless homelab deployment, featuring fast WebUI and full API control.
GitHub: qbittorrent/qBittorrent ↗
SABnzbd Usenet
High-speed binary Usenet newsreader with automated par2 repair, multi-part unrar, and SSL direct transfer.
GitHub: sabnzbd/sabnzbd ↗
TinyMediaManager Metadata
Comprehensive media scraper creating restoration-grade local `.nfo` metadata, poster sets, cast thumbs, and clearart.
Project: tinymediamanager.org ↗
Tdarr Transcoding
Distributed multi-node audio/video transcoding automation engine utilizing hardware NVENC/QSV pipelines.
GitHub: HaveAGitGat/Tdarr ↗
TRaSH Guides Bible
The definitive community guides for folder structures, hardlinking, quality profiles, and custom format regex scoring.
Docs: trash-guides.info ↗
BookOrbit Books & Audio
Primary modern eBook and audiobook platform featuring automated Book Dock ingestion (/data/book-dock), rich metadata enrichment, and KOReader/Kobo sync.
Portal: books.puckaway.org ↗

🏗️ Hardware Architecture & The Two-Box Model

1. Central NAS vs. Compute Separation

In a mature homelab, never run heavy transcode/download containers directly on your storage array. Storage controllers (Synology, TrueNAS, Unraid) should focus on ZFS parity, snapshots, and disk integrity.

  • Storage Box (NAS): Hosts the raw disks and exposes NFSv4.1 exports.
  • Appliance Server (Compute Host): Dedicated mini-PC or rack server running Proxmox / Ubuntu Docker. Armed with an Intel QuickSync CPU or Nvidia GPU for hardware transcoding.

2. The Usenet vs. BitTorrent Hybrid Engine

Why pay for Usenet if torrents are free? Because they serve two completely different purposes in a resilient library:

Feature Usenet (SABnzbd) BitTorrent (qBittorrent)
Speed Maxes out 1 Gbps (110+ MB/s) Variable based on seeders
Privacy Direct SSL/TLS (No VPN needed) Requires Strict VPN Tunnel
Seeding None. Download & done. Required for healthy ratios
Cost ~$102 / year Free (plus VPN cost)
Best For New releases & popular TV Old, niche, or rare media
💰

Usenet Cost Baseline

To get blazing fast, zero-VPN Usenet downloads, you need two subscriptions: a Provider (gives you raw backbone NNTP access) and an Indexer (the search engine that provides NZB files to Prowlarr).

  • Usenet Provider: UsenetExpress — $90 / year (SSL port 563, high retention, unlimited bandwidth).
  • NZB Indexer: NZBGeek — $12 / year (Fast VIP API access directly queried by Prowlarr).

🍿 The Front Door: SeerrNG Media Request Portal

The biggest mistake homelabbers make is giving friends and family access to the Radarr and Sonarr admin panels. It takes one accidental click on "Delete all files from disk" to ruin your weekend.

SeerrNG (the next-generation, actively maintained unified evolution of Overseerr & Jellyseerr, deployed via ghcr.io/snapetech/seerrng:v3.21.4) serves as our unified media request, discovery, and user onboarding front door.

Key Advantages of SeerrNG

  • Authentik OIDC (Tier 1 Seamless Auto-Login): Fully integrated with our central Authentik identity provider. Users authenticate once via SSO and enjoy automatic passwordless sign-in with granular RBAC permissions.
  • Direct Bi-Directional Media Sync: Syncs directly with Jellyfin via administrative API tokens, reflecting existing media libraries, live watch history, and real-time availability badges in a slick Netflix-grade interface.
  • Automated *Arr Dispatch: Instantly and deterministically routes approved movie requests to Radarr and TV shows to Sonarr, mapping root folders, tags, and custom quality profiles automatically.
  • Granular Quotas & Tiered Approvals: Auto-approves requests for immediate family (Tier 1/2) while queuing casual requests for manual review with strict weekly volume limits.
  • Smart 4K vs. 1080p Routing: Prevents casual remote users from requesting uncompressed 4K HDR Remuxes, transparently mapping default requests to efficient 1080p profiles while reserving 4K profiles for local theater clients.

Connecting SeerrNG to the Pipeline

Configuration in SeerrNG's administrative console takes under five minutes:

  1. Authentik OIDC Authentication: Enable OpenID Connect, point to https://authentik.puckaway.org/application/o/seerrng/, and configure claims mapping for seamless Tier 1 auto-login.
  2. Radarr Integration: Enter internal container endpoint (http://radarr:7878), API key, default root directory (/data/media/movies), and primary quality profile (HD-1080p).
  3. Sonarr Integration: Connect TV backend (http://sonarr:8989), map series root folder (/data/media/shows), and configure dedicated anime series types and tags.
  4. Jellyfin Media Server Sync: Connect Jellyfin with an API token to continuously synchronize library inventory and user watch states in real time.

🔒 Homelab Perimeter Security: The "One Door In" Rule

A core principle of the Puckanet architecture is extreme defense-in-depth. The *arr ecosystem and download clients are administrative backends—they must never be directly exposed to the open internet.

🟢 The Public Ingress Layer (Only 2 Services)

The only endpoints that should have public DNS and reverse proxy routes are hardened streaming and request portals:

  • Jellyfin: media.puckaway.org (SSL + rate limiting + hardware transcode)
  • SeerrNG: requests.puckaway.org (SSL + Authentik OIDC Tier 1 Auto-Login)

🔴 Tailnet-Only Backend Layer (Zero Public Exposure)

All backend administration, download queues, and indexers stay strictly isolated on your private Tailscale mesh network:

  • Radarr / Sonarr / Prowlarr: Accessible only via Tailnet IPs / MagicDNS (e.g. sonarr.tailnet.internal)
  • qBittorrent / SABnzbd / Tdarr: Completely unreachable from WAN—immune to port scans and brute force attacks.
🛡️

Why Tailnet Isolation is Essential

By keeping download clients and orchestration dashboards restricted to Tailscale, you eliminate the need for router port forwarding, remove credential-stuffing bot attacks from your server logs, and can safely access all your homelab tools from your phone or laptop anywhere in the world.

📚 Expanding Beyond Video: Books, Audiobooks, Comics & Music

Once your video pipeline is running smoothly, the exact same architectural patterns easily extend to books, audiobooks, graphic novels, and music:

BookOrbit Primary Books & Audio
Primary modern eBook and audiobook platform serving books.puckaway.org with automated Book Dock staging, rich metadata enrichment, and KOReader / Kobo sync.
Kapowarr Comics (*arr)
Comic book and graphic novel acquisition automation engine (*arr style) connecting to Prowlarr/GetComics and feeding completed CBZ/CBR files.
GitHub: Casvt/Kapowarr ↗
Lidarr + LYD Music Automation
Music acquisition engine pairing MusicBrainz and AcoustID fingerprinting with automated Usenet/torrent downloads and weighted YouTube Music fallback scraping.

📥 The Book Dock Automated Ingestion Pipeline

Instead of fragile legacy book downloaders, we employ an automated drop-and-ingest workflow centered around the Book Dock staging volume at /data/book-dock:

  • Automated Drop-In Staging: Newly acquired EPUB, PDF, CBZ, and M4B/MP3 audiobooks drop into /data/book-dock via automated fetchers, browser uploads, or sync hooks.
  • Continuous Ingestion Watcher: BookOrbit's background daemon monitors the staging directory with filesystem events, automatically deduplicating incoming files against existing library checksums.
  • Zero-Copy Library Sorting: Files are parsed, normalized, and atomically organized into canonical library structures (/data/media/books/{Author}/{Series}/{Title}) without corrupting live reading locks.

📖 Metadata Enrichment & Native E-Reader Sync

BookOrbit provides a unified, distraction-free reading experience across desktop, mobile, and dedicated e-ink hardware:

  • Multi-Source Metadata Enrichment: Queries OpenLibrary, Google Books, and Hardcover simultaneously to fetch high-res cover art, ISBNs, publisher blurbs, and verified series reading orders.
  • Native KOReader Sync Server: Hosts a native KOReader sync API endpoint. Any e-reader running KOReader (e.g. Kobo, Android, Tolino) synchronizes reading positions, highlights, and annotations across devices in real time.
  • Kobo Store Emulation: Exposes native Kobo Sync protocol so Kobo devices (Clara, Libra, Sage) connect directly over Wi-Fi, pulling new book additions and syncing progress without tethering via USB.

🛠️ Infrastructure & Maintenance Companions

These high-utility sidecars keep your library clean, automate subtitle synchronization, and handle user onboarding without manual intervention:

Bazarr Subtitles
Companion to Sonarr/Radarr that automatically monitors, downloads, and syncs missing subtitles in preferred languages using OpenSubtitles, Whisper STT, and UTF-8 SRT normalization.
GitHub: Bazarr ↗
Cleanuparr Auto-Maintenance
Automated garbage collection for Sonarr/Radarr. Purges stalled/dead downloads, cleans stuck queue items, and deletes orphaned torrent payloads.
GitHub: Cleanuparr ↗
Wizarr Onboarding
Automated user invitation management system for Jellyfin with customized welcome screens, automatic library rules, and auto-invites to SeerrNG.
GitHub: Wizarr ↗

🏷️ Metadata Mastery & Whipping Files into Shape

Nothing is more frustrating than a media server mistaking the 2022 movie Avatar for the 2005 anime series, or showing generic placeholder posters. The fix is strict naming hygiene backed by TinyMediaManager (TMM).

1. The Golden Rule: Explicit ID Tagging

Always configure Radarr and Sonarr to include database IDs directly in the folder name. Media scrapers will never misidentify a title when the ID is embedded:

Radarr Movie Folder Naming Pattern
{Movie CleanTitle} ({Release Year}) [tmdbid-{TmdbId}]/{Movie CleanTitle} ({Release Year}) [tmdbid-{TmdbId}] - [{Quality Full}]
Sonarr TV Series Folder Naming Pattern
{Series CleanTitle} ({Release Year}) [tvdbid-{TvdbId}]/Season {season:00}/{Series CleanTitle} - S{season:00}E{episode:00} - {Episode CleanTitle} [{Quality Full}]

2. TinyMediaManager REST API Automation

Rather than relying on real-time external API calls during playback, we run TinyMediaManager in the background. When Sonarr or Radarr imports a file, a custom event script triggers TMM's REST API:

  • Generates standardized local movie.nfo and tvshow.nfo metadata files.
  • Downloads high-res posters, fanart, clearart logos, and actor thumbnails locally.
  • Enables Jellyfin/Plex to operate in "Local NFO First" mode—making library scans instant and immune to internet outages.
Sonarr/Radarr Custom Connect Script (tmm_update.sh)
#!/bin/bash
# Trigger targeted TMM scan upon download completion
API_KEY="your-tmm-api-key"
TMM_HOST="10.0.0.100"
TMM_PORT="7778"

if [ "$sonarr_eventtype" = "Download" ] || [ "$radarr_eventtype" = "Download" ]; then
    TARGET_PATH="${sonarr_series_path:-$radarr_movie_path}"
    PAYLOAD='[{"action":"update","scope":{"name":"path","args":["'$TARGET_PATH'"]}},{"action":"scrape","scope":{"name":"new"}}]'
    curl -s -X POST -H "api-key: $API_KEY" -H "Content-Type: application/json" -d "$PAYLOAD" "http://$TMM_HOST:$TMM_PORT/api/movies"
fi

3. Advanced Media Mismatch Identification & Correction

Even with strict ID tagging, chaotic real-world releases—mangled ID3 tags, generic filenames, bootleg audio rips, and broadcast airing inconsistencies—can defeat standard scrapers. We deploy three battle-tested heuristic and algorithmic defenses:

🎵 AcoustID & MusicBrainz Fingerprinting

Music files downloaded from varied sources often have missing ID3 tags, wrong artist labels, or generic filenames like track01.mp3, causing Lidarr and Beets to make catastrophic false matches.

The Solution: We compute AcoustID acoustic fingerprints directly from raw audio waveforms using chromaprint (fpcalc). The acoustic hash is queried against the authoritative MusicBrainz database. Regardless of stripped tags or fabricated filenames, the track, album, and disc index are matched with 100% mathematical certainty.

📺 Custom YTD / yt-dlp Search Tweaks

When automated music pipelines fall back to YouTube / YouTube Music via LYD or yt-dlp, naive searches frequently grab live crowd bootlegs, low-bitrate rips, nightcore remixes, or acoustic user covers.

The Solution: Custom extractor arguments enforce strict search result weighting:

  • Channel Verification: Prioritizes official verified artist channels and - Topic releases over third-party uploads.
  • Runtime Precision: Discards candidates whose duration deviates by > 3 seconds from the official MusicBrainz track duration.
  • Bitrate & Codec Gate: Selects best Opus (160k) or AAC (256k) audio streams while stripping video payloads.

🎙️ Subtitles & Whisper STT for Chaotic TV (MythBusters)

Iconic series like MythBusters suffer from notorious metadata chaos: broadcast air dates, Discovery air codes, DVD production codes, and TheTVDB/TMDB numbering all wildly disagree, resulting in wrong episode titles and scrambled files.

The Solution: Automated opening narration fingerprinting. Every episode opens with narrator Robert Lee stating: "On this episode of MythBusters... Adam and Jamie test [Myth A], while Kari, Grant, and Tory investigate [Myth B]..."

By extracting subtitle tracks or running local Whisper STT (Speech-to-Text) on the first 60 seconds of audio, our script transcribes the spoken myths and fuzzy-matches the text against official episode synopsis databases. The episode is deterministically tagged and renamed to its exact TVDB SxxExx code with 100% accuracy.

Deterministic Episode Resolver (whisper_myth_match.py)
import whisper, re, json, difflib, subprocess

# 1. Transcribe opening 60s of audio via lightweight local Whisper STT
def transcribe_opener(video_path):
    subprocess.run(["ffmpeg", "-ss", "0", "-t", "60", "-i", video_path, 
                    "-vn", "-ac", "1", "-ar", "16000", "-y", "/tmp/opener.wav"], 
                   stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
    model = whisper.load_model("tiny.en")
    result = model.transcribe("/tmp/opener.wav")
    return result["text"].lower()

# 2. Match spoken narration ("Adam and Jamie test...") against TVDB episode log
def resolve_episode(transcription, episode_db):
    best_match, highest_score = None, 0.0
    for ep in episode_db:
        # Fuzzy score against known myth synopsis keywords
        score = difflib.SequenceMatcher(None, transcription, ep["synopsis"].lower()).ratio()
        if score > highest_score:
            highest_score, best_match = score, ep
    # Deterministic resolution: returns verified TVDB SxxExx
    return best_match if highest_score > 0.42 else None

🎬 Post-Processing: Tdarr Hardware Transcoding Flows

Raw downloaded releases often contain bloated uncompressed codecs, foreign multi-channel audio tracks you will never listen to, or broken subtitle streams. We use Tdarr with distributed worker nodes to standardize our library in H.265 (HEVC).

The Stream Cleanup Decision Engine

Before encoding a single pixel, every file passes through custom logic in the Tdarr Flow:

  • Fast Skips: If the file is already H.265 or overall bitrate is < 500 kbps, skip immediately (< 5ms check).
  • MKV Subtitle Protection: Strips mov_text and eia_608 streams. These are MP4-specific codecs that cause FFmpeg multiplexer crashes when saved into MKV containers.
  • Language Pruning: Drops non-English audio/subtitles (with custom flow exceptions for dual-audio Japanese anime).
  • Audio Standardization: Ensures a clean AAC 2.0 fallback track exists alongside 5.1/7.1 surround sound.

Tradeoffs: CPU (x265) vs. GPU (NVENC / QuickSync)

Criteria CPU (libx265) GPU (NVENC / QSV)
Speed Slow (2–6 hours / movie) ⚡ Fast (10–25 mins / movie)
Power / Heat 100% CPU usage, high thermal load Low CPU load, ~35W GPU draw
Compression Efficiency Slightly smaller at equal quality ~5–8% larger than CPU at equal VMAF
Homelab Recommendation Only for small archival batches Gold Standard for automated bulk pipelines
⚠️

The TMM MediaInfo XML Trap

When Tdarr transcodes an existing file in-place, TinyMediaManager may refuse to update its database because it reads stale -mediainfo.xml cached files. Always configure your Tdarr post-transcode hook to delete stale .mediainfo.xml files before firing the TMM REST API call!

🔤 Subtitle Standardization & SRT Normalization Pipeline

The single most common root cause of unexpected server transcoding in a homelab isn't video codecs or high bitrates—it is incompatible subtitle streams.

The Transcoding Culprits: PGS/VobSub & Styled ASS/SSA

Direct Blu-ray and DVD remuxes carry raw bitmap subtitle formats (PGS / hdmv_pgs_subtitle and VobSub / dvd_subtitle). Anime releases frequently embed heavily styled ASS/SSA tracks with custom rasterized fonts and precise on-screen positioning coordinates.

Most thin clients—including smart TVs, Roku sticks, Apple TV native players, and mobile browsers—cannot render bitmap or styled vector subtitles client-side. When a user turns on subtitles, Jellyfin is forced into software video transcoding to burn the subtitles directly into the video stream. This instantly destroys direct play, spikes CPU/GPU utilization to 100%, breaks HDR tone mapping, and degrades stream clarity.

The Fix: Automated UTF-8 SRT & Default Disposition

Our ingestion pipeline (via Tdarr stream cleanup and Bazarr automation) standardizes all subtitles into universal SubRip (clean UTF-8 .srt):

  • Purge Bitmap & Styled Tracks: Ingested MKVs are parsed by Tdarr flows that strip all PGS, VobSub, and complex ASS streams from the container.
  • Bazarr Automated Retrieval: Bazarr monitors Sonarr/Radarr and automatically acquires matching clean text subtitles from OpenSubtitles, Subscene, or generates them via local Whisper STT.
  • UTF-8 Character Sanitization: Subtitle tracks are converted to standard UTF-8 .en.srt, stripping HTML styling tags, color codes, and malformed encodings.
  • Standardized Disposition (-disposition:s:0 default): The primary English text subtitle track is flagged with default disposition so compatible media players select it automatically without prompting the user or triggering server-side transcode burn-in.
Automated SRT Subtitle Extraction & Disposition Normalization
# Strip incompatible bitmap subtitles, standardize clean English text stream as UTF-8 SRT, and set default disposition
ffmpeg -i "input_movie.mkv" \
  -map 0:v:0 -map 0:a \
  -map 0:s:m:language:eng? \
  -c:v copy -c:a copy \
  -c:s srt \
  -metadata:s:s:0 language=eng \
  -metadata:s:s:0 title="English [SRT Normalized]" \
  -disposition:s:0 default \
  "output_movie_normalized.mkv"

# Sidecar extraction workflow for thin-client direct streaming
ffmpeg -i "input_movie.mkv" -map 0:s:m:language:eng:0 -c:s srt -y "movie_title.en.srt"

⚔️ Battle-Tested Homelab Gotchas & Pro-Tips

1. Storage Protocol: Why NFSv4.1 Beats CIFS/SMB

If you mount your NAS media storage via SMB/CIFS to your Docker host, high-throughput concurrent writes (e.g. SABnzbd extracting at 80 MB/s while Tdarr nodes write back transcoded files) will eventually cause transient socket reconnects.

On CIFS soft mounts, writes fail silently at 4 MiB buffer boundaries—leaving you with permanently truncated media files that freeze mid-movie.

The Fix: Always use NFSv4.1 hard mounts. NFS handles concurrent multithreaded I/O and container lockups gracefully without locking kernel threads.

2. Synology ACLs vs. POSIX Permissions

When Sonarr/Radarr running as root moves a downloaded file to a Synology NFS share, it attempts a POSIX chmod 644. Synology DSM intercepts this and drops Windows ACL inheritance, making the file inaccessible to Jellyfin.

The Fix: Create a scheduled task in Synology DSM Task Scheduler running every 30 minutes:

Synology Root Task Script
find /volume1/media/movies -mmin -60 -exec /usr/syno/bin/synoacltool -enforce-inherit "{}" \;
find /volume1/media/shows -mmin -60 -exec /usr/syno/bin/synoacltool -enforce-inherit "{}" \;

3. The Golden Path: Atomic Hardlinks (Never separate /downloads & /movies)

If you map volumes as /downloads:/downloads and /movies:/movies, Docker sees them as separate file systems. When a download finishes, Radarr has to copy 40 GB across disks and delete the old one.

The Fix: Mount a single parent path (e.g. /mnt/nas-data:/data) into all containers. Structure it as /data/torrents, /data/usenet, and /data/media. This allows Radarr/Sonarr to create instant, zero-cost hardlinks—meaning zero extra disk space is used while you continue seeding!

📄 Production Docker Compose Blueprint

Here is a clean, battle-hardened starter compose.yaml demonstrating the Gluetun VPN sandbox, *arr services, and single-root storage mounts:

compose.yaml (Complete Unified Pipeline)
services:
  # VPN Gateway with Hardware Killswitch
  gluetun:
    image: qmcgaw/gluetun:latest
    container_name: gluetun
    cap_add:
      - NET_ADMIN
    devices:
      - /dev/net/tun:/dev/net/tun
    ports:
      - 8080:8080   # qBittorrent WebUI (bound through VPN)
      - 6881:6881   # Torrent peering
      - 6881:6881/udp
    environment:
      - VPN_SERVICE_PROVIDER=protonvpn # or mullvad, airvpn, custom
      - VPN_TYPE=wireguard
      - WIREGUARD_PRIVATE_KEY=your_private_key
      - WIREGUARD_ADDRESSES=10.2.0.2/32
    restart: unless-stopped

  # qBittorrent bound strictly into Gluetun network namespace
  qbittorrent:
    image: lscr.io/linuxserver/qbittorrent:latest
    container_name: qbittorrent
    network_mode: "service:gluetun"
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=America/Chicago
      - WEBUI_PORT=8080
    volumes:
      - ./data/qbittorrent:/config
      - /mnt/data:/data # Root data folder for instant hardlinks
    depends_on:
      - gluetun
    restart: unless-stopped

  # SABnzbd (Usenet - Direct SSL connection, no VPN required)
  sabnzbd:
    image: lscr.io/linuxserver/sabnzbd:latest
    container_name: sabnzbd
    ports:
      - 8880:8080
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=America/Chicago
    volumes:
      - ./data/sabnzbd:/config
      - /mnt/data:/data
    restart: unless-stopped

  # Prowlarr Indexer Proxy
  prowlarr:
    image: lscr.io/linuxserver/prowlarr:latest
    container_name: prowlarr
    ports:
      - 9696:9696
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=America/Chicago
    volumes:
      - ./data/prowlarr:/config
    restart: unless-stopped

  # Radarr (Movies)
  radarr:
    image: lscr.io/linuxserver/radarr:latest
    container_name: radarr
    ports:
      - 7878:7878
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=America/Chicago
    volumes:
      - ./data/radarr:/config
      - /mnt/data:/data
    restart: unless-stopped

  # Sonarr (TV Shows)
  sonarr:
    image: lscr.io/linuxserver/sonarr:latest
    container_name: sonarr
    ports:
      - 8989:8989
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=America/Chicago
    volumes:
      - ./data/sonarr:/config
      - /mnt/data:/data
    restart: unless-stopped

  # SeerrNG Request Portal (Unified Media Discovery & Authentik OIDC)
  seerrng:
    image: ghcr.io/snapetech/seerrng:v3.21.4
    container_name: seerrng
    ports:
      - 5055:5055
    environment:
      - LOG_LEVEL=debug
      - TZ=America/Chicago
    volumes:
      - ./data/seerrng:/app/config
    restart: unless-stopped

  # Tdarr Transcoding Server + Hardware Node
  tdarr:
    image: ghcr.io/haveagitgat/tdarr:latest
    container_name: tdarr
    restart: unless-stopped
    ports:
      - 8265:8265  # WebUI
      - 8266:8266  # Node registration port
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=America/Chicago
      - serverIP=0.0.0.0
      - serverPort=8266
      - webUIPort=8265
      - internalNode=true
      - nodeName=TranscodeNode
      - NVIDIA_DRIVER_CAPABILITIES=compute,video,utility
      - NVIDIA_VISIBLE_DEVICES=all
    volumes:
      - ./data/tdarr/server:/app/server
      - ./data/tdarr/configs:/app/configs
      - ./data/tdarr/logs:/app/logs
      - /mnt/data/media/movies:/media/movies
      - /mnt/data/media/shows:/media/shows
      - /tmp/tdarr-scratch:/temp # Fast local scratch disk
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: 1
              capabilities: [gpu]