Skip to content

Media Stack

Nota (2026-07-17): Lidarr está de vuelta con un pipeline de música basado en Soulseek (Lidarr + slskd + soularr) — ya no usa Deemix ni torrents como fuente principal. Ver Music Acquisition (Soulseek) abajo.

Core media automation and streaming services. Always running.

Compose file media/compose.yaml
Status Always on
Dependencies NFS mount at /mnt/nfs_media

Architecture

                    ┌──────────────┐
                    │  Jellyseerr  │ ← User requests
                    │    :5055     │
                    └──────┬───────┘
          ┌────────────────┼────────────────┐
          ▼                ▼                ▼
    ┌──────────┐     ┌──────────┐     ┌──────────┐
    │  Sonarr  │     │  Radarr  │     │  Lidarr  │
    │   :8989  │     │   :7878  │     │   :8686  │
    └────┬─────┘     └────┬─────┘     └──────────┘
         │                │
         └────────┬───────┘
    ┌─────────────────────────┐
    │       Prowlarr          │ ← Indexer management
    │         :9696           │
    │   (FlareSolverr :8191)  │
    └─────────────┬───────────┘
    ┌─────────────▼───────────┐
    │       Plundrio          │ ← Put.io downloader
    │         :9091           │
    └─────────────┬───────────┘
    ┌─────────────▼───────────┐     ┌──────────────┐
    │   Plundrio-Scanner      │────▶│ Plundrio-    │
    │         :8086           │     │ Hunter :8087 │
    └─────────────────────────┘     └──────────────┘
    ┌─────────────────────────┐
    │       Jellyfin          │ ← Streaming
    │         :8096           │
    └─────────────┬───────────┘
         ┌───────┴───────┐
         ▼               ▼
    ┌──────────┐    ┌──────────┐
    │ Jellystat│    │  Tunarr  │
    │   :3100  │    │   :8555  │
    └──────────┘    └──────────┘

Services

Media Management

Service Port Image Purpose
Sonarr 8989 linuxserver/sonarr TV show automation
Radarr 7878 linuxserver/radarr Movie automation
Lidarr 8686 lscr.io/linuxserver/lidarr Music library + wanted list (Soulseek acquisition — ver Music)
Bazarr 6767 linuxserver/bazarr Subtitle management
Prowlarr 9696 linuxserver/prowlarr Indexer management
FlareSolverr 8191 flaresolverr/flaresolverr Cloudflare bypass proxy

Download Management (Plundrio Ecosystem)

Custom Put.io integration built locally. See ~/plundrio/README.md (separate git repo).

Service Port Purpose Watchtower
Plundrio 9091 Put.io download client Yes
Plundrio-Scanner 8086 Verifies imports, cleans up, cancels dead torrents; ManualImport fallback + orphan sweep (2026-07-16: fixes files DownloadedEpisodesScan silently skips — season packs / tracker-prefixed names) No (custom build)
Plundrio-Hunter 8087 Proactively searches for missing media No (custom build)

Key settings (turbo-boosted): - PLDR_WORKERS=6 - Parallel download threads - POLL_INTERVAL=20 - Scanner checks every 20s - HUNT_BATCH_SIZE=6 - Items per hunt cycle - HOURLY_CAP=60 - Max searches per hour

Music Acquisition (Soulseek)

Re-added 2026-07-17. Music uses a Soulseek pipeline (not torrents/Deemix as the primary source) — Soulseek has the best coverage for 2000s / back-catalog music. Repo: plundrio-ecosystem is unrelated; these are stock images + config.

Service Port Image Purpose
Lidarr 8686 lscr.io/linuxserver/lidarr Music library + wanted/missing list
slskd 5030 / 50300 slskd/slskd Soulseek daemon (search + download)
soularr 8265 ghcr.io/mrusse/soularr Bridge: Lidarr wanted → slskd → import

Flow: Lidarr catalogues each artist's discography → marks missing albums → soularr reads the wanted list, searches slskd (Soulseek), downloads FLAC/MP3 to /downloads/soulseek/complete, then triggers Lidarr to import into /data/music.

Config & tuning:

  • Library root: /data/music (/mnt/nfs_media/music); Soulseek downloads land in /mnt/nfs_media/downloads/soulseek/.
  • slskd.yml (~/appdata/slskd/): Soulseek creds + web login + an API key for soularr. Shares /music read-only.
  • soularr config.ini (~/appdata/soularr/), tuned for max coverage: allowed_filetypes = flac,mp3, minimum_filename_match_ratio = 0.4, number_of_albums_to_grab = 30, search_type = incrementing_page, search_source = all.
  • Lidarr quality profile = Any for all artists (accepts SD/MP3 → lossless), so nothing is rejected on quality.
  • Secondary source: Lidarr also grabs music torrents via Putioarr (the plundrio Transmission client) + Prowlarr indexers. Download client category is empty so it resolves to /data/downloads (flat, where plundrio writes).

