feat(tracks): add muxing.original_label to mark original-language tracks

Adds the label to audio, subtitle and embedded audio names unless the name already says it, and escapes track lines in the --list tree.
This commit is contained in:
imSp4rky
2026-10-24 22:51:35 -06:00
parent 80bda08f36
commit cc33600cc7
6 changed files with 105 additions and 13 deletions
+1 -1
View File
@@ -377,7 +377,7 @@ The server sorts tracks by bitrate, descending. Episodes the server cannot get g
The `drm` array on a track is a list of `{type, pssh?, kids?, content_keys?, license_url?}` objects.
Every track carries the same fields as a local track: `is_original_lang`, `name`, `needs_repack`, `edition`, and `data`. `name` is the name the service set, or null. `track_name` is the name `--list` shows and the mux writes to an audio or subtitle track: `name` when the service set one, else the name of the language (English, or in the language itself when the server sets `muxing.track_names: native`, or no name when it sets `none`), with the SDH, CC, Forced or Descriptive label. `bitrate` is in kb/s, and `bitrate_bps` gives the exact bits/s. `data` holds the part of the service-set `track.data` that fits in JSON, without the `hls`, `dash`, and `ism` parser keys. Audio keeps `is_original` and `atmos` for clients that read them, and adds the exact `joc` object count.
Every track carries the same fields as a local track: `is_original_lang`, `name`, `needs_repack`, `edition`, and `data`. `name` is the name the service set, or null. `track_name` is the name `--list` shows and the mux writes to an audio or subtitle track: `name` when the service set one, else the name of the language (English, or in the language itself when the server sets `muxing.track_names: native`, or no name when it sets `none`), then the server's `muxing.original_label` on an original-language track, then the SDH, CC, Forced or Descriptive label. `bitrate` is in kb/s, and `bitrate_bps` gives the exact bits/s. `data` holds the part of the service-set `track.data` that fits in JSON, without the `hls`, `dash`, and `ism` parser keys. Audio keeps `is_original` and `atmos` for clients that read them, and adds the exact `joc` object count.
| Status | Error code | Meaning |
| --- | --- | --- |
+28
View File
@@ -326,6 +326,34 @@ SDH, CC, Forced or Descriptive track then has only that label as its name.
The option also changes the names in `--list` and in the `track_name` field of the REST API.
Set `muxing.original_label` to add a label after the name of each audio and subtitle track in the
title's original language. unshackle also sets the Matroska original flag on these tracks, but some
players show only the name. MP4 output has no original flag, so there the label is the only marker:
```yaml title="unshackle.yaml"
muxing:
original_label: "[Original]"
```
| Track | Track name |
|-------|------------|
| Japanese audio, original language | Japanese [Original] |
| Japanese SDH subtitle, original language | Japanese [Original] (SDH) |
| Korean subtitle | Korean |
The label can be any text, for example `"| Original"` or a label in another language. Put it in
quotes: YAML reads an unquoted `[Original]` as a list, and an unquoted `| Original` stops the config
from loading. unshackle ignores a value that is not text.
The label also applies to a name that the service sets, and to audio that a service keeps inside the
video file. unshackle does not add the label when the name already contains its words, so a service
name `Original` or `Japanese (original)` stays as it is.
!!! tip "Use an English label with Jellyfin 12"
Jellyfin 12 adds its own "Original" to an original-language audio track from the flag, unless the
name already contains the word. It adds none to a subtitle. A label in another language, such as `[원어]`, then shows next to Jellyfin's
"Original".
!!! note "Players that show the language next to the name"
Some players, such as Jellyfin, show the track name and the language name together. They leave
out the language when the name already contains it, so an English name shows once. A native name
+1
View File
@@ -289,6 +289,7 @@ Matroska (MKV) muxing options.
| `merge_audio` | bool | `true` | Merge all audio into one file. `--split-audio` on the CLI flips this off. |
| `merge_video` | bool | `false` | Merge video tracks that share height, range, and codec into one file, so only language varies inside a file. `--merge-video` on the CLI flips this on. |
| `track_names` | str | `english` | The language of the name unshackle gives a track that the service left unnamed: `english` (`Chinese (Traditional)`), `native`, the name in the language itself (`中文(繁體)`), or `none`, which leaves the track unnamed. Read [Track names and language tags](../../guide/output-and-naming.md#track-names-and-language-tags). |
| `original_label` | str | unset | Text that unshackle adds after the name of an audio or subtitle track in the title's original language, such as `[Original]`. Read [Track names and language tags](../../guide/output-and-naming.md#track-names-and-language-tags). |
| `concurrency` | int | `4` | How many mkvmerge processes run at the same time when a title muxes more than one output file (one per video variant or audio codec). Each process uses one CPU core, so this shortens the mux step on an SSD. Set it to `1` on a hard disk, where parallel writes are slower. |
```yaml