All apps · 0 apps
UmlautAdaptarrEX
Docker app from lexfi's Repository
Overview
Readme
View on GitHub
Umlaut and German-title proxy for Sonarr / Radarr / Lidarr / Readarr.
Deutsch · English
UmlautAdaptarrEX
AI Disclaimer: This project was built with the help of AI, but not "vibe coded". I have been a software developer for over 11 years and security is a high priority.
Full rewrite of the original .NET tool on Next.js + Fastify + Prisma + SQLite.
UmlautAdaptarrEX presents itself to the *arrs as an indexer, sits between the *arrs and the real indexers, and corrects both searches and results so that releases with umlauts or German titles are reliably found, downloaded and imported.
Which problems does it solve?
- Releases with umlauts are often not found or imported correctly by the *arrs (searching for
oinstead ofö, missing mapping at the indexer). - Sonarr & Radarr expect the English title from TheTVDB / TMDB. For German productions or translations this leads to
errors like
Found matching series/movie via grab history, but release was matched to series by ID. - Bad release naming (e.g. missing
GERMANtag) is optionally corrected so the *arrs detect it properly.
Features
| Feature | Status |
|---|---|
| ✓ | |
alternateTitles + optional TMDB) |
✓ |
| ✓ | |
| ✓ | |
| ✓ | |
Prowlarr indexer-patch dialog: select indexers, auto-tag them & switch from https to http |
✓ |
| Newznab (Usenet) & Torznab (Torrent) support | ✓ |
| Multiple instances per *arr type (e.g. 2× Sonarr) | ✓ |
| Detection of releases with German title & TVDB alias | ✓ |
| Correct search and detection of titles with umlauts | ✓ |
| Renaming of releases with bad naming (optional) | ✓ |
| Web UI (setup wizard, login, dashboard, instances, sync runs, request & rename history) | ✓ |
| Persistent SQLite database, no cache loss after restart | ✓ |
| Live logs via WebSocket | ✓ |
| Multiple title providers with configurable order: pcjones-API, TVDB, TMDB | ✓ |
| Language plugins: German umlauts (default), Swedish umlauts, French accents | ✓ |
| i18n: German + English | ✓ |
Information about Radarr:
- A TMDB / TVDB key is required for Radarr to work.
- A TMDB / TVDB key is required for the plugins to work.
Language Plugins
Language plugins control how titles are normalized and which spelling variants are sent to the indexer. They can be enabled individually during the setup wizard (step "Plugins") or later under Settings → Plugins. Several plugins can run at the same time, e.g. when a library contains both German and French titles.
| Plugin | Language | Default | Behavior |
|---|---|---|---|
| German umlauts | de |
✓ | Latin variants (ä → ae, ö → oe, ü → ue, ß → ss) and no-dots variants (ä → a, …); strips articles Der/Die/Das/The/An/A. |
| Swedish umlauts | sv |
◯ | Swedish romanization: Å → A or AA, Ä → A or AE, Ö → O or OE (preserves case). |
| French accents | fr |
◯ | Removes accents (é → e, à → a, ç → c, …) and expands ligatures (æ → ae, œ → oe); strips articles Le/La/Les/Un/Une/Des/Du/De. |
Each plugin generates multiple variation maps so that releases with mixed spellings (e.g. Brueckenkopf vs.
Brückenkopf vs. Brueckenkopf) are still reliably detected. Audio libraries (Lidarr) additionally use a
"strip-all" path that removes the diacritic letter entirely.
Installation
Three ways to start the image. Whichever variant you pick: after the first start, open
http://<host>:5007 and the setup wizard will walk you through account creation, mode, plugins, Prowlarr and proxy
configuration.
Variant 1: Docker Compose (recommended)
The repository contains two compose files:
| File | Image source | When to use? |
|---|---|---|
docker-compose.yml |
Local build (build: .) |
You cloned the repository and want to build from source. |
docker-compose.release.yml |
lexfi/umlautadaptarrex:latest (Docker Hub) |
Fastest way, no repo checkout needed. |
Note: when the container runs as root (the default), the image fixes permissions on the /data volume
automatically at startup (default PUID=1000, PGID=1000). A manual chown is no longer needed. root
is used only for this one-time chown: the entrypoint fixes ownership and then switches to
PUID:PGID via gosu, so the application process (node start.mjs) never runs as root. If you want
files under ./data to be owned by a different host user, set PUID/PGID as env variables (see
comments in the respective compose file).
Unprivileged operation: the image can also be started directly as a non-root user
(docker run --user 1000:1000, a user: entry in the compose file, Kubernetes runAsUser, or the
TrueNAS app's run_as field). In that case the entrypoint skips chown/gosu and runs directly under
the given UID/GID, with no need for CHOWN/SETUID/SETGID capabilities. Prerequisite: the /data
volume is already owned by that UID/GID (chown it manually or via the TrueNAS ACL).
Start the container. Either with the image from Docker Hub:
curl -O https://raw.githubusercontent.com/xpsony/UmlautAdaptarrEX/main/docker-compose.release.yml docker compose -f docker-compose.release.yml up -dor as a local build (requires a repo checkout):
docker compose up -dOpen the web UI: http://localhost:5007.
Follow logs: docker compose -f docker-compose.release.yml logs -f umlautadaptarrex (or without -f docker-compose.release.yml for the local build). Stop: docker compose ... down.
Update from Docker Hub: docker compose -f docker-compose.release.yml pull && docker compose -f docker-compose.release.yml up -d. Update for local build: docker compose build --pull && docker compose up -d.
Variant 2: docker run (without Compose)
Sufficient if you do not want to clone the repository and just want to run the prebuilt image:
docker run -d \
--name umlautadaptarrex \
--restart unless-stopped \
-p 5005:5005 \
-p 5006:5006 \
-p 5007:5007 \
-v /srv/umlautadaptarrex/data:/data \
-e TZ=Europe/Berlin \
lexfi/umlautadaptarrex:latest
The directory /srv/umlautadaptarrex/data is created automatically on first start and the entrypoint will chown it
to PUID:PGID (default 1000:1000). A manual chown is not needed.
Optional additional -e flags:
PUID=1000/PGID=1000(UID and GID under which the app process runs. Files under./datawill be owned by these IDs). Only takes effect when the container starts as root; with--user,PUID/PGIDare ignored and the app runs directly under the given UID/GID.LOG_LEVEL=info(Pino level:trace,debug,info,warn,error,fatal).
Update: docker pull lexfi/umlautadaptarrex:latest && docker rm -f umlautadaptarrex and re-run the command above.
The data/ volume is preserved.
Variant 3: Unraid Template
The Unraid template for UmlautAdaptarrEX is now officially available in the Community Applications (CA) store: in Unraid, just open Apps, search for "UmlautAdaptarrEX" and install it directly, no template URL required. The template is maintained in a separate repository: xpsony/UmlautAdaptarrEX-Unraid-Template.
Installation instructions, template URL, and field defaults (ports, PUID/PGID, appdata path) are documented in the template repo's README.
Variant 4: TrueNAS App
UmlautAdaptarrEX is available as a community app in the TrueNAS app catalog: apps.truenas.com/catalog/umlautadaptarrex_community. In the TrueNAS UI, go to Apps → Discover Apps, search for "UmlautAdaptarrEX" and install it.
The app is maintained by xopez, many thanks for that.
Variant 5: Bare metal / without Docker
Works on any Linux or macOS host with Node >= 24 and pnpm 11.11.0. The supervisor in
start.mjs handles migration, Fastify (port 5005 + TCP proxy 5006) and Next.js (port
5007); no reverse proxy is required.
git clone https://github.com/xpsony/UmlautAdaptarrEX.git
cd UmlautAdaptarrEX
pnpm install --frozen-lockfile
pnpm prod # build:prod -> prisma migrate deploy -> start:prod
The individual steps as separate scripts (e.g. for CI):
| Script | What it does |
|---|---|
pnpm build:prod |
Builds Next.js (standalone) + Fastify bundle (tsup) with NODE_ENV=production. |
pnpm prisma:deploy |
Applies migrations idempotently to the SQLite DB. |
pnpm start:prod |
Starts the supervisor (migrate -> Fastify -> Next.js child) with prod env. |
Persistence: the data/ directory (SQLite) stays in the repo working tree. For "survives a reboot",
a systemd unit ships under deploy/umlautadaptarrex.service,
including examples for user, WorkingDirectory and hardening (ProtectSystem, ReadWritePaths).
Short version of the install:
sudo cp deploy/umlautadaptarrex.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now umlautadaptarrex
journalctl -u umlautadaptarrex -f
Variant 6: Proxmox VE (LXC, community script)
Works, but currently not accepted into the Proxmox Helper Scripts. The script follows the community-scripts (ProxmoxVED) format and is ready to use. Due to the project's current regulations it cannot be included in the official Proxmox Helper Scripts repo at the moment, so it is provided self-hosted from this fork.
A single command, run on the Proxmox VE host shell, creates an LXC container and installs UmlautAdaptarrEX inside it (self-hosted from this fork, no ProxmoxVED clone required):
bash -c "$(curl -fsSL https://raw.githubusercontent.com/xpsony/UmlautAdaptarrEX/main/proxmox/community-scripts/ct/umlautadaptarrex.sh)"
What the script does:
- Creates a Debian 13 LXC (2 vCPU, 2048 MB RAM for the build, 6 GB disk).
- Installs Node.js 26 + pnpm (via npm), fetches the latest release of
xpsony/UmlautAdaptarrEXand runspnpm build:prod+pnpm prisma:deploy. - Prompts for the three service ports during install (pre-filled with the defaults, press Enter to accept):
- 5007 — web UI + setup wizard (
http://<IP>:5007/setup) - 5005 — public API + indexer routes for the *arrs
- 5006 — Prowlarr TCP proxy (basic auth, set during setup)
- 5007 — web UI + setup wizard (
- Runs the app as a systemd service (
umlautadaptarrex). The SQLite DB lives at/opt/umlautadaptarrex/data/and is preserved across updates.
After it finishes, open the setup in your browser: http://<container-IP>:5007/setup.
Changing ports later: edit /opt/umlautadaptarrex/.env (UMLAUTADAPTARREX_WEBUI_PORT /
_LEGACYAPI_PORT / _PROXY_PORT) and run systemctl restart umlautadaptarrex. An LXC has its own IP,
so there is no host-side port mapping. Details and maintenance notes are in
proxmox/community-scripts/README.md.
Ports
| Port | Service | Purpose |
|---|---|---|
| 5005 | Fastify | Public API, legacy routes (/<apiKey>/<host>/api), WebSocket logs (/ws/logs) |
| 5006 | TCP HTTP proxy | Prowlarr indexer proxy with HTTPS CONNECT tunneling |
| 5007 | Next.js | Web UI |
Ports can be set via environment variables (precedence: branded variable > DB > default):
| Port | Environment variable | Fallback |
|---|---|---|
| 5005 | UMLAUTADAPTARREX_LEGACYAPI_PORT |
5005 |
| 5006 | UMLAUTADAPTARREX_PROXY_PORT |
Setting.proxyPort (DB) |
| 5007 | UMLAUTADAPTARREX_WEBUI_PORT |
5007 |
UMLAUTADAPTARREX_PROXY_PORT overrides the value stored in the database at every start; when set, the proxy-port field under Settings → Advanced is shown read-only. Each variable sets both the in-container bind port and the published host port (the compose mapping uses the same value on both sides). See .env.example for a template.
The data/ DB is mounted into the container and contains the entire configuration.
Architecture
How UmlautAdaptarrEX sits between the *arrs, Prowlarr and the indexers.
Mode 1: Prowlarr indexer proxy (recommended, port 5006)
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ Sonarr │ │ Radarr │ │ Lidarr │ │ Readarr │
└────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘
│ │ │ │
│ Newznab/Torznab API (with *arr API key)│
└─────────────┼─────────────┼─────────────┘
▼
┌───────────┐
│ Prowlarr │ Indexer manager
└─────┬─────┘
│ HTTP (indexer scheme changed from https → http)
│ HTTP proxy: indexer proxies → "UmlautAdaptarrEX"
▼
┌──────────────────────────────────┐
│ UmlautAdaptarrEX │
│ ───────────────────────────── │
│ :5006 TCP proxy (Basic auth) │◀── HTTP CONNECT tunnel for https targets
│ :5005 Fastify API + legacy │
│ :5007 Web UI (Next.js) │
│ │
│ Pipeline per request: │
│ 1. Parse URL (t=search/...) │
│ 2. Title lookup via providers │
│ (pcjones │ TVDB │ TMDB │ │
│ db-cache, order │
│ configurable) │
│ 3. Expand query with title │
│ variants (umlauts, aliases, │
│ language plugin maps) │
│ 4. Request to real indexer │
│ 5. Rewrite XML response │
│ (title fix, rename, tags) │
│ │
│ Persistence: SQLite (Prisma) │
│ • Settings, instances, apiKey │
│ • Title cache, sync runs │
│ • Request & rename history │
└──────────────┬───────────────────┘
│ HTTPS (outbound)
▼
┌────────────┐
│ Indexer │ Newznab/Torznab,
│ (Usenet/ │ NZB Hydra, ...
│ Torrent) │
└────────────┘
Mode 2: Direct as indexer (without Prowlarr proxy, port 5005)
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Sonarr │ │ Radarr │ │ Lidarr │ ...
└────┬─────┘ └────┬─────┘ └────┬─────┘
│ │ │
│ Indexer URL entered as: │
│ http://<host>:5005/<apiKey>/<indexer-host>
└───────────────┼───────────────┘
▼
┌──────────────────────────────────┐
│ UmlautAdaptarrEX │
│ Legacy route │
│ /<apiKey>/<host>/api?t=... │
│ (same pipeline as above) │
└──────────────┬───────────────────┘
│ HTTPS
▼
┌────────────┐
│ Indexer │
└────────────┘
Key points:
- 5006 is the only port Prowlarr talks to directly (HTTP proxy with Basic auth, default user
UmlautAdaptarr). - 5005 carries both the admin API and the legacy route
/<apiKey>/<host>/apifor direct mode. - 5007 is only the UI; it reverse-proxies
/api/*to 5005 at runtime (src/proxy.ts).
Configuration in Prowlarr (recommended)
Recommended method, because there is no speed loss with multiple indexers.
Start UmlautAdaptarrEX and walk through the setup in the web UI (create Sonarr/Radarr/Lidarr/Readarr instances).
In Prowlarr: Settings → Indexers → Indexer Proxies → Add (HTTP)
- Name:
UmlautAdaptarrEX HTTP Proxy - Host: container name (
umlautadaptarrex) or host IP - Port:
5006 - Tag:
umlautadaptarrex - Username/Password: use the credentials set in the setup wizard (step "Proxy"). The default user is
UmlautAdaptarrand the password is auto-generated. Both values are visible at any time under Settings → Proxy in the web UI. If UmlautAdaptarrEX creates the Prowlarr indexer proxy configuration automatically (setup wizard, step "Prowlarr install"), the credentials are stored directly.
- Name:
For all indexers that should use the proxy:
- Add tag
umlautadaptarrex - Change the URL scheme from
httpstohttp, only then can UmlautAdaptarrEX intercept the requests locally. Outgoing requests to the indexer remainhttps, of course.
The indexer-patch dialog is faster: instead of touching each indexer in Prowlarr by hand, UmlautAdaptarrEX lists your Prowlarr indexers and performs both steps (set the tag +
https→http) for the indexers you select. The dialog is part of the setup wizard and is available any time under Settings → Prowlarr → "Patch indexers". "Select all" is the default; de-selecting an already-patched indexer reverts both the tag and the scheme. The dialog also explains why the switch is needed and that the connection to the indexer on the internet stayshttps(no unencrypted traffic leaves your system).- Add tag
Run Test All Indexers. If any
httpsURLs remain, a warning appears in the live logs.
Configuration without Prowlarr proxy
Note: not yet tested
With only a few indexers or without Prowlarr, enter the API URL per indexer directly in Sonarr/Radarr/Lidarr/Readarr:
http://<host>:5005/<apiKey>/<indexer-host>
The API key is set as usual. The apiKey for UmlautAdaptarrEX is created in the web UI.
The full HTTP API (admin, auth, legacy, WebSocket, TCP proxy) is documented in docs/api.md.
The release-rename pipeline is described in docs/renaming.md. For users who want to fork the
project and re-flag it under their own GitHub owner / Docker Hub namespace, the guide is in
docs/forking.md, including scripts/rebrand.sh for the static defaults and the three runtime
levers (DOCKERHUB_IMAGE, UMLAUTADAPTARREX_IMAGE, NEXT_PUBLIC_GITHUB_OWNER / NEXT_PUBLIC_GITHUB_REPO).
Local Development
pnpm install
cp .env.example .env
pnpm prisma:migrate
pnpm dev
# Web UI: http://localhost:5007
# Fastify API: http://localhost:5005
# Prowlarr proxy: tcp://localhost:5006
Development Container (VS Code)
For a reproducible dev environment, you can use the included devcontainer:
- Open the repository in VS Code.
- Run
Dev Containers: Reopen in Container. - After the container has started:
pnpm dev.
The container ships Node 26 (dev and production image) + pnpm 11.11.0, forwards ports 5005/5006/5007 and sets recommended VS Code
extensions/settings for TypeScript, Next.js, Prisma, Tailwind, ESLint/Prettier, Vitest and Playwright.
After pnpm dev you reach the UI on port 5007 and the API on port 5005 (directly or via VS Code port
forwarding). The TCP proxy is reachable on port 5006.
Tests
pnpm test # vitest (unit + integration)
pnpm test:e2e # playwright (baseURL = http://localhost:5005)
pnpm typecheck
pnpm lint
Project Structure
src/
├─ app/ # Next.js App Router (web UI)
├─ components/ # React + shadcn UI
├─ server/ # Fastify gateway, TCP proxy, sync workers, logging
├─ domain/ # Framework-free core
│ ├─ normalization/ # Title normalization
│ ├─ variations/ # Title variants
│ ├─ matching/ # Release matching
│ ├─ plugins/ # Language plugins (DE umlauts, SE umlauts, FR accents)
│ └─ xml/ # Newznab/Torznab XML rewriting
├─ providers/ # External title providers (pcjones, TVDB, TMDB, db-cache)
├─ arr/ # Sonarr/Radarr/Lidarr/Readarr/Prowlarr clients
├─ schemas/ # Zod schemas (shared client/server)
├─ messages/ # i18n (de.json, en.json)
└─ lib/ # db, auth, secrets, legacy-env, i18n, utils
Stack
- Node 24+ (production image: Node 26) / TypeScript / pnpm 11
- Next.js 16 / React 19 / Tailwind 4 / shadcn (new-york)
- Fastify 5 / Prisma 7 / SQLite (better-sqlite3)
- Zod 4 / next-intl / @tanstack/react-query
- Vitest 4 / Playwright
Contact & Support
- GitHub issues for bug reports and feature requests
- UsenetDE Discord →
#umlautadaptarr
Credits
Based on the idea and logic of PCJones/UmlautAdaptarr.
Thanks to xopez for the TrueNAS community app.
Disclaimer
UmlautAdaptarrEX is a technical compatibility proxy. The software does not download any content itself, does not circumvent any technical protection measures (DRM) and does not establish connections to indexers that were not previously configured in the *arrs or in Prowlarr.
The project is intended exclusively for use with legal sources, such as your own backup copies, regularly subscribed Usenet or tracker services, public-domain works, and content with explicit licensing by the rights holder. Responsibility for lawful use of the *arrs and the connected indexers lies entirely with the respective operator.
The authors assume no liability for any unintended or unlawful use. In Germany this includes the Copyright Act (UrhG); comparable rules exist in other countries. The software is provided "as is", without any warranty (see MIT license).
License
MIT
Media gallery
1 / 2Install UmlautAdaptarrEX on Unraid in a few clicks.
Find UmlautAdaptarrEX in Community Apps on your Unraid server, review the template, and click Install. Unraid handles the Docker app or plugin setup from the published template.
Categories
Download Statistics
Related apps
Explore more like this
Explore allDetails
lexfi/umlautadaptarrex:latestRuntime arguments
- Web UI
http://[IP]:[PORT:5007]/- Network
bridge- Shell
sh- Privileged
- false
Template configuration
HTTP port for the Next.js web UI. Open this in your browser to reach the setup wizard and admin panel. IMPORTANT: the host port and the container port MUST be identical (1:1 mapping). To use a non-default port, change this value AND set the matching UMLAUTADAPTARREX_WEBUI_PORT variable below to the SAME number.
- Target
- 5007
- Default
- 5007
- Value
- 5007
Fastify API + WebSocket port. This is the URL you point your *Arr instances at (e.g. http://unraid-ip:5005/apikey/sonarr/api). Also serves /api/admin, /api/auth, /titlelookup and /ws/logs. IMPORTANT: the host port and the container port MUST be identical (1:1 mapping). To use a non-default port, change this value AND set the matching UMLAUTADAPTARREX_LEGACYAPI_PORT variable below to the SAME number.
- Target
- 5005
- Default
- 5005
- Value
- 5005
TCP HTTP-CONNECT proxy for Prowlarr indexers. Configure this as Prowlarr's HTTP proxy so indexer responses get rewritten on the fly. IMPORTANT: the host port and the container port MUST be identical (1:1 mapping). To use a non-default port, change this value AND set the matching UMLAUTADAPTARREX_PROXY_PORT variable below to the SAME number.
- Target
- 5006
- Default
- 5006
- Value
- 5006
In-container bind port for the Fastify API. MUST match the 'API Port' mapping above (1:1: host port = container port = this value). The image reads ONLY this branded variable -- the legacy PORT fallback was removed in 1.2.2. Leave at 5005 unless you also remapped the 'API Port' above to the same number.
- Target
- UMLAUTADAPTARREX_LEGACYAPI_PORT
- Default
- 5005
- Value
- 5005
In-container bind port for the Next.js Web UI. MUST match the 'Web UI Port' mapping above (1:1: host port = container port = this value). The image reads ONLY this branded variable -- the legacy WEB_PORT fallback was removed in 1.2.2. Leave at 5007 unless you also remapped the 'Web UI Port' above to the same number.
- Target
- UMLAUTADAPTARREX_WEBUI_PORT
- Default
- 5007
- Value
- 5007
In-container bind port for the Prowlarr HTTP-CONNECT proxy. MUST match the 'Indexer Proxy Port' mapping above (1:1: host port = container port = this value). When set, it overrides the value stored in the database on every start and the Settings UI shows the proxy port read-only. Leave at 5006 unless you also remapped the 'Indexer Proxy Port' above to the same number.
- Target
- UMLAUTADAPTARREX_PROXY_PORT
- Default
- 5006
- Value
- 5006
Persistent storage for the SQLite database (umlautadaptarrex.db) and the title-cache. Do NOT delete - it contains all your *Arr connections, API keys and matching state. Ownership is fixed automatically on container start (see PUID/PGID).
- Target
- /data
- Default
- /mnt/user/appdata/umlautadaptarrex
- Value
- /mnt/user/appdata/umlautadaptarrex
UID the app runs as. Default 99 = Unraid `nobody`, which matches the rest of your appdata shares. The entrypoint chowns /data to PUID:PGID on every start.
- Default
- 99
- Value
- 99
GID the app runs as. Default 100 = Unraid `users` group.
- Default
- 100
- Value
- 100
IANA timezone (e.g. Europe/Berlin, UTC, America/New_York). Affects timestamps in logs and the Web UI.
- Default
- Europe/Berlin
- Value
- Europe/Berlin
Pino log level: trace, debug, info, warn, error, fatal.
- Default
- info
- Value
- info