Subtitler
Experimental · early build

Every title,
subtitled.

A self-hosted tool that generates the subtitles your media library is missing. It uses preferred audio tracks for timing and calls OpenAI only when it has to — writing clean, standard SRT files. Sonarr and Radarr tell it where your media lives.

Audio-first Dry-run by default GPL-3.0
How it works

Find the gaps, fill only what's missing

Subtitler scans your library, checks what subtitles already exist, and creates only what's absent — doing the least expensive thing each time. It leans on Sonarr and Radarr to locate files, so there's no media path to configure twice.

1

Locate media

Asks Sonarr and Radarr for the paths of every file — no separate library config.

2

Inspect

Checks existing sidecars and embedded subtitle streams against your required languages.

3

Extract or generate

Transcribes the preferred source audio first, then translates those timed cues when needed.

4

Write

Saves standard SRT sidecars next to the video and records state for retries.

Why it stays out of your way

Built for set-and-forget homelabs

Generates what's missing

Transcribes audio with OpenAI and writes an SRT only for the languages your media lacks.

Audio-first

Existing sidecars are respected, while generated subtitles stay tied to the preferred audio track.

Controlled rollout

Dry-run, missing_only, and a per-scan job cap keep first runs cheap and safe.

Fits your library

Integrates with Sonarr and Radarr to find media, then drops .srt files beside each video.

Quickstart

Docker-native, ffmpeg included

The image bundles the Go binary plus ffmpeg and ffprobe. Copy the examples, add your keys, validate in dry-run, then start the daemon.

terminal
# configure
cp config.example.yaml config.yaml
cp .env.example .env

# validate safely (dry-run is on by default)
docker compose --env-file .env \
  -f docker-compose.example.yaml \
  run --rm subtitler doctor -config /etc/subtitler/config.yaml

# start the daemon
docker compose --env-file .env \
  -f docker-compose.example.yaml up -d