⚠️ AI-Generated Code - Review before production use. Test withDRY_RUN=truefirst. Backup your databases.
Automatic quality profile management for Radarr & Sonarr based on original language
Perfect for multilingual libraries where you want original audio for some languages (English, German) but dubbed audio for foreign content (Korean, Japanese, French, etc.).
What you need:
- Radarr v3+ and/or Sonarr v3+ (v4 recommended)
- Recyclarr already running in your docker compose stack
- Docker & Docker Compose
What it does:
- Creates two quality profiles:
Original PreferredandDub Preferred - Automatically assigns profiles based on original language
- Tags foreign content with
prefer-dubfor easy filtering - (Optional) Tags media based on actual audio tracks present in files
Using pre-built image (recommended):
Choose your version:
latest- Stable releases (recommended for production)v1.0.0- Specific version (pin for stability)develop- Development builds (testing/bleeding edge)
services:
langarr:
image: ghcr.io/qudiqudi/langarr:latest # or :v1.0.0 or :develop
container_name: langarr
ports:
- "5678:5678" # For webhook support
environment:
- RADARR_URL=${RADARR_URL}
- RADARR_API_KEY=${RADARR_API_KEY}
- SONARR_URL=${SONARR_URL}
- SONARR_API_KEY=${SONARR_API_KEY}
- OVERSEERR_URL=${OVERSEERR_URL} # Optional
- OVERSEERR_API_KEY=${OVERSEERR_API_KEY} # Optional
volumes:
- ./langarr-config:/config:ro
networks:
- your_network_name
restart: unless-stoppedBuilding from source:
git clone https://github.com/qudiqudi/langarr.git
cd langarrThen use build: ./langarr/language-tagger instead of image: in docker-compose.yml.
New to Recyclarr? Copy the full example:
cp recyclarr/recyclarr-full-example.yml /path/to/recyclarr/config/recyclarr.ymlExisting config? See recyclarr/README.md to merge profiles.
Sync profiles:
docker exec recyclarr recyclarr syncVerify in Radarr/Sonarr → Settings → Profiles
Create ./langarr-config/config.yml:
radarr:
main:
enabled: true
original_languages:
- en # English
- de # German
original_profile: Original Preferred
dub_profile: Dub Preferred
sonarr:
main:
enabled: true
original_languages:
- en
- de
original_profile: Original Preferred
dub_profile: Dub Preferred
webhook:
enabled: true
port: 5678
auth_token: "your-secure-random-token-here" # REQUIRED for securitydocker compose up -d langarr
docker logs -f langarr# Required (usually already defined)
RADARR_URL=http://radarr:7878
RADARR_API_KEY=your-api-key
SONARR_URL=http://sonarr:8989
SONARR_API_KEY=your-api-key
# Optional: Testing
DRY_RUN=true # Preview changes without applyingFor 4K/Anime instances, add to config:
radarr:
main:
enabled: true
# ...
4k: # Matches RADARR_4K_URL env var
enabled: true
original_languages:
- enTo only process monitored items (skip unmonitored):
radarr:
main:
only_monitored: true # Default: falseAutomatically set correct profiles on requests before they reach Radarr/Sonarr.
1. Add environment variables:
OVERSEERR_URL=http://overseerr:5055
OVERSEERR_API_KEY=your-api-key2. Enable in config.yml:
overseerr:
main:
enabled: true
radarr_servers:
0: main # Overseerr server ID 0 → langarr radarr.main
sonarr_servers:
0: mainFinding Server IDs:
- Settings → Services → click server → check URL
- Example:
/settings/services/radarr/0→ ID is0 - Note: Seerr uses 0-based IDs (starts at 0, not 1)
For instant profile updates with auto-approve enabled:
1. Enable webhook in config.yml:
webhook:
enabled: true
port: 5678
auth_token: "your-secure-random-token-here" # REQUIRED for security2. Expose port in docker-compose.yml:
services:
langarr:
ports:
- "5678:5678"3. Configure in Seerr/Overseerr:
- Settings → Notifications → Webhook
- URL:
http://langarr:5678/webhook - Authorization Header:
your-secure-random-token-here(must match config.yml auth_token)- Note: Enter just the token value, not
X-Auth-Token:orBearer - The server accepts:
Authorization,Bearer <token>, orX-Auth-Tokenformats
- Note: Enter just the token value, not
- Enable: Media Auto Approved + Media Pending
How it works:
User requests → Webhook fires → Langarr updates profile in Radarr
→ Triggers search → Downloads with correct quality ✅
Without webhook: Profiles updated every 24 hours (still works, just slower)
- Original language matches config (
en,de) →Original Preferred - Foreign language (
ko,ja,fr) →Dub Preferred+prefer-dubtag
- Recyclarr syncs quality profiles with custom formats
- Langarr assigns profiles based on original language
- Runs every 24 hours to tag new content
- (Optional) Webhook for instant updates on new requests
Tag media based on actual audio tracks in downloaded files, not just original language metadata.
Use case: Tag all movies/shows that have a German audio track, regardless of original language. Useful for filtering in Plex/Jellyfin.
Add audio_tags to your instance config in config.yml:
schedule:
interval_hours: 24
audio_scan_interval_hours: 24 # Optional: separate interval for audio scanning
radarr:
main:
# ...existing config...
audio_tags: # Add this section
- language: de # ISO code or full name
tag_name: german-audio
- language: en
tag_name: english-audio
sonarr:
main:
# ...existing config...
audio_tags:
- language: de
tag_name: german-audio- Fetches
mediaInfo.audioLanguagesfrom each downloaded file - Falls back to
languagesfield (parsed from release name) if mediaInfo is empty - Parses languages (handles "English / German" format)
- Adds tags when language is detected
- Removes tags if language no longer present (file replaced)
For Sonarr: Tags the series only if all episodes have the audio track.
| Feature | Profile Assignment | Audio Tagging |
|---|---|---|
| Data source | TMDB original language | Actual file mediaInfo |
| When | Before/during download | After download |
| Purpose | Quality profile selection | Filtering/organization |
docker exec langarr env DRY_RUN=true RUN_MODE=once python3 /app/arr-language-tagger.pyProfiles not appearing?
docker exec recyclarr recyclarr sync
# Check Radarr/Sonarr → Settings → ProfilesItems not being tagged?
docker logs langarr
# Verify profile names match exactlyWebhook not working?
docker logs -f langarr
# Check for "Received webhook" messages
# Verify port 5678 is exposedLanguage detection issues?
- Sonarr v4+ required for full language support
- Check if content has language metadata in Radarr/Sonarr
-
Find your language: TRaSH Guides
- French, Spanish, Italian, Portuguese, Japanese, etc.
-
Update recyclarr template:
include:
- template: radarr-custom-formats-hd-bluray-web-french # Replace 'german'-
Replace custom format IDs: Follow language-specific IDs from TRaSH Guides
-
Update language codes:
original_languages:
- en
- fr # Your languageShare your config! Submit a PR to help others.
Langarr follows Semantic Versioning:
- Production: Use
latesttag or pin to specific versionv1.0.0 - Testing: Use
developtag for bleeding-edge features - Releases: Tagged as
v1.0.0,v1.1.0, etc.
Docker image tags:
ghcr.io/qudiqudi/langarr:latest # Latest stable release
ghcr.io/qudiqudi/langarr:v1.0.0 # Specific version
ghcr.io/qudiqudi/langarr:develop # Development builds- Recyclarr - Quality profile management
- TRaSH Guides - Custom formats
- Built with AI assistance (Claude Code)
MIT