Skip to content

fix(tags): preserve Matroska LanguageBCP47 regions - #790

Open
maghuro wants to merge 2 commits into
n00bcodr:mainfrom
maghuro:fix/789-language-ietf
Open

fix(tags): preserve Matroska LanguageBCP47 regions#790
maghuro wants to merge 2 commits into
n00bcodr:mainfrom
maghuro:fix/789-language-ietf

Conversation

@maghuro

@maghuro maghuro commented Aug 28, 2026

Copy link
Copy Markdown

Summary

Preserves explicit Matroska LanguageBCP47 / LanguageIETF regional variants before they are lost by Jellyfin/FFmpeg, allowing the existing region-aware language flag resolver to receive values such as pt-BR, pt-PT, en-US, and en-GB.

Fixes #789.

Root cause

Matroska can contain both a legacy Language element (por, eng, etc.) and an authoritative BCP-47 language element (pt-BR, en-US, etc.).

For the tested MKVToolNix files, FFmpeg/Jellyfin exposes only the legacy/base value through MediaStream.Language. As a result, Jellyfin Enhanced never receives the regional tag even though its client-side flag resolver already understands it.

Implementation

  • Adds a lightweight internal Matroska/EBML reader for local Matroska/WebM sources.
  • Reads only the container metadata required to locate Tracks / TrackEntry; it does not scan media clusters.
  • Prefers LanguageBCP47 over the legacy Language element.
  • Falls back to Jellyfin's existing MediaStream.Language for unsupported, inaccessible, malformed, non-Matroska, or non-regional media.
  • Aligns Matroska languages only with embedded audio streams and only when the embedded audio-track counts match exactly, avoiding incorrect ordinal assignment when external or missing streams are present.
  • Uses the resolved language in both server-side tag-cache extraction and the /tag-data path used when the server cache is disabled.
  • Updates item-details and Series/Season first-episode language paths to use the same region-aware projection.
  • Bumps the tag-cache schema from v2 to v3 so stale entries containing region-less language values are discarded and rebuilt.
  • Adds no external executable or package dependency.

Bare-language policy is intentionally unchanged. For example, an explicit en-US can resolve to the US flag, while bare eng continues to follow Jellyfin Enhanced's existing default behavior.

Testing

Runtime-tested on:

  • Jellyfin Server 12.0.0
  • Jellyfin Enhanced 12.4.1.0
  • Docker / Jellyfin Web
  • Server-Side Tag Cache enabled and disabled

Verified with real Matroska files containing:

  • por + pt-PT
  • por + pt-BR
  • eng + en-US
  • eng + en-GB

Verified regional values in the rebuilt v3 server tag cache, including pt-PT, pt-BR, en-US, en-GB, fr-CA, and es-419.

Also verified the non-cache card path and item-details path, including Series/Season first-episode language resolution.

Build/static validation:

  • Jellyfin 12 target / .NET 10: 0 warnings, 0 errors
  • Jellyfin 10.11 target / .NET 9: 0 warnings, 0 errors
  • node --check passed for both modified JavaScript files
  • git diff --check passed

AI assistance

AI assistance was used during investigation and implementation; I reviewed and tested the changes and understand the implementation.

Read embedded Matroska LanguageBCP47/LanguageIETF values directly when Jellyfin/FFmpeg exposes only the legacy base language.

Use the region-aware language resolver in server cache and tag-data paths, preserve native Jellyfin values as a fail-safe fallback, and invalidate stale tag-cache entries via schema v3.

Refs n00bcodr#789
Comment thread Jellyfin.Plugin.JellyfinEnhanced/Helpers/MatroskaLanguageReader.cs Fixed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

🐛[BUG] Language Tags lose Matroska LanguageIETF/BCP-47 regional variants before flag resolution

2 participants