From 1401e9e00ffc5f3daccad8d10d2323753ce6e712 Mon Sep 17 00:00:00 2001 From: Miguel Palhas Date: Mon, 24 Aug 2026 21:37:37 +0100 Subject: [PATCH] =?UTF-8?q?docs(arr):=20add=20DESIGN.md=20=C2=A715=20subti?= =?UTF-8?q?tles=20contract?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Records the subtitle decisions settled during Subtitles milestone planning: global wanted set (pt + en), embedded-track extraction, providers, ranking, translation backends, sidecar naming, alass sync, budgets, and stated non-goals. Points §13 item 9 at §15 and adds arr-subs to the crate lists. Closes-Issue: #183 Co-Authored-By: Claude Fable 5 --- CLAUDE.md | 1 + DESIGN.md | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 88 insertions(+), 1 deletion(-) diff --git a/CLAUDE.md b/CLAUDE.md index db766c0..906b5cf 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -18,6 +18,7 @@ crates/ ├── arr-indexer/ Torznab via Prowlarr ├── arr-dl/ Transmission RPC ├── arr-probe/ ffprobe wrapper +├── arr-subs/ subtitle providers, translation, sync ├── arr-db/ sqlx + migrations ├── arr-api/ axum + OpenAPI ├── arr-compat/ Radarr/Sonarr v3 shim for Jellyseerr diff --git a/DESIGN.md b/DESIGN.md index 09e4f0e..c32648d 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -666,6 +666,7 @@ arr-meta TMDB client arr-indexer Torznab via Prowlarr arr-dl Transmission RPC arr-probe ffprobe wrapper +arr-subs subtitle providers, translation, sync arr-db sqlx + migrations arr-api axum + OpenAPI arr-compat Radarr/Sonarr v3 shim for Jellyseerr @@ -748,7 +749,7 @@ previous one. grabbing, derived status. 7. **Owners and notifications** — tags, per-person ntfy topics, filtered views. 8. **Jellyseerr compat** — `arr-compat`. -9. **Subtitles** — replaces Bazarr. Out of scope for this document. +9. **Subtitles** — replaces Bazarr. See §15. Movies before TV because TV adds season packs, air-date calendars and per-episode state on top of an otherwise identical pipeline. Doing it second @@ -768,3 +769,88 @@ means that pipeline is already proven. RSS lane obeys the same guard — it skips packs for any season with episodes on disk. Whether a re-grab is ever wanted remains unresolved and deliberately deferred. + +## 15. Subtitles + +Replaces Bazarr. Phase 9 in §13; the `arr-subs` crate in §11. + +**Wanted set.** Global, not per root. Two languages are separately wanted for +every media file: Portuguese — pt-PT preferred, pt-BR accepted — and English. +A file is satisfied for a language when a subtitle in it exists, embedded or as +a sidecar. This is deliberately unlike §5.2's audio rules, which attach to a +root: subtitles carry no blacklist there and none here. pt-BR subtitles are +always fine. + +**Embedded tracks.** An embedded subtitle track satisfies its language. +Text-format tracks (`subrip`, `ass`, `mov_text`) are additionally extracted to +a sidecar SRT, because an extracted track is a legal translation source. +Image-format tracks (PGS on BluRay, VobSub on DVD) carry bitmaps, not text: +they satisfy viewing but can never feed a translator, and arr does not OCR +them. `arr-probe` already reports subtitle tracks with resolved languages; the +format is the new fact it must carry. + +**Providers.** OpenSubtitles.com and Podnapisi, behind one trait. + +**Ranking.** A `moviehash` match wins outright. Then an exact release-name +match, then same release group or same source, then uploader rating and +download count as tiebreakers. Every rejected candidate names the rule that +killed it, so the manual view described in §9.3 works unchanged for subtitles. + +**Forced and SDH.** A forced track covers only foreign-language lines and +on-screen signs; it never satisfies a want and arr never goes looking for one. +An SDH track is complete and satisfies, ranked below a plain subtitle. + +**Translation.** When no provider has a wanted language, arr translates +immediately — there is no waiting window. The source is an existing subtitle: +a downloaded one, or one extracted from a text-format embedded track. Being +able to translate from an embedded track is a deliberate improvement on +Bazarr, which cannot. + +**Translation backends.** Pluggable, each behind its own cargo feature: an +OpenAI-compatible HTTP endpoint, DeepL, Google Translate, and a generic remote +command driven by a configured template (`ssh box claude -p` is one instance +of that template, not a backend of its own). The engine in use is a database +setting, so switching does not need a rebuild when the feature is compiled in. +Subtitles are sent in batches of cues; a reply whose cue count or numbering +does not match the batch is rejected. Timing data never leaves arr. + +**No upgrade loop.** Once a language is satisfied — by a machine translation +too — arr stops working on it. A real subtitle appearing later does not +replace anything. Replacement is a manual action from the UI. This is §5.4's +rule applied to subtitles. + +**On disk.** Sidecars live next to the video inside the §7.4 title folder, +named `