feat(dl)!: treat a missing -sl language as a warning

A missing -sl language now warns and continues, with or without --best-available. --require-subs counts a forced track only when selection keeps it, and a title with no track left is skipped instead of failing at mux.

BREAKING CHANGE: a missing -sl subtitle language no longer fails the run. Use --require-subs to fail on it.
This commit is contained in:
imSp4rky
2026-11-09 15:01:54 -07:00
parent 2ddc69970f
commit 4b6d15cc2a
10 changed files with 96 additions and 63 deletions
+1 -1
View File
@@ -450,7 +450,7 @@ Make a download job. It requires `service` and `title_id`. Every other field is
| `wanted` | string / string[] | `[]` | Episode/season selectors, as a list or as one comma-separated string. Accepts the part form, `"S01E01.2"`, and the air-date form, `"2026-08-11"` or `"2026-08-01:2026-08-31"`. For a music release, a selector is a track number, `"1-5"` or `"1,3,7"`, or `"{disc}x{track}"` such as `"2x3"`. |
| `latest_episode` | boolean | `false` | Only the newest episode. |
| `latest_episodes` | integer | `null` | Only the N newest episodes. A positive integer. When set, it overrides `latest_episode`. |
| `lang` / `v_lang` / `a_lang` / `s_lang` | string[] | `["orig"]` / `[]` / `[]` / `["all"]` | Language filters. |
| `lang` / `v_lang` / `a_lang` / `s_lang` | string[] | `["orig"]` / `[]` / `[]` / `["all"]` | Language filters. A missing `s_lang` language gives a warning and the job continues. |
| `require_audio` | string[] | `[]` | Audio languages that must exist. The job fails if one is missing, even with `best_available`. |
| `require_video` | string[] | `[]` | Video languages that must exist. The job fails if one is missing, even with `best_available`. |
| `require_subs` | string[] | `[]` | Subtitle languages that must exist. The job fails if one is missing. `s_lang` still decides what to keep. |
+1 -1
View File
@@ -84,7 +84,7 @@ unshackle dl [OPTIONS] SERVICE [SERVICE ARGS...]
| `-c`, `--channels` | - | Audio channels; matches sub-layouts (5.1 ≈ 6.0). |
| `-naa`, `--noatmos` | off | Exclude Dolby Atmos audio tracks. |
| `--worst` | off | Pick the lowest bitrate within the requested quality. **Requires `-q`.** |
| `--best-available`, `--warn-only` | off | Warn and continue when a requested resolution, range, or language is absent, instead of failing. With `--all-drm`, also when one DRM system does not license. |
| `--best-available`, `--warn-only` | off | Warn and continue when a requested resolution, range, video language, or audio language is absent, instead of failing. With `--all-drm`, also when one DRM system does not license. |
| `-rvb`, `--real-video-bitrate` | off | Probe real media size for true video bitrates, overriding the manifest. |
| `-rab`, `--real-audio-bitrate` | off | Same for audio (slower). |
+3 -2
View File
@@ -97,7 +97,7 @@ By default a missing requested resolution is an error. Two flags change that:
| Flag | Behaviour |
| --- | --- |
| `--best-available` (`--warn-only`) | If the requested resolution(s) are not present, continue with the best that *is* available instead of failing. Also softens missing video/audio/subtitle languages and hybrid fallbacks, and with `--all-drm` a DRM system that does not license. |
| `--best-available` (`--warn-only`) | If the requested resolution(s) are not present, continue with the best that *is* available instead of failing. Also softens missing video and audio languages and hybrid fallbacks, and with `--all-drm` a DRM system that does not license. |
| `--worst` | Within the specified quality, pick the **lowest** bitrate rendition. **Requires `-q/--quality`.** |
```shell title="Never fail on a missing resolution"
@@ -421,7 +421,8 @@ selects `pt-BR`. If the title has no such variant, the tag takes every regional
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.
stops. With `--best-available`, it continues with the other languages. A missing `-sl`
language always gives a warning and the download continues; `--require-subs` makes it fail.
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`
+7 -11
View File
@@ -75,7 +75,7 @@ Subtitle selection happens through `dl` flags. The most important is language se
| Flag | Purpose |
| --- | --- |
| `-sl`, `--s-lang` | Language(s) wanted for subtitles. Defaults to `all`. A `-` prefix excludes, e.g. `all,-es`. |
| `--require-subs` | Require these languages to exist; if present, download **all** subtitles. Cannot be combined with `--s-lang`. |
| `--require-subs` | Require these languages to exist. The title fails if one is missing. `--s-lang` still decides what to keep. |
| `-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. |
@@ -102,25 +102,21 @@ that variant:
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
If a requested language is missing, unshackle continues with the languages it found and
tells you which ones it dropped. To stop the title instead, use `--require-subs`. 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
subtitles, but only if every language you name is present. If any is missing, the title
errors out. This is useful for batch jobs where you want a title without your must-have
language to fail loudly, and not to silently give a partial result.
`--require-subs` is a gate rather than a filter. If any language you name is missing, the
title fails, even under `--best-available`. It does not select tracks: `--s-lang` still
decides what to keep. This is useful for batch jobs where you want a title without your
must-have language to fail loudly, and not to silently give a partial result.
```shell title="Fail unless both English and French subs exist, then grab everything"
unshackle dl --require-subs en,fr EXAMPLE B0ABCDEFGH
```
!!! warning "`--require-subs` and `--s-lang` are mutually exclusive"
Because `--require-subs` forces downloading of all subtitle languages, it cannot be
combined with `--s-lang`. Choose one or the other.
### Forced subtitles
Forced tracks carry only the important on-screen signs and foreign-dialogue lines meant
+1 -1
View File
@@ -51,7 +51,7 @@ Common config keys. This is a useful subset, and every `dl` flag works:
| `workers` | int | *(downloader default)* | Threads per track. |
| `speed_limit` | str | *(unlimited)* | Total download speed cap across all downloads combined, e.g. `500k`, `5M`, `1.5G` or plain bytes/sec. Values are bytes, not bits (`5M` = 5.0 MB/s). |
| `slow` | str | *(unset)* | Inter-title delay, e.g. `"20-40"`. |
| `best_available` | bool | `false` | Warn instead of failing when a requested resolution, range, or language is missing, or when one DRM system does not license under `--all-drm`. The CLI flag is `--best-available`, also spelled `--warn-only`. |
| `best_available` | bool | `false` | Warn instead of failing when a requested resolution, range, video language, or audio language is missing, or when one DRM system does not license under `--all-drm`. The CLI flag is `--best-available`, also spelled `--warn-only`. |
| `generate_dv` | bool | `false` | With `-r HYBRID`, make Dolby Vision from the HDR10+ metadata when a title has no DV track. Needs `hdr10plus_tool`. See [Dolby Vision from HDR10+](../../guide/downloading.md#dolby-vision-from-hdr10). |
| `proxy` | str | *(unset)* | Default proxy URI or 2-letter country. |
| `no_folder` | bool | `false` | Do not create a per-title folder. |