Homelab Haven

Self-Hosted Media Stack, Part 7: Profilarr, Teaching the Stack Taste

July 29, 20264 min read

Part 7, the last of Media Stack from Scratch. The stack works end to end since Part 4 — this part is about making its choices good.

Out of the box, a quality profile is mostly a resolution preference. Two releases of the same movie at 1080p can differ wildly — a clean efficient encode versus a bloated transcode, a reputable group versus one that mislabels sources — and stock profiles can't tell them apart. The *arrs can, through custom formats with scores, but building and maintaining those by hand is a hobby in itself.

Profilarr's pitch: don't. It syncs curated custom formats and full quality profiles from the Dictionarry project into Sonarr and Radarr, and keeps them updated as the curators refine them — the same way Prowlarr saved you from maintaining indexers per app.

Summary

  • Custom formats turn "grab the 1080p" into "grab the good 1080p".
  • Profilarr manages them for you, synced from a maintained database.
  • Fewer profiles is better — I consolidated to two per app and regret nothing.
  • Two real traps below: removing a profile from sync doesn't remove it downstream, and format-list updates can silently re-score files already on disk.

The compose

Two containers — Profilarr and a parser sidecar it depends on:

services:
  profilarr:
    image: ghcr.io/dictionarry-hub/profilarr:latest
    container_name: profilarr
    restart: unless-stopped
    environment:
      - PUID=1001
      - PGID=100
      - UMASK=022
      - TZ=Europe/Amsterdam
      - PORT=6868
      - AUTH=on              # it can rewrite your arr profiles; gate it
      - PARSER_HOST=parser
      - PARSER_PORT=5000
    volumes:
      - /path/to/appdata/profilarr:/config
    ports:
      - "6868:6868"
    depends_on:
      parser:
        condition: service_started

  parser:
    image: ghcr.io/dictionarry-hub/profilarr-parser:latest
    container_name: profilarr-parser
    restart: unless-stopped
    expose:
      - "5000"

AUTH=on is not optional in spirit: this app holds write access to your Sonarr and Radarr configuration. Anything that can rewrite profiles can also wreck them.

Setup

  1. *Connect the arrs — Sonarr and Radarr, URL + API key, the same ritual as every other part of this series.
  2. Browse the database and pick profiles — Dictionarry maintains profiles tuned for different goals (quality-first, space-efficient, and so on). Pick the one that matches the ceiling you chose back in Part 2 — if you decided 1080p and finite disks, pick the efficient 1080p profile, not the transparency-at-any-cost one.
  3. Sync — Profilarr writes the profile and its full custom-format set into the *arr. Open Settings → Profiles there and look at what arrived: dozens of formats with scores, the thing you were never going to maintain by hand.
  4. Assign it — new adds get it as their default; existing library entries keep their old profile until you switch them deliberately.

Keep the profile count low. I ended up with exactly two per app — an efficient 1080p and an efficient 4K — after starting with more and discovering that every extra profile is another thing to keep synced, reason about, and accidentally leave a show on. Consolidating meant migrating shows off the deprecated profiles first (a profile in use can't be deleted), which is exactly the kind of chore you avoid by starting small.

Trap one: deselecting syncs nothing away

Removing a profile from Profilarr's sync does not remove it from Sonarr or Radarr. It just stops updating it — the profile stays behind as an orphan, frozen at its last synced state, looking exactly like a managed one. If you reorganize, finish the job in the *arr: migrate anything still using the orphan, then delete it there yourself.

Trap two: updates can re-score what's already on disk

This one cost me an afternoon of confusion. The *arrs decide "is this release an upgrade?" by comparing the candidate's score against the score of the file you already have — and that stored score is recalculated as format lists change. When a curated list update adds a release group to a banned list, a file you've had for a year can drop to a deeply negative score overnight, at which point almost anything looks like a valid upgrade — including a worse release.

Practical defence: after a big definition update, don't fire mass searches blindly. Spot-check a few titles first (Movie → Files shows the current score of what's on disk); if the scores of files you're happy with have cratered, fix the assignment before letting the automation "upgrade" them away.

Where the series ends

That's the stack, complete: Sonarr and Radarr deciding, downloaders fetching behind a VPN, Prowlarr feeding indexers, Seerr taking requests, Bazarr handling subtitles, and Profilarr keeping the definition of "good" current — all unattended.

If you remember one thing from seven parts: every container mounts the same /Media at the same path with the same PUID/PGID. Ninety percent of broken media stacks are that sentence, violated.

Previous: Part 6 — Bazarr. Start of the series: Part 1 — the map.

If this saved you some time, a coffee keeps the lights on and the posts coming.

☕ Buy me a coffee