feat(dl): add --audio-description-only and --forced-subs-only

Each keeps one kind of track inside its track type. A run of more than one title skips a title that has no such track. The REST API rejects a non-boolean value for a boolean dl param, and the DASH parser reads audio description from Role elements.
This commit is contained in:
imSp4rky
2026-10-06 12:45:52 -06:00
parent 9fc25e53d5
commit 3477d09cc2
17 changed files with 426 additions and 26 deletions
+2
View File
@@ -435,12 +435,14 @@ Make a download job. It requires `service` and `title_id`. Every other field is
| `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. |
| `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. |
| `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. |
| `audio_description` | boolean | `false` | Download audio description. |
| `audio_description_only` | boolean | `false` | Download audio description and no standard audio. Not valid with `no_audio`, `video_only`, `subs_only` or `chapters_only`. |
| `slow` | boolean/string | `null` | Randomized delay between downloads. |
| `split_audio` | boolean | `null` | Separate files per audio codec. |
| `skip_dl` | boolean | `false` | Only fetch keys, do not download. |
+3 -2
View File
@@ -438,8 +438,9 @@ server drops an unknown codec name. An empty array is a valid value and stays
empty.
The server does not forward the `dl` mode flags: `video_only`, `audio_only`,
`subs_only`, `chapters_only`, `list_`, `skip_dl`, `sub_format` and
`no_attachments`. A service that reads one of them to skip work fetches more on
`subs_only`, `chapters_only`, `list_`, `skip_dl`, `sub_format`,
`no_attachments`, `audio_description`, `audio_description_only` and
`forced_subs_only`. A service that reads one of them to skip work fetches more on
the server, but the result is the same.
In a client-login session (not a server account), the server gives the service
+2
View File
@@ -102,6 +102,7 @@ unshackle dl [OPTIONS] SERVICE [SERVICE ARGS...]
| `--require-video` | - | Video langs that must exist. The title fails even with `--best-available`. Does not select tracks. |
| `--require-subs` | - | Subtitle langs that must exist. Fails the title if one is missing. `--s-lang` still decides what to keep. |
| `-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. |
| `--sub-format` | - | Output subtitle format (`SRT`/`srt`, `VTT`/`webvtt`, `ASS`/`ssa`, `TTML`, `SMI`, ...), or `original` to keep the source format. |
@@ -139,6 +140,7 @@ Keep only certain track types, or skip certain track types.
| Flag | Description |
|---|---|
| `-ad`, `--audio-description` | Include descriptive (audio-description) tracks. |
| `-ado`, `--audio-description-only` | Keep only descriptive (audio-description) tracks; drop the standard audio. Does not need `-ad`. |
| `--skip-subtitle-errors` | Skip a failed subtitle instead of aborting the title. Video/audio failures remain fatal. |
### Output, muxing & files
+22
View File
@@ -416,6 +416,8 @@ video track counts. `--no-audio` and `--no-video` drop the matching requirement.
`-fs`). Works independently of `--s-lang`, so `-sl all -fsl en` grabs every full
subtitle but only the English forced track. It accepts exclusions too: `-fsl all,-es`
keeps every forced subtitle except the Spanish one, and `-fsl -es` means the same.
- `-fso` / `--forced-subs-only`: keep only the forced subtitle tracks and drop every
other subtitle (implies `-fs`). `--s-lang` and `-fsl` still select the languages.
- `--sub-format`: set the output subtitle format, converting only when necessary.
Accepts codec names/values and common aliases (`srt`, `vtt`, `ass`, `ssa`, `ttml`,
and the other codec aliases), or the literal `original` to keep the source format.
@@ -637,9 +639,29 @@ Additional track-type flags:
- `-ad` / `--audio-description`: include descriptive (audio-description) tracks, which
unshackle drops by default.
- `-ado` / `--audio-description-only`: keep only the descriptive tracks and drop the
standard audio. It does not need `-ad`. Add `-A` to download no video or subtitles.
- `--skip-subtitle-errors`: if a subtitle fails to download, skip it and continue rather
than aborting the whole title. Video and audio failures remain fatal.
!!! note "The `-only` kind flags"
`-ado` and `-fso` each keep one kind of track inside its track type. They do not drop
the other track types: `-ado` still downloads the video, and `-fso` still downloads
video and audio. Add `-A` or `-S` for that.
- The language flags still apply. With the default `-l orig`, `-ado` fails when the
descriptive track is not in the original language. Select the language with `-al`.
- A flag that drops the same tracks is an error, for example `-ado` with `--no-audio`
or `-fso` with `-A`.
- A title with no track of that kind stops a run of one title. A run of more than one
title skips that title with a warning and continues.
- unshackle reads the kind from the manifest or from the service. A track that
neither of them marks as descriptive or forced does not match.
```shell title="Audio description only, in English"
unshackle dl -A -ado -al en EXAMPLE 81234567
```
```shell title="Subtitles only"
unshackle dl -S -sl en EXAMPLE 81234567
```
+12
View File
@@ -74,6 +74,7 @@ Subtitle selection happens through `dl` flags. The most important is language se
| `-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`. |
| `-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. |
| `-S`, `--subs-only` | Download only subtitle tracks. |
@@ -138,6 +139,17 @@ If you pass both flags, `-fsl` wins and keeps only forced tracks in its language
It also understands `orig` (the title's original language) and `all` (every forced
track, same as plain `-fs`).
To download the forced tracks and no other subtitle, use `-fso` / `--forced-subs-only`.
It implies `-fs`, and `--s-lang` and `-fsl` still select the languages:
```shell title="Only the English forced track"
unshackle dl --s-lang en --forced-subs-only EXAMPLE 81234567
```
`-fso` does not drop video or audio. Add `-S` for a subtitle-only download. A title with
no forced track stops a run of one title. A run of more than one title skips that title
with a warning.
## Track types: forced, SDH, and CC
Every subtitle track carries flags describing what kind of captions it holds. These
+3
View File
@@ -43,6 +43,9 @@ Common config keys. This is a useful subset, and every `dl` flag works:
| `sub_format` | str | *(unset)* | Convert subtitles to this format (`srt`, `vtt`, `original`, ...). |
| `forced_subs` | bool | `false` | Include forced subtitle tracks. |
| `forced_s_lang` | list | `[]` | Forced subtitle language(s); implies `forced_subs`. A `-` prefix excludes. |
| `forced_subs_only` | bool | `false` | Keep only forced subtitle tracks; implies `forced_subs`. |
| `audio_description` | bool | `false` | Include descriptive (audio-description) tracks. |
| `audio_description_only` | bool | `false` | Keep only descriptive (audio-description) tracks. |
| `no_subs` / `no_audio` / `no_chapters` / `no_attachments` | bool | `false` | Skip that track type. `no_attachments` also skips attaching subtitle fonts. |
| `downloads` | int | `1` | Tracks downloaded concurrently. |
| `workers` | int | *(downloader default)* | Threads per track. |