Indexers (Prowlarr, expanded 2026-07-16): added EZTV, 1337x, LimeTorrents, Knaben, Nyaa.si, RuTor, RuTracker.org — 1337x / EZTV / RuTracker route through FlareSolverr (tagged cloudflare). RuTracker needs a (free) account.

External access: lidarr / slskd / soularr.monxas.casa — routed by homelab-ctl sync (tunnel.hostname labels) behind CF Access / PocketID.

Streaming & Stats

Música → doc dedicado

El streaming de música (Navidrome), la curación de metadatos (beets), letras, ReplayGain, smart playlists y la radio por IA (AudioMuse-AI) tienen su propio doc: Música — Navidrome + AudioMuse-AI.

Service Port Purpose
Jellyfin 8096 Media streaming server
Navidrome 4533 Music streaming (Subsonic) — ver doc dedicado
Jellyseerr 5055 Request management UI
Jellystat 3100 Viewing statistics dashboard
Tunarr 8555 Custom TV channels from library
Audiobookshelf 13378 Podcast/audiobook server

Sharing & Utilities

Service Port Purpose
Jellyfin-Share 8097 Temporary shareable links
ntfy 8082 Push notifications
Torrentland-Torznab 5075 Custom indexer scraper
Beszel-Agent 45876 System metrics agent

Data Paths

Container Path Host Path Purpose
/data /mnt/nfs_media Full NAS mount
/downloads /mnt/nfs_media/downloads Download staging
/config /home/monxas/appdata/<service> Service config

Dependencies

FlareSolverr (no deps)
    └── Prowlarr
        ├── Sonarr
        ├── Radarr
        └── Lidarr

Plundrio (no deps)
    └── Plundrio-Scanner
        └── Plundrio-Hunter

Jellyfin (no deps)
    ├── Jellyseerr
    ├── Jellystat → jellystat-db
    ├── Tunarr
    └── Jellyfin-Share → jellyfin-share-db

ntfy (no deps) ← Used by Scanner, Hunter

Rebuilding Custom Services

Plundrio-Scanner and Hunter are built from local source:

cd ~/stacks/media

# Rebuild after code changes
docker compose build plundrio-scanner plundrio-hunter

# Restart with new build
docker compose up -d plundrio-scanner plundrio-hunter

# Force rebuild without cache
docker compose build --no-cache plundrio-scanner

Environment Variables

Key environment variables for this stack (from ~/.env):

Variable Used By Description
SONARR_API_KEY Scanner, Hunter Sonarr API access
RADARR_API_KEY Scanner, Hunter Radarr API access
PUTIO_TOKEN Plundrio, Scanner, Hunter Put.io OAuth token
PLUNDRIO_USER All Plundrio services RPC authentication
PLUNDRIO_PASS All Plundrio services RPC authentication
JELLYFIN_API_KEY Jellystat, JF-Share Jellyfin API access
POSTGRES_PASSWORD jellystat-db, jf-share-db Database password

Troubleshooting

Plundrio not downloading?

# Check health
curl -s "http://localhost:9091/health" -u "monxas:$PLUNDRIO_PASS"  # ver secrets.local.md

# Check Put.io slots
curl -s "https://api.put.io/v2/transfers/list?oauth_token=YOUR_TOKEN" | jq '.transfers | length'

Scanner not importing?

# Check dashboard
open http://localhost:8086

# Check logs
docker logs plundrio-scanner -f --tail 100

Sonarr/Radarr not finding releases?

# Check Prowlarr indexers
open http://localhost:9696

# Test FlareSolverr
curl -X POST "http://localhost:8191/v1" -H "Content-Type: application/json" \
  -d '{"cmd":"request.get","url":"https://example.com"}'

Downloads stalled / queue not draining?

Dead torrents (no seeders) pile up on put.io in WAITING and clog the download slots so good transfers never start. Purge them — Sonarr's autoRedownloadFailed then re-searches for seeded alternatives:

TOKEN=$(grep ^PUTIO_TOKEN= ~/.env | cut -d= -f2-)
# IDs of the dead ones (ERROR, or WAITING/DOWNLOADING with availability 0 and no speed):
IDS=$(curl -s "https://api.put.io/v2/transfers/list" -H "Authorization: Bearer $TOKEN" | \
  jq -r '.transfers[] | select(.status=="ERROR" or ((.status=="WAITING" or .status=="DOWNLOADING") and (.availability//0)==0 and (.down_speed//0)==0)) | .id' | paste -sd,)
# cancel them:
curl -s -X POST "https://api.put.io/v2/transfers/cancel" -H "Authorization: Bearer $TOKEN" \
  --data-urlencode "transfer_ids=$IDS"

(plundrio-hunter also detects + removes dead torrents over time.)