Media stack: requests, storage, 4K, cleanup and re-encoding¶
This stack is here for learning: how the apps are wired, stored and run on Kubernetes. The only things downloaded with it are Linux ISOs and other openly licensed content.
The arr apps, Cleanuparr and Tdarr keep their settings in their own databases on their config PVCs, not in this repo. This page records the settings that matter. With them you can rebuild the apps after a lost volume.
Overview¶
| App | URL | Namespace | Role |
|---|---|---|---|
| Seerr | https://seerr.bigd.no |
plex-media-stack |
Requests, with a separate "Request in 4K" button |
| Radarr | https://radarr.local.bigd.no |
arr-stack |
1080p movies in /data/movies |
| Radarr 4K | https://radarr-4k.local.bigd.no |
arr-stack |
4K movies in /data/movies-4k |
| Bazarr, Bazarr 4K | https://bazarr.local.bigd.no, https://bazarr-4k.local.bigd.no |
arr-stack |
Subtitles for Sonarr and Radarr, and for Radarr 4K |
| Sonarr | https://sonarr.local.bigd.no |
arr-stack |
TV in /data/series |
| Prowlarr | https://prowlarr.local.bigd.no |
gluetun-vpn |
Indexers, sidecar in the VPN pod. Its DNS goes through the VPN, so it reaches the arr apps through hostAliases |
| qBittorrent | https://qbittorrent.local.bigd.no |
gluetun-vpn |
Downloads, sidecar in the VPN pod |
| Tdarr | https://tdarr.local.bigd.no |
arr-stack |
Re-encodes H.264 to HEVC |
| Plex | http://10.3.10.103:32400/web |
plex-media-stack |
Playback, libraries below |
A request goes from Seerr to Radarr, Radarr 4K or Sonarr. The arr app searches the
Prowlarr indexers and sends the torrent to qBittorrent. When the download finishes,
the arr app hardlinks the file into its root folder. Plex picks up the file. Tdarr
later re-encodes it if it is H.264 and no longer seeding. All of these apps have
tiles on the hub (hub.bigd.no, k8s/talos/apps/homepage/values.yaml).
Prowlarr, qBittorrent and Gluetun share one pod. All their traffic leaves through
the PIA VPN. Prowlarr reaches FlareSolverr in arr-stack for indexers behind a
browser challenge.
Plex libraries: Movies (/movies), Movies 4K (/movies-4k), TV Shows (/tv),
Courses, Youtube. Each is a read-only NFS mount of the matching folder on the
share, declared in k8s/talos/apps/plex-media-stack/plex.yaml. A new library folder
must exist on the share before you add it there. If it does not, Plex fails to start.
Storage layout and hardlinks¶
Everything is on one Synology share, /volume1/shared-data/media. Sonarr, Radarr,
Radarr 4K, Bazarr, Unpackerr and Tdarr mount it at /data.
| Path | Contents |
|---|---|
/data/series |
Sonarr root folder |
/data/movies |
Radarr root folder (also the root for all Radarr collections) |
/data/movies-4k |
Radarr 4K root folder |
/data/torrents/download |
qBittorrent incomplete downloads |
/data/torrents/completed |
qBittorrent completed torrents, still seeding |
/data/transcode_cache/tdarr |
Tdarr work files |
Library and torrents must stay on the same mount. Linux cannot hardlink across two
mounts. With separate /tv and /torrents mounts the arr apps silently copy every
import, and each seeding torrent costs a second full copy on the NAS.
qBittorrent is not part of this. It still mounts only /torrents (the torrents
folder) and reports paths like /torrents/completed/.... Sonarr and Radarr translate
those paths with a remote path mapping.
Check that an import was hardlinked: stat -c %h <library file> shows 2 while the
torrent is still in qBittorrent.
Seeding¶
Almost every torrent is from a private tracker. If a torrent stops before the tracker's minimum, the tracker gives a hit-and-run strike. Every layer is set so that nothing stops or removes a torrent early:
| Layer | Setting |
|---|---|
| Prowlarr, per indexer (synced to Sonarr, Radarr, Radarr 4K) | seed ratio and time set per indexer. Ratio limits are 5 or none, never a time limit |
| qBittorrent, global | no ratio, seeding time or inactivity limit. Queueing off, so every torrent seeds |
| Sonarr | "Remove Completed" on: removes a torrent only after qBittorrent stopped it at ratio 5 |
| Radarr, Radarr 4K | "Remove Completed" off |
| All arrs | "Remove Failed" off |
| Cleanuparr | "Delete Private" off, Download Cleaner off |
| Tdarr | skips hardlinked files (library filter and flow), so a seeding file is never split |
Moves inside /data |
renames on one share keep the inode, so the torrent keeps its data |
qBittorrent stops a torrent at the ratio limit or at the time limit, whichever comes first. A ratio limit is only safe for a tracker whose hit-and-run rule is "ratio or time". Some trackers demand a minimum seed time at any ratio. For those, remove the ratio limit in Prowlarr.
Check: stoppedUP or missingFiles in qBittorrent's torrent list should be empty.
Sonarr and Radarr¶
- Root folders:
/data/series,/data/movies. - Media Management: "Use Hardlinks instead of Copy" on.
- Download client qBittorrent: host
qbittorrent.gluetun-vpn, port8080, no SSL. Categoriestv-sonarrandradarr. - Remote path mapping: host
qbittorrent.gluetun-vpn, remote/torrents/, local/data/torrents/. The host must match the download client host exactly. - "Remove Failed Downloads" off in both. Almost every torrent is from a private tracker. A removal from qBittorrent risks a hit-and-run strike.
- "Remove Completed Downloads": on in Sonarr, off in Radarr and Radarr 4K. The arr app removes a torrent only after qBittorrent has stopped it at its seeding limit.
- qBittorrent categories:
tv-sonarr,radarr,radarr-4k, plus manual ones. Each arr creates its own on the first connection test. - Seerr default folders:
/data/seriesand/data/movies. 4K requests go to Radarr 4K (below). - General > Backups (also in Radarr 4K and Prowlarr): interval 1 day, retention 14 days, folder
Backups. The nightly VolSync copy of/configcarries these zips. A restore starts from the newest zip, not from the live database (docs/platform/backups/README.md).
Release filters¶
The goal is media that plays correctly, not the highest quality tier. Recyclarr
(k8s/talos/apps/arr-stack/recyclarr.yaml) runs every night. It syncs TRaSH custom
formats and scores into the HD - 720p/1080p profile in Sonarr and Radarr, and into
the Any profile in Sonarr. Radarr 4K is not managed.
| Score | Custom formats | Effect |
|---|---|---|
| -10000 | LQ, LQ (Release Title), BR-DISK, Extras, Bad Dual Groups, Upscaled, 3D (Radarr only) | The release is rejected |
| -2000 | MULTi | The release is grabbed only when nothing else exists. These releases often have a foreign first audio track |
| TRaSH default | WEB Tier 01 to 03, WEB Scene, HD Bluray tiers | Good groups win inside one quality |
| 150 | Season Pack (Sonarr) | One source for a whole season wins, so the audio does not change between episodes |
Minimum custom format score is -5000. Scores decide only new grabs. Upgrades stay off in these profiles, so a filter change replaces no file. Existing bad files need a manual search.
Do not add these rules:
- A penalty on x265. Tdarr makes the library HEVC on purpose.
- "Language: Not Original". Sonarr lists some Norwegian shows as English, and the rule would reject their Norwegian releases.
- An
upgradekey with a score cutoff in the Recyclarr config. Almost every file scores 0 today, so a large part of the library would download again.
Check a release: GET /api/v3/parse?title=<release name> on Sonarr or Radarr
returns its custom formats and score.
Radarr 4K¶
https://radarr-4k.local.bigd.no is a second Radarr for films kept in 4K. A 4K film
lives only here. The main Radarr does not track it, so there is no 1080p copy unless
someone requests one in Seerr. Radarr tracks one file per movie, so 4K needs its own
instance and root folder. Two instances that share /data/movies would delete each
other's files on upgrade.
- Root folder
/data/movies-4k, owned by the Synology share user with mode 777. - Media Management and file naming copied from Radarr (hardlinks on).
- Download client qBittorrent, same host, user and remote path mapping as Radarr,
category
radarr-4k, "Remove Completed" and "Remove Failed" off. - Quality profile
2160p: WEB 2160p and Bluray-2160p, no remux, cutoff WEB 2160p, upgrades on. Existing remuxes rank above the cutoff, so Radarr 4K keeps them and does not swap in a smaller WEB release. Custom format "DV (w/o HDR fallback)" from TRaSH (docs/json/radarr/cf/dv-wo-hdr-fallback.json) scored -10000. Those files play with purple and green colours on screens without Dolby Vision. - Indexers: Prowlarr syncs them. Radarr 4K is its own app there
(
https://radarr-4k.local.bigd.no, full sync, movie categories). - Seerr: Radarr server "Radarr 4K", hostname
radarr-4k.local.bigd.noport 443 SSL, "4K Server" and "Default Server" on, profile2160p, root/data/movies-4k. - Plex:
Movies 4Klibrary, shared only with users whose devices play 4K HDR. Then nobody else forces a 4K HDR transcode on the iGPU. - Tdarr: library
Movies 4Kwith the same flow. Today every file is HEVC and is skipped. The library is there to catch a 2160p H.264 release. Such a release is SDR, so re-encoding loses no HDR. - Bazarr 4K: subtitles, see below.
- Cleanuparr: its own Radarr instance,
http://radarr-4k:7878. - Unpackerr:
UN_RADARR_1_*ink8s/talos/apps/arr-stack/unpackerr.yaml. - Metrics:
exportarr-radarr-4k, so the Radarr alerts ink8s/talos/infra/kube-prometheus-stack/homelab-alerts.yamlcover it too. - Hub tile with a widget. Its API key is Bitwarden secret
homepage-radarr-4k-api. All of the above use that key in Git.
Moving an existing 1080p-library film to 4K only: move its folder from
/data/movies to /data/movies-4k. This is a rename on the same share, so the
hardlinks stay. Add the film in Radarr 4K with that path and profile 2160p, without
a search. Then delete it from Radarr with "Delete files" off. Check first that its
collection is not monitored in Radarr. If it is, Radarr adds the film back and
downloads a 1080p copy.
Seerr and Tautulli¶
Both reach Plex at plex.plex-media-stack, port 32400, no SSL. Use the Service
name, never the Plex pod IP or the *.plex.direct name that Plex offers during setup.
That name encodes the pod IP. The pod IP changes on every Plex restart, and then
scans, availability and activity silently time out.
Seerr (https://seerr.bigd.no):
- Plex libraries enabled:
Movies,Movies 4K,TV Shows,Courses,Youtube. A new Plex library shows up only after Settings > Plex > Sync Libraries. It stays disabled until you tick it. - Servers: Radarr (1080p, default, profile
HD - 720p/1080p,/data/movies), Radarr 4K (4K, default, profile2160p,/data/movies-4k), Sonarr (default,/data/series). There is no 4K Sonarr. - After you move films between libraries, run the "Media Availability Sync" job. It clears the old 1080p status, and the film can be requested in 1080p again.
Tautulli (https://tautulli.local.bigd.no): Settings > Plex Media Server, same address.
If its websocket logs "401 Unauthorized", the stored Plex token was revoked. Either use
"Fetch New Token" on the same page and sign in with the Plex account, or give it the
server owner's token. That token is PlexOnlineToken in Plex's Preferences.xml. Set
it with $.post('save_pms_token', {token: '<token>'}) in the browser console on
Tautulli's settings page.
Bazarr and Bazarr 4K¶
Bazarr connects to one Sonarr and one Radarr. Radarr 4K therefore has its own
instance, bazarr-4k, built from the same settings.
- Both: the same subtitle providers (Settings > Providers). Language profile
"English + Norwegian" (
no,en) is the default for new titles. Embedded subtitles count. Upgrades for 7 days. They have no login page of their own and are reachable on the private gateway only. - Bazarr: Sonarr
sonarr.arr-stack.svc.cluster.local:8989, Radarrradarr.arr-stack.svc.cluster.local:7878. - Bazarr 4K: Sonarr off, Radarr
radarr-4k.arr-stack.svc.cluster.local:7878. - Rebuilding Bazarr 4K: copy
/config/config/config.yamlfrom Bazarr. It carries the provider logins. Keep the new instance's ownauth.apikey, setuse_sonarr: falseand the Radarr 4K address and key, then restart. The language profile is in the database, so create it again (Settings > Languages) and assign it to the films. - Each has an exporter (
exportarr-bazarr,exportarr-bazarr-4k) and a hub tile. The 4K key is Bitwarden secrethomepage-bazarr-4k-api.
Cleanuparr¶
https://cleanuparr.local.bigd.no, admin account in the password manager.
- Download client qBittorrent at
http://qbittorrent.gluetun-vpn:8080, with the qBittorrent exporter credentials. - Sonarr
http://sonarr:8989(v4), Radarrhttp://radarr:7878(v6), Radarr 4Khttp://radarr-4k:7878(v6). - Queue Cleaner, every 5 min, failed imports at 3 strikes:
Ignore Private off, Delete Private off, Skip if not found in client on,
Force Import on (3 tries), pattern mode Exclude with
matched to series by IDandmatched to movie by ID. No stall or slow rules. - Malware Blocker, every 5 min: blocklist
https://cleanuparr.pages.dev/static/blacklist_permissivefor Sonarr and Radarr, Ignore Private off, Delete Private off. - Seeker: search on, proactive search off.
- Download Cleaner: off.
Delete Private off is the rule that keeps private torrents seeding. Cleanuparr then removes only the item from the arr queue and leaves the torrent in qBittorrent.
Tdarr¶
https://tdarr.local.bigd.no. The server has an internal node on genesis-worker-01.
The node uses the iGPU through Quick Sync, shared with Plex (see
k8s/talos/infra/intel-gpu-plugin/daemonset.yaml).
Flow h264ToHevcQsv, stored in tdarr-flow-h264-to-hevc-qsv.json next to this file:
- Skip files with more than one link (still seeding) and anything with
remuxin the path. - In an MKV with a usable English track, make that track the first audio track and the default. Commentary and audio-description tracks do not count. Clear the default flag on subtitles in other languages. All streams are copied, so quality does not change. Stop with an error if the duration changes by more than 0.5 percent.
- Only H.264 video continues.
- Encode video to HEVC with QSV, preset slow, quality 23, audio and subtitles copied.
- Stop with an error if the new file's duration is not within 0.5 percent of the original's. This catches a truncated or broken encode.
- Replace the original only when the new file is under 85 percent of the old size. Otherwise switch back to the original and end without an error. There is no lower size bound. QSV quality 23 gives 6 to 20 percent on clean H.264 WEB-DL and Bluray sources at 42 to 50 dB PSNR. The duration check is what guards against a broken output.
Restore it with:
jq -c '{data:{collection:"FlowsJSONDB", mode:"insert", docID:._id, obj:.}}' docs/apps/media-stack/tdarr-flow-h264-to-hevc-qsv.json \
| curl -s -H 'Content-Type: application/json' https://tdarr.local.bigd.no/api/v2/cruddb -d @-
Libraries TV (/data/series), Movies (/data/movies) and Movies 4K
(/data/movies-4k): flow
h264ToHevcQsv, cache /data/transcode_cache/tdarr, health checks off,
"skip hardlinked files" on, folder watching on, @eaDir ignored, schedule
00:00 to 07:00 every day. Scanner: 4 threads, MediaInfo scan off. The flow reads only
ffprobe data, and each extra scanner reads every file again over NFS. FFprobe and
ExifTool always run. The UI shows them as fixed ON.
Node: 1 GPU transcode worker, no CPU workers. Set the worker limit on the live node
(Nodes page, or POST /api/v2/alter-worker-limit). A write to the database alone
does nothing.
A re-encode of a file that is hardlinked to a seeding torrent would split it into two copies again. That is why both the library setting and the flow skip such files.