mirror of
https://github.com/unshackle-dl/unshackle.git
synced 2026-11-14 13:05:09 +00:00
feat(tracks)!: match a language tag to the variant it means
A tag with a region (en-US, es-419) matches only that variant and reports a miss instead of taking another region. A bare tag takes the variant it means (pt -> pt-BR, es -> es-ES) and falls back to any variant only when that one is missing. `orig` prefers the title's own tag, `-sl orig` resolves, forced and SDH subtitles are picked from their own pools, and the track name no longer strips the region from the cached language. BREAKING CHANGE: -l es-419 no longer selects es-ES, and language_priority, language_tags and muxing.default_language treat a regional tag as exact.
This commit is contained in:
@@ -448,7 +448,7 @@ Make a download job. It requires `service` and `title_id`. Every other field is
|
||||
| `forced_subs` | boolean | `false` | Include forced subtitles. |
|
||||
| `forced_subs_only` | boolean | `false` | Download forced subtitles and no other subtitle; implies `forced_subs`. Not valid with `no_subs`, `video_only`, `audio_only` or `chapters_only`. |
|
||||
| `forced_s_lang` | string[] | `[]` | Forced subtitle language(s); implies `forced_subs`. |
|
||||
| `exact_lang` | boolean | `false` | Exact language matching. |
|
||||
| `exact_lang` | boolean | `false` | A language tag without a region never falls back to another variant. A tag with a region is always exact. |
|
||||
| `sub_format` | string | `null` | Output subtitle format. |
|
||||
| `video_only` / `audio_only` / `subs_only` / `chapters_only` | boolean | `false` | Track-type restriction (at most one). |
|
||||
| `no_subs` / `no_audio` / `no_chapters` / `no_video` / `no_attachments` | boolean | `false` | Skip a track type. |
|
||||
|
||||
@@ -104,7 +104,7 @@ unshackle dl [OPTIONS] SERVICE [SERVICE ARGS...]
|
||||
| `-fs`, `--forced-subs` | off | Include forced subtitle tracks. |
|
||||
| `-fso`, `--forced-subs-only` | off | Keep only forced subtitle tracks; drop the other subtitles. Implies `-fs`. |
|
||||
| `-fsl`, `--forced-s-lang` | none | Language(s) wanted for forced subtitles; implies `-fs`. A `-` prefix excludes. |
|
||||
| `--exact-lang` | off | Exact matching only: `-l es-419` matches `es-419`, not `es-ES`. Applies to selection and to sort order. |
|
||||
| `--exact-lang` | off | A tag without a region selects only the variant it means and never falls back to another: `-l es` does not select `es-419`. A tag with a region, such as `es-419`, is always exact. Applies to selection and to sort order. |
|
||||
| `--sub-format` | - | Output subtitle format (`SRT`/`srt`, `VTT`/`webvtt`, `ASS`/`ssa`, `TTML`, `SMI`, ...), or `original` to keep the source format. |
|
||||
|
||||
!!! tip "These flags select languages, they do not order them"
|
||||
|
||||
@@ -315,9 +315,9 @@ unshackle dl -l en,-es -vl ja EXAMPLE 81234567
|
||||
!!! note "Rules for exclusion tokens"
|
||||
- `orig` becomes the title's own original language, so `-sl -orig` drops the
|
||||
subtitles in that language.
|
||||
- `--exact-lang` applies to exclusions with the same matching rules as selection:
|
||||
`-es` removes exactly the tracks that `es` would select. Without it, `-es` also
|
||||
removes `es-419` and `es-ES`.
|
||||
- An exclusion without a region removes every regional form: `-es` removes `es-419`
|
||||
and `es-ES`. An exclusion with a region removes only that variant: `-es-419` removes
|
||||
only `es-419`. With `--exact-lang`, `-es` removes only the variant `es` means.
|
||||
- Tracks with no language tag are never excluded.
|
||||
- unshackle rejects `-all`. Name the languages you do not want instead.
|
||||
- The comma form is the documented style. `-sl -es` also works, but a shell can read
|
||||
@@ -345,9 +345,28 @@ See [`subtitle.language_priority`](../reference/configuration/download.md#subtit
|
||||
|
||||
### Exact vs fuzzy matching
|
||||
|
||||
By default language matching is fuzzy: `-l en` also accepts `en-US`, `en-GB`, and the
|
||||
other regional forms (up to a small distance). Pass `--exact-lang` when only an exact
|
||||
match is acceptable: with it, `-l es-419` selects only `es-419`, not `es-ES`.
|
||||
A tag without a region asks for the variant it means: `pt` is Brazilian Portuguese, `es` is
|
||||
Spanish from Spain, and `en` is US English. With `pt-PT` and `pt-BR` tracks, `-l pt`
|
||||
selects `pt-BR`. If the title has no such variant, the tag takes every regional form, so
|
||||
`-l es` on a title with only `es-419` selects `es-419`.
|
||||
|
||||
A tag with a region asks for that variant only: `-l es-419` selects `es-419`, never `es-ES`
|
||||
or `es-MX`. If the service has no `es-419` track, unshackle reports `es-419 not found` and
|
||||
stops. With `--best-available`, it continues with the other languages.
|
||||
|
||||
A track without a region matches only the region its language implies. `en` is US English
|
||||
and `pt` is Brazilian Portuguese, so `-l en-US` accepts a track tagged `en`, but `-l en-GB`
|
||||
and `-l pt-PT` do not accept `en` or `pt`. To take any English track, write `en`.
|
||||
|
||||
`--exact-lang` turns off that fallback: a tag without a region then selects only the
|
||||
variant it means, so `-l es` does not select `es-419`.
|
||||
|
||||
`orig` is the title language that the service gives. It selects that exact variant first,
|
||||
so a `fr-CA` title takes `fr-CA` audio over `fr-FR`. When the title has no track in that
|
||||
variant, `orig` takes the closest regional form, unless you pass `--exact-lang`.
|
||||
|
||||
An exclusion without a region removes every regional form: `-es` drops `es-ES` and `es-419`.
|
||||
See the [exclusion rules](#excluding-languages) for `--exact-lang`.
|
||||
|
||||
!!! tip "The `all` and `best` tokens"
|
||||
For audio, the tokens `all` and `best` bypass the usual one-track-per-language pick
|
||||
|
||||
@@ -116,7 +116,7 @@ Every variable below is valid in both output and folder templates. unshackle tak
|
||||
| `lang_tag` | Result of your `language_tags` rules, if configured | `MULTi` |
|
||||
|
||||
!!! note "How `language_tags` rules match"
|
||||
unshackle tries the rules in order, but language comparison is **fuzzy**: a rule condition of `en` matches `en-US`, `en-GB`, and any other `en-*` form. Within a single rule, **all** conditions must match (AND logic) for it to apply. The first rule that fully matches wins. If none match, unshackle removes `{lang_tag?}` from the filename cleanly.
|
||||
unshackle tries the rules in order, and they compare languages with the same [matching rules](downloading.md#exact-vs-fuzzy-matching) as `-l`: a rule condition of `en` matches `en-US`, `en-GB`, and any other `en-*` form, but `es-419` matches only `es-419`. Within a single rule, **all** conditions must match (AND logic) for it to apply. The first rule that fully matches wins. If none match, unshackle removes `{lang_tag?}` from the filename cleanly.
|
||||
|
||||
### Episode-specific
|
||||
|
||||
|
||||
+14
-12
@@ -76,7 +76,7 @@ Subtitle selection happens through `dl` flags. The most important is language se
|
||||
| `-fs`, `--forced-subs` | Include forced subtitle tracks (excluded by default). |
|
||||
| `-fso`, `--forced-subs-only` | Keep only forced subtitle tracks and drop the other subtitles; implies `-fs`. |
|
||||
| `-fsl`, `--forced-s-lang` | Language(s) wanted for forced subtitles; implies `-fs`. A `-` prefix excludes. |
|
||||
| `--exact-lang` | Exact language matching, with no regional variants. |
|
||||
| `--exact-lang` | A tag without a region never falls back to another variant: `es` does not match `es-419`. |
|
||||
| `-S`, `--subs-only` | Download only subtitle tracks. |
|
||||
| `-ns`, `--no-subs` | Do not download subtitle tracks at all. |
|
||||
| `--sub-format` | Output subtitle format / conversion target (see [conversion](#converting-subtitle-formats)). |
|
||||
@@ -91,17 +91,18 @@ To narrow it down, pass a comma-separated list of language tags:
|
||||
unshackle dl --s-lang en,es EXAMPLE 81234567
|
||||
```
|
||||
|
||||
Language matching is fuzzy by default: `en` matches `en-US`, `en-GB`, and similar
|
||||
variants. If a requested language is missing but others were found, unshackle continues
|
||||
with whatever remains and tells you which languages it dropped.
|
||||
|
||||
For strict matching, where `es-419` matches only `es-419` and never `es-ES`, add
|
||||
`--exact-lang`:
|
||||
A tag without a region selects the variant it means, such as `en-US` for `en`, and every
|
||||
regional form only when the title has no such variant. A tag with a region matches only
|
||||
that variant:
|
||||
|
||||
```shell title="Only Latin-American Spanish, no other Spanish variants"
|
||||
unshackle dl --s-lang es-419 --exact-lang EXAMPLE 'https://www.example.com/...'
|
||||
unshackle dl --s-lang es-419 EXAMPLE 'https://www.example.com/...'
|
||||
```
|
||||
|
||||
If a requested language is missing, unshackle stops with an error. With `--best-available`,
|
||||
it continues with the languages it found and tells you which ones it dropped. See
|
||||
[exact vs fuzzy matching](downloading.md#exact-vs-fuzzy-matching) for the full rules.
|
||||
|
||||
### Requiring languages before downloading
|
||||
|
||||
`--require-subs` is a gate rather than a filter. It downloads **all** available
|
||||
@@ -193,10 +194,11 @@ can make a clean non-SDH version for you by stripping the hearing-impaired cues:
|
||||
sound effects, speaker labels, music notes, and similar. This is on by default and
|
||||
controlled by the [`strip_sdh`](#subtitle-configuration) config key.
|
||||
|
||||
The check is deliberately loose: if a close-enough plain track already exists (for
|
||||
example an `en-GB` non-SDH track when the SDH track is `en-US`), no stripped copy is
|
||||
created. When a stripped copy *is* created, the original SDH track is kept as well, so
|
||||
you end up with both.
|
||||
The check uses the same [matching rules](downloading.md#exact-vs-fuzzy-matching) as
|
||||
`--s-lang`. A plain track covers an SDH track only when it is the same variant: `en` and
|
||||
`en-US` cover each other, but a plain `en-GB` track does not stop a stripped `en` or `en-US`
|
||||
copy. When unshackle creates a stripped
|
||||
copy, it keeps the original SDH track as well, so you end up with both.
|
||||
|
||||
The [`sdh_method`](#subtitle-configuration) config key selects the stripping engine
|
||||
itself. The default (`auto`) prefers the `subby` cleaner for SRT, falls back to
|
||||
|
||||
@@ -219,13 +219,15 @@ subtitle:
|
||||
|
||||
unshackle removes nothing, unlike `-sl`, which drops every subtitle language it does not name.
|
||||
|
||||
Use `orig` in the list for the title's original language. A base tag also covers its
|
||||
regional forms, so `en` sorts `en-US` and `en-GB`, but `zh` does **not** cover
|
||||
`zh-Hant`, which you must name. The sort ignores entries that match no track, and it
|
||||
ignores entries that are not valid language tags.
|
||||
Use `orig` in the list for the title's original language. A base tag puts the variant it
|
||||
means first and its other regional forms after it, so `en` sorts `en-US` and then
|
||||
`en-GB`, but `zh` does **not** cover `zh-Hant`, which you must name. A tag with a region sorts only that variant, so
|
||||
`[en-US]` puts `en-US` before `en-GB`. The sort ignores entries that match no track, and
|
||||
it ignores entries that are not valid language tags.
|
||||
|
||||
`--exact-lang` applies here too: with it, `en` sorts only `en`, and `en-US` falls to
|
||||
the alphabetical tail with the rest. Name each tag you want when you use that flag.
|
||||
`--exact-lang` applies here too: with it, `en` sorts only the variant it means, and
|
||||
`en-GB` falls to the alphabetical tail with the rest. Name each tag you want when you use
|
||||
that flag.
|
||||
|
||||
!!! note "`type_priority` picks the default subtitle only with `muxing.default_language`"
|
||||
At mux time the `default` flag goes to every forced subtitle whose language matches the
|
||||
@@ -277,7 +279,7 @@ Matroska (MKV) muxing options.
|
||||
| Sub-key | Type | Default | Description |
|
||||
|---------|------|---------|-------------|
|
||||
| `set_title` | bool | `true` | Write a human-readable title into the MKV container. |
|
||||
| `default_language` | dict | `{}` | Force which language is flagged *default* per track type, e.g. `{audio: en, subtitle: en}`. |
|
||||
| `default_language` | dict | `{}` | Force which language is flagged *default* per track type, e.g. `{audio: en, subtitle: en}`. A tag with a region, such as `en-US`, matches only that variant. |
|
||||
| `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. |
|
||||
| `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. |
|
||||
@@ -308,7 +310,8 @@ Language-tag remapping and the rule engine behind the `{lang_tag}` filename vari
|
||||
|
||||
Each language condition takes one language tag or a list of them. A list matches when **any**
|
||||
entry matches, except `subs_contain_all`, which needs them all. An entry that is not a valid
|
||||
language tag (for example `japanese`) never matches. `dual`, `multi` and `dubbed` take a bare
|
||||
language tag (for example `japanese`) never matches. A tag with a region matches only that
|
||||
variant, so `audio: es-419` does not match `es-ES` audio. `dual`, `multi` and `dubbed` take a bare
|
||||
`true` or `false`, not a quoted string. unshackle skips a rule with a condition name it does
|
||||
not know, or with any other value in a boolean condition. It logs a warning in each of these
|
||||
cases and tries the next rule.
|
||||
|
||||
Reference in New Issue
Block a user