# Subtitle process — changelog ## v1 — 2026-05-09 Initial recipe. Drafted while running on American Dad. Distilled from doc 03-subtitles.md (Futurama work) and the actual AD run. Approach: Jellyfin RemoteSearch/Subtitles/eng → pick best non-HI/non-MT match via Python filter → POST download → docker cp metadata cache → media folder → delete cache dupes → validation refresh. Scope: works on shows whose library season/episode numbering matches OpenSubtitles' indexed numbering. Verified passing on AD S01 (7/7 episodes). ### Known break — added 2026-05-09 same day After S01 passed, S02 returned 0 results for every episode probed (E01, E02, E08, E13). Quota was fine (13 downloads remaining). Cause: > Jellyfin metadata for American Dad uses **Hulu/DSP season ordering** > (S1=7, S2=16, S3=19, S4=16). OpenSubtitles indexes by **Fox original-airing > order** where S1 has 23 episodes. The plugin queries OS by > `(parent_imdb_id, season_number, episode_number)`. For library S02E01 > "Bullocks to Stan" the plugin sends `S=2,E=1` but OS catalogues that > episode as `S=1,E=8`. Result: 0 hits. Each library episode has its own correct per-episode IMDB id (e.g. `tt0511631` for "Bullocks to Stan") which would resolve directly via OS REST `imdb_id=` parameter, but the plugin doesn't expose that path. ## v2 — 2026-05-09 Approach **A** chosen: direct OpenSubtitles REST API, per-episode `imdb_id` lookup, bypass the Jellyfin plugin entirely. New helper at `lib/sub-rest-fetch.py`. - API key file: `~/.config/arrflix-opensubtitles-api.txt` (mode 600) - Account: `Caveman5` (free tier, 20 downloads/day) - Saves sidecars directly to nullstone media folder via `ssh ... cat >` - No more docker-cp from `/config/metadata/library` cache (plugin path) Recipe upgrade: - Step 4 swaps `lib/sub-fetch.sh` → `lib/sub-rest-fetch.py` for shows with non-standard season ordering. - Picker logic identical: filter HI/MT/AI/Forced (renamed `foreign_parts_only` in OS REST), prefer 23.976fps, sort by `download_count` desc. ### v2 known quirks - **OpenSubtitles `/download` endpoint rejects urllib** — consistent HTTP 503 via Python `urllib.request`, HTTP 200 via `curl` with same headers/body. `_curl()` shim added; all OS API calls go through it. **Each 503 still consumes 1 download-quota slot**, so this had to be fixed before retrying large batches. - `download_count` of `0` and `fps` of `0.0` appear on some catalogue entries; treat as informational, not exclusionary. - Some hits have `file_name` mismatching the `imdb_id` searched (OS metadata drift). Recipe Step 6 visual-sync check is the catch. ### v2 known limits - Free-tier 20/day still in force (REST and plugin share the counter). - Recipe Step 6 (sync verification) is still manual — no automated check that the picked .srt actually aligns with audio.