Four research-grade docs covering everything four parallel agents found while fixing the live Futurama deploy: - 01-artwork-and-images: root-cause of missing posters (EnableInternetProviders=false + wrong fetcher names 'The Movie Database' vs 'TheMovieDb' in 10.10.x). Fixed in-place. Doc covers image-type matrix, scraper-to-imagetype map, refresh API. - 02-metadata-and-titles: Futurama series had empty ProviderIds; locked to TMDB 615 (1999 original, not 2023 reboot). All 44 eps now have proper titles + Polish overviews. Doc covers filename regex, Identify flow, language cascade. - 03-subtitles: installed OpenSubtitles plugin v20.0.0.0 (v21+ needs JF 10.11 ABI). User must add opensubtitles.com creds. Doc covers sidecar naming, embedded extraction, per-user prefs. - 04-theming-and-users: applied ElegantFin v25.12.31 via Branding API. Doc covers theme rationale, multi-user policy template, SyncPlay, friend playbook.
15 KiB
03 — Subtitles on Jellyfin (tv.s8n.ru)
Last updated: 2026-05-08
Server: Jellyfin 10.10.3 (X64) on nullstone, container jellyfin
URL: https://tv.s8n.ru
Use-case: Futurama (44 episodes), Polish audio, no embedded subs, automatic English subtitles required.
1. How Jellyfin resolves subtitles (priority order)
When a client requests playback, Jellyfin presents subtitle streams from three sources, in this order:
- Embedded — subtitle tracks muxed inside the container (
mkv,mp4, etc.). Codecs:srt,ass,ssa,pgs,vobsub,dvd_subtitle,mov_text. Always available. - Sidecar (external) —
.srt,.vtt,.ass,.ssa,.subfiles placed next to the video on disk. Discovered automatically on library scan. - Downloaded — fetched at scan time (or via "Find subtitles" UI) by a subtitle provider plugin (OpenSubtitles, etc.). Saved as a sidecar when
SaveSubtitlesWithMedia=true.
A user's SubtitleMode setting (per-user) decides what is auto-selected at playback:
None— never load subtitles by default.Default— load only if markedIsDefaultin the file.Always— always load if any track inSubtitleLanguagePreferenceexists.Smart— load only when audio language differs from the user's audio preference.OnlyForced— load only forced tracks.
The s8n user is set to Always + preference eng (see § 6).
2. Current Futurama state (verified 2026-05-08)
Library: TV Shows (Id 767bffe4f11c93ef34b805451a696a4e, path /media/tv)
Episodes: 44 (Futurama.s01e01.pl.mkv … s01e44? — actually s01–s07 PL dub split)
Container: mkv
Audio: ac3 stereo 192k, language=pol
Video: h264 1080p (the eng tag on the video stream is a mux artefact, not English audio)
Subs: 0 embedded, 0 sidecar — verified on episodes 1–5; assume same for all 44
Result: every episode needs subs from OpenSubtitles or sidecars dropped on disk. There is nothing to extract — mkvextract/ffmpeg would yield nothing.
3. OpenSubtitles plugin — what is installed, what is pending
3.1 Installed (done by automation 2026-05-08)
| Item | Value |
|---|---|
| Plugin | Open Subtitles v20.0.0.0 |
| GUID | 4b9ed42f-5185-48b5-9803-6ff2989014c4 |
| Status | Active (after docker restart jellyfin, ~5 s downtime) |
| Repo | Official https://repo.jellyfin.org/files/plugin/manifest.json (already configured) |
| API endpoint | https://api.opensubtitles.com/api/v1 (REST, NOT the legacy XML-RPC at .org) |
| API key | Embedded in the plugin binary — user does NOT supply one |
3.2 Why v20 and not v24
| Plugin version | targetAbi | Compatible with 10.10.3? |
|---|---|---|
| v24, v23, v22, v21 | 10.11.x | NO — ABI too new, will not load |
| v20 | 10.9.0.0 | YES — installed |
| v19 and older | 10.8.x | yes but lacks recent fixes |
When the server is upgraded to 10.11.x, switch to v24 via:
curl -s -X POST -H "X-Emby-Token: $TOKEN" \
"https://tv.s8n.ru/Packages/Installed/Open%20Subtitles?AssemblyGuid=4b9ed42f-5185-48b5-9803-6ff2989014c4&Version=24.0.0.0&RepositoryUrl=https%3A%2F%2Frepo.jellyfin.org%2Ffiles%2Fplugin%2Fmanifest.json"
docker restart jellyfin
3.3 The .com vs .org distinction (READ THIS)
OpenSubtitles split into two services in 2021:
- opensubtitles.org — legacy site, legacy XML-RPC API. Old Jellyfin plugin (v16 and below) used this. DEAD for new code.
- opensubtitles.com — new site, new REST API. Jellyfin plugin v17+ (including the v20 we have) uses this exclusively.
User accounts: an opensubtitles.org account does NOT automatically work on .com. Existing .org users must:
- Visit https://www.opensubtitles.com/en/users/sign_up.
- Sign up with the same email — the system will offer to import the .org account.
- Reset password (mandatory; the .org password hash is incompatible).
User does NOT need to obtain an API key. The plugin embeds its own key (verified by reading OpenSubtitlesPlugin.ApiKey in RequestHandler.cs of v20). Free accounts get 20 downloads/day; VIP accounts get more.
3.4 Pending — user supplies credentials
After signup at opensubtitles.com, save creds via API:
TOKEN=*redacted*
USER='your-opensubtitles-com-username'
PASS='your-opensubtitles-com-password'
# 1. Validate (returns 200 on success, 401 on bad creds)
curl -s -X POST -H "X-Emby-Token: $TOKEN" -H "Content-Type: application/json" \
-d "{\"Username\":\"$USER\",\"Password\":\"$PASS\"}" \
"https://tv.s8n.ru/Jellyfin.Plugin.OpenSubtitles/ValidateLoginInfo" -w "\nHTTP %{http_code}\n"
# 2. Persist into plugin config
curl -s -X POST -H "X-Emby-Token: $TOKEN" -H "Content-Type: application/json" \
-d "{\"Username\":\"$USER\",\"Password\":\"$PASS\",\"CredentialsInvalid\":false}" \
"https://tv.s8n.ru/Plugins/4b9ed42f-5185-48b5-9803-6ff2989014c4/Configuration" -w "\nHTTP %{http_code}\n"
Or via UI: Dashboard → Plugins → Open Subtitles → Settings.
A failed validate currently returns {"Message":"Error, invalid username/password failed:5 remaining:5"} HTTP 401 — the embedded API key is fine, only the user creds are missing.
4. Library + user configuration (already applied)
4.1 Library options — TV Shows (and Movies)
POST /Library/VirtualFolders/LibraryOptions was issued with:
{
"Id": "767bffe4f11c93ef34b805451a696a4e",
"LibraryOptions": {
"SubtitleDownloadLanguages": ["eng"],
"RequirePerfectSubtitleMatch": false,
"SkipSubtitlesIfAudioTrackMatches": true,
"SkipSubtitlesIfEmbeddedSubtitlesPresent": false,
"SaveSubtitlesWithMedia": true,
"AllowEmbeddedSubtitles": "AllowAll"
}
}
Effect:
SubtitleDownloadLanguages: ["eng"]— primary trigger. Any new scan or "Refresh metadata" will fetch English subs for items lacking them.RequirePerfectSubtitleMatch: false— accept good-match subs even when filename hashes don't line up (Polish-dubFuturama.s01e01.pl.mkvwill not byte-match an English .srt anywhere on the planet).SkipSubtitlesIfAudioTrackMatches: true— never fetch a language already present as an audio track (no English audio here, so no effect; safe to leave on).SaveSubtitlesWithMedia: true— write.eng.srtnext to the.mkvinstead of caching in the metadata folder. Survives library wipes and is portable.
4.2 Per-user playback prefs — user s8n
POST /Users/2be0f0d3fe3a45dc9298138a15a01925/Configuration:
{
"AudioLanguagePreference": "pol",
"SubtitleLanguagePreference": "eng",
"SubtitleMode": "Always"
}
Result: every Futurama episode auto-plays Polish audio + auto-loads English subs.
Other users (if any) need the same change individually — there is no global "default new user" subtitle prefs in 10.10.x; set on each user.
5. Triggering download for the existing 44 episodes
Adding SubtitleDownloadLanguages does NOT retroactively fetch subs for items already scanned. After credentials are saved, force a search:
5.1 Single episode (test path — episode Futurama.s01e01.pl)
EP=2b73bc176fbf8a02bb9bea9015ec13c6
# Query providers
curl -s -H "X-Emby-Token: $TOKEN" \
"https://tv.s8n.ru/Items/$EP/RemoteSearch/Subtitles/eng" | jq .
# Returns array of SubtitleInfo objects: Id, ProviderName, Format, Comment, IsHashMatch, ...
# Pick one, e.g. SUBID = first result's Id
SUBID="opensubtitles_..."
# Download + save next to media
curl -s -X POST -H "X-Emby-Token: $TOKEN" \
"https://tv.s8n.ru/Items/$EP/RemoteSearch/Subtitles/$SUBID" -w "HTTP %{http_code}\n"
# 204 = saved. File appears as Futurama.s01e01.pl.eng.srt next to the mkv.
While unauthenticated, RemoteSearch returned [] — confirms credentials are the only blocker.
5.2 All 44 — refresh metadata for the whole series
Easiest is a series-level refresh once creds are entered:
SERIES=156e57437f795e5c8cd80fc98bafaee0 # Futurama
curl -s -X POST -H "X-Emby-Token: $TOKEN" \
"https://tv.s8n.ru/Items/$SERIES/Refresh?MetadataRefreshMode=FullRefresh&ImageRefreshMode=Default&ReplaceAllMetadata=false&ReplaceAllImages=false&Recursive=true" \
-w "HTTP %{http_code}\n"
MetadataRefreshMode=FullRefresh triggers subtitle download for items missing matching language. This will take a few minutes and is rate-limited by the OpenSubtitles 20-downloads/day cap on free accounts. 44 episodes exceeds that — plan for 3 days, or upgrade to VIP, or use sidecars (§ 7).
6. Per-user vs library default — who wins
| Setting | Lives in | Effect |
|---|---|---|
SubtitleDownloadLanguages (library) |
Library options | What languages are fetched and saved to disk |
SubtitleLanguagePreference (user) |
User config | Which existing track is auto-selected at playback |
SubtitleMode (user) |
User config | When to auto-display (Always / Default / OnlyForced / Smart / None) |
AudioLanguagePreference (user) |
User config | Which audio track is auto-selected |
A user's preferences are display-time only — they cannot trigger a download. A library's SubtitleDownloadLanguages is scan-time only — it does not affect what plays. You need both, and they should agree.
7. Sidecar subtitles — naming convention
If/when subs come from OpenSubtitles, Jellyfin saves them as sidecars (because SaveSubtitlesWithMedia=true). You can also drop your own. Filename pattern:
<videobasename>.<lang>[.flag].<ext>
Examples for Futurama.s01e01.pl.mkv:
| Filename | Meaning |
|---|---|
Futurama.s01e01.pl.en.srt |
English, regular |
Futurama.s01e01.pl.eng.srt |
English (ISO-639-2 code, also accepted) |
Futurama.s01e01.pl.en.forced.srt |
English forced (only foreign-language scenes) |
Futurama.s01e01.pl.en.sdh.srt |
English SDH (deaf/hard-of-hearing — includes [music], [door slams]) |
Futurama.s01e01.pl.en.cc.srt |
English closed captions (alias of SDH in Jellyfin) |
Futurama.s01e01.pl.en.default.srt |
Marked default — auto-selects regardless of SubtitleMode |
Futurama.s01e01.pl.en.forced.default.srt |
Forced AND default (flags compose, any order) |
Futurama.s01e01.pl.en.ass |
Advanced SubStation Alpha — supports styling/positions |
Futurama.s01e01.pl.en.ssa |
SubStation Alpha — older, also supported |
Futurama.s01e01.pl.en.vtt |
WebVTT — supported |
Futurama.s01e01.pl.en.sub + .idx |
VobSub (DVD bitmap subs) |
Language codes: Jellyfin accepts both ISO-639-1 (en, pl, de) and ISO-639-2/T (eng, pol, deu). Either works for filename matching — the parser canonicalises to 639-2 internally.
Region tags like en-US, pt-BR are accepted and shown to the user but treated as the bare language for matching.
After dropping sidecars, trigger a library scan:
curl -s -X POST -H "X-Emby-Token: $TOKEN" "https://tv.s8n.ru/Library/Refresh"
Or per-item: POST /Items/{id}/Refresh.
8. Extracting embedded subs to sidecars (irrelevant for Futurama, but documented)
If a future series has embedded but slow-loading PGS/SSA subs, extract once with ffmpeg:
# List streams
ffmpeg -i input.mkv 2>&1 | grep Subtitle
# Extract stream index 2 (first sub) to .srt — works for srt/ass/mov_text
ffmpeg -i input.mkv -map 0:s:0 -c:s copy input.en.srt
# For PGS or VobSub bitmap subs, copy keeps them as-is (rename .sup):
ffmpeg -i input.mkv -map 0:s:0 -c:s copy input.en.sup
# Then OCR with subtitleedit-cli or pgs2srt to convert to text srt.
Or with mkvextract (mkvtoolnix-cli):
mkvmerge -i input.mkv # lists tracks with IDs
mkvextract tracks input.mkv 2:input.en.srt
Jellyfin also has a built-in plugin Subtitle Extract (manifest GUID cd893c24-b59e-4060-87b2-184070e1bf68, latest v7.0.0.0 needs ABI 10.11.2.0 — wait until 10.11 upgrade). It extracts on the fly and caches in metadata/Subtitles/.
9. Auto-download settings cheatsheet
| Field | Where set | Recommended value | Why |
|---|---|---|---|
SubtitleDownloadLanguages |
Library options | ["eng"] |
Trigger downloads in English |
RequirePerfectSubtitleMatch |
Library options | false |
Don't insist on hash-match for foreign-dub releases |
SkipSubtitlesIfEmbeddedSubtitlesPresent |
Library options | false |
Allow override fetch even if embedded subs exist (e.g. if embedded are forced-only) |
SkipSubtitlesIfAudioTrackMatches |
Library options | true |
Don't fetch English subs for English audio (no waste) |
SaveSubtitlesWithMedia |
Library options | true |
Subs saved as sidecars on disk; portable; survives metadata wipe |
AllowEmbeddedSubtitles |
Library options | AllowAll |
Default; AllowText excludes PGS bitmap |
MaxResults |
(n/a in v20 plugin config) | — | The plugin returns the provider's full list; client picks |
IsAutomated |
(n/a, removed) | — | Older plugins had a flag; v20 always auto-fetches when a library scan finds an item missing the configured language |
10. Troubleshooting
| Symptom | Cause / fix |
|---|---|
RemoteSearch returns [] for every episode |
Creds missing / wrong (HTTP 401 in plugin logs). Re-validate via ValidateLoginInfo. |
429 Too Many Requests in logs |
Hit the 20/day quota on free account. Wait 24 h, upgrade to VIP, or fall back to sidecars. |
| Subs found but in wrong language | OpenSubtitles can mislabel — set RequirePerfectSubtitleMatch: true to filter, or pick manually via UI. |
.srt on disk but Jellyfin doesn't show it |
Filename language token doesn't match. Use .en.srt not .english.srt. Trigger library scan. |
| Subs show but client doesn't auto-display | User-side. Set SubtitleMode: Always and SubtitleLanguagePreference: eng. |
| Embedded subs preferred over downloaded | Expected — embedded come first in the priority order. Use the player's track switcher, or remux without subs. |
CredentialsInvalid: true keeps reappearing |
Plugin auto-flips this on a 401. Re-enter creds (likely changed on opensubtitles.com) and reset to false. |
Plugin v24 install but stuck on Restart forever after upgrade |
Server still on 10.10.x — v24 needs ABI 10.11. Reinstall v20. |
Plugin logs: docker logs jellyfin 2>&1 | grep -i opensubtitles.
11. Summary — Futurama after this work
| Step | State |
|---|---|
| Plugin Open Subtitles v20.0.0.0 | Installed + Active |
TV library SubtitleDownloadLanguages |
["eng"] |
TV library RequirePerfectSubtitleMatch |
false |
TV library SaveSubtitlesWithMedia |
true |
User s8n SubtitleMode |
Always |
User s8n SubtitleLanguagePreference |
eng |
User s8n AudioLanguagePreference |
pol |
| OpenSubtitles credentials | PENDING — user signs up at https://www.opensubtitles.com |
| Series refresh to fetch all 44 | PENDING — after creds entered |
When the user enters creds and runs the series refresh in § 5.2, expect ~20 episodes downloaded the first day (free quota), the rest over the next two days unless upgraded. Sidecar filenames will be Futurama.s01eXX.pl.eng.srt next to each .mkv.