mirror of
https://github.com/unshackle-dl/unshackle.git
synced 2026-09-30 04:52:17 +02:00
Split episodes count once. Exposed as latest_episodes on the REST API. Closes #159.
601 lines
28 KiB
Markdown
601 lines
28 KiB
Markdown
# CLI Reference
|
|
|
|
A complete reference for every `unshackle` command, subcommand, and flag. This page groups the commands by purpose:
|
|
|
|
- **[`dl`](#dl)**: the download pipeline (the command you use most).
|
|
- **[`search`](#search)**: find titles on a service.
|
|
- **[`import`](#import)**: rebuild a download from an export file.
|
|
- **[`cfg`](#cfg)**, **[`env`](#env)**: manage configuration and the environment.
|
|
- **[`kv`](#kv)**: Key Vault operations.
|
|
- **[`wvd`](#wvd)**, **[`prd`](#prd)**: Widevine / PlayReady device management.
|
|
- **[`serve`](#serve)**: operate the local CDM and REST API server.
|
|
- **[`util`](#util)**: helper media utilities.
|
|
|
|
!!! tip "Getting help on any command"
|
|
Every command accepts `-h`, `--help`, or `-?`. For example `unshackle dl --help` or `unshackle wvd new --help`. Each service defines its own arguments for `dl` and `search` (such as a title ID or a query), so examine `unshackle dl SERVICE --help` for those.
|
|
|
|
---
|
|
|
|
## Root command
|
|
|
|
```
|
|
unshackle [OPTIONS] COMMAND [ARGS]...
|
|
```
|
|
|
|
> unshackle: Modular Movie, TV, and Music Archival Software.
|
|
|
|
Every invocation prints a banner and, when you enable `update_checks` in your config, checks for a newer release.
|
|
|
|
| Option | Description |
|
|
|---|---|
|
|
| `-v`, `--version` | Print version information and exit. |
|
|
| `-d`, `--debug` | Enable `DEBUG`-level logs and JSON debug logging. Silences noisy HTTP libraries unless `debug_requests` is set in config. |
|
|
| `-h`, `--help`, `-?` | Show help and exit. |
|
|
|
|
Commands are auto-discovered, so third-party command modules dropped into the commands directory appear automatically.
|
|
|
|
---
|
|
|
|
## `dl`
|
|
|
|
The download command. It is itself a group whose **subcommands are the installed streaming services**, so an invocation always has three layers:
|
|
|
|
```
|
|
unshackle dl [OPTIONS] SERVICE [SERVICE ARGS...]
|
|
```
|
|
|
|
- `OPTIONS`: every flag below, parsed at the `dl` level.
|
|
- `SERVICE`: a service tag (for example `EXAMPLE1` or `EXAMPLE2`). Tags are case-insensitive and honour each service's aliases (`example+`, `EXAMPLE2`, and the other alias forms all give the same tag).
|
|
- `SERVICE ARGS`: the title, URL, or ID, plus any service-specific options. These belong to the service, not to `dl`.
|
|
|
|
!!! example "Typical downloads"
|
|
```shell
|
|
# Best available 1080p SDR of a title
|
|
unshackle dl -q 1080 EXAMPLE 81234567
|
|
|
|
# 4K HDR10, English audio + subs, from a URL
|
|
unshackle dl -q 2160 -r HDR10 -l en EXAMPLE "https://www.example.com/..."
|
|
|
|
# A season range, HEVC video, EC3 audio
|
|
unshackle dl -w S01-S03 -v H.265 -a EC3 SERVICE TITLE-ID
|
|
```
|
|
|
|
!!! note "Config-driven defaults"
|
|
You can give any `dl` flag a default under the `dl:` section of `unshackle.yaml`, and per-service under `services.<TAG>.dl`. Explicit command-line values (and environment values) always win over both. Service defaults only fill in options you did not set. See the [configuration file](../getting-started/configuration-file.md) guide.
|
|
|
|
### Quality, codec, bitrate & range
|
|
|
|
| Flag | Default | Description |
|
|
|---|---|---|
|
|
| `-p`, `--profile` | - | Profile for credentials and cookies. |
|
|
| `-q`, `--quality` | best | Resolution(s), comma-separated, e.g. `1080,720`. `-q 1080` also matches anamorphic tracks by 16:9 canvas. |
|
|
| `-v`, `--vcodec` | any | Video codec(s). Accepts names or values: `AVC`/`H.264`/`H264`, `HEVC`/`H.265`/`H265`, `VC1`/`VC-1`, `VP8`, `VP9`, `AV1`. |
|
|
| `-a`, `--acodec` | any | Audio codec(s), comma-separated. Accepts `AAC`, `AC3`/`DD`, `EC3`/`DD+`/`eac3`/`ddp`, `AC4`/`AC-4`, `OPUS`, `OGG`/`VORB`/`vorbis`, `DTS`, `DTSX`/`DTS-X`, `ALAC`, `FLAC`. |
|
|
| `-vb`, `--vbitrate` | highest | Exact video bitrate in kbps. |
|
|
| `-ab`, `--abitrate` | highest | Exact audio bitrate in kbps. |
|
|
| `-vb-range`, `--vbitrate-range` | - | Video bitrate range in kbps, e.g. `6000-7000`; picks highest within. Mutually exclusive with `--vbitrate`. |
|
|
| `-ab-range`, `--abitrate-range` | - | Audio bitrate range in kbps, e.g. `128-256`. Mutually exclusive with `--abitrate`. |
|
|
| `-r`, `--range` | `SDR` | Colour range(s): `SDR`, `HLG`, `HDR10`, `HDR10P` (HDR10+), `DV`, `HYBRID`. |
|
|
| `-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. |
|
|
| `-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). |
|
|
|
|
!!! note "`HYBRID` range"
|
|
`-r HYBRID` fetches both HDR10/HDR10+ and Dolby Vision and merges them with `dovi_tool`. It requires the `dovi_tool` binary on your `PATH`.
|
|
|
|
### Language & subtitles
|
|
|
|
| Flag | Default | Description |
|
|
|---|---|---|
|
|
| `-l`, `--lang` | `orig` | Language(s) for **both** video and audio. `orig` = the title's original language; e.g. `orig,en`. A `-` prefix excludes, e.g. `all,-es`. |
|
|
| `-vl`, `--v-lang` | - | Video-only language (overrides `-l` for video). A `-` prefix excludes. |
|
|
| `-al`, `--a-lang` | - | Audio-only language (overrides `-l` for audio). A `-` prefix excludes. |
|
|
| `-sl`, `--s-lang` | `all` | Subtitle language(s). A `-` prefix excludes, e.g. `all,-es`. |
|
|
| `--require-audio` | - | Audio langs that must exist. The title fails even with `--best-available`. Does not select tracks. |
|
|
| `--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. |
|
|
| `-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. |
|
|
|
|
!!! tip "These flags select languages, they do not order them"
|
|
Naming languages with `-l` or `-sl` removes the others. To keep every language but put
|
|
your preferred ones first, use `audio.language_priority` and
|
|
[`subtitle.language_priority`](../reference/configuration/download.md#subtitle) in your
|
|
configuration file.
|
|
|
|
unshackle honours the special language tokens `orig`, `all`, and `best` everywhere it expects a language.
|
|
|
|
### Title & episode selection
|
|
|
|
| Flag | Description |
|
|
|---|---|
|
|
| `-w`, `--wanted` | Wanted episodes, e.g. `S01-S05,S07`, `S01E01-S02E03`. Supports exclusions with a leading `-` (e.g. `-S03`). For a [split episode](downloading.md#split-episodes), `.N` picks one part (`S01E01.2`), a range must stay inside the episode (`S01E01.1-S01E01.3`), and `S01E01` on its own takes every part. For a [dated episode](downloading.md#daily-and-date-based-content), a token can also be an ISO air date (`2026-08-11`) or a date range with a colon (`2026-08-01:2026-08-31`). For a [music release](downloading.md#music-tracks), a token is a track number (`1-5`, `1,3,7`), or `{disc}x{track}` (`2x3`) when the release has more than one disc. |
|
|
| `--select-titles` | Interactively select what to download: episodes of a series, or films when a title has more than one. **Cannot combine with `-w`.** |
|
|
| `--latest-episode` | Download only the single most recent episode. |
|
|
| `--latest-episodes N` | Download only the N most recent episodes. |
|
|
| `--list-titles` | List titles only; do not download. |
|
|
|
|
### Track-type inclusion / exclusion
|
|
|
|
Keep only certain track types, or skip certain track types.
|
|
|
|
| Include-only | Skip |
|
|
|---|---|
|
|
| `-V`, `--video-only` | `-nv`, `--no-video` |
|
|
| `-A`, `--audio-only` | `-na`, `--no-audio` |
|
|
| `-S`, `--subs-only` | `-ns`, `--no-subs` |
|
|
| `-C`, `--chapters-only` | `-nc`, `--no-chapters` |
|
|
| | `-nt`, `--no-attachments` (cover art, subtitle fonts, and files the service attaches) |
|
|
|
|
| Flag | Description |
|
|
|---|---|
|
|
| `-ad`, `--audio-description` | Include descriptive (audio-description) tracks. |
|
|
| `--skip-subtitle-errors` | Skip a failed subtitle instead of aborting the title. Video/audio failures remain fatal. |
|
|
|
|
### Output, muxing & files
|
|
|
|
| Flag | Description |
|
|
|---|---|
|
|
| `--split-audio` | Write a separate output file per audio codec instead of merging. Defaults to config `muxing.merge_audio`. |
|
|
| `--merge-video` | Mux video tracks that share a height, range, and codec into one file, so only language varies inside a file. Defaults to config `muxing.merge_video`. |
|
|
| `-o`, `--output` | Override the output directory for this run. |
|
|
| `--no-folder` | Disable folder creation for TV shows. |
|
|
| `--no-source` | Remove the source tag from the filename/path. |
|
|
| `--no-mux` | Do not mux; keep individual track files. |
|
|
| `--tag` | Group tag override. |
|
|
| `--repack` | Add a `REPACK` tag to the filename. |
|
|
| `--postscript` | Run a command after each output file, with `{variable}` placeholders substituted. Repeatable. Replaces the `post_scripts` config for this run. See [Post-scripts](../reference/configuration/post-scripts.md). |
|
|
| `--no-postscript` | Run no post-script for this run, neither the configured ones nor `--postscript`. |
|
|
|
|
### Metadata & tagging
|
|
|
|
| Flag | Description |
|
|
|---|---|
|
|
| `--tmdb` | TMDB ID (integer). Used for the tags. Skips the title search. `--enrich` reads it too. Needs `tmdb_api_key`. |
|
|
| `--imdb` | IMDb ID, e.g. `tt1375666`. Used for the tags. Skips the title search. `--enrich` reads it too. Needs no API key. |
|
|
| `--tvdb` | TVDB ID (integer). Used for the tags. Skips the series lookup that `--tvdb-order` would otherwise do. `--enrich` reads it too. Needs `tvdb_api_key`. |
|
|
| `--anilist` | AniList ID (integer), e.g. `--anilist 21`. A MyAnimeList ID is accepted as `mal:12345` and resolved to the AniList entry. Used for the tags. Skips the title search. `--enrich` reads it too. Needs no API key. |
|
|
| `--enrich` | Overwrite show title, year and original language with the external source's. **Requires** one of `--tmdb`, `--imdb`, `--tvdb`, or `--anilist`. |
|
|
| `--daily` | Treat the title as daily/date-based content and fill missing episode air dates from TVDB. The fill needs `--enrich` and a TVDB ID. See [Daily and date-based content](downloading.md#daily-and-date-based-content). |
|
|
| `--tvdb-order` | Renumber episodes to a TVDB season order: `official` (aired), `dvd`, `absolute`, `alternate`, or `regional`. Needs `tvdb_api_key`. |
|
|
|
|
!!! note "One ID at a time"
|
|
You cannot combine `--tmdb`, `--imdb` and `--tvdb`. Give one and unshackle finds the
|
|
others from it, and writes all three to the tags. `--anilist` is outside that rule and pairs
|
|
with one of them, which is how you attach a western ID to an anime title.
|
|
An ID with no metadata provider that can find it, such as `--tmdb` with no `tmdb_api_key`,
|
|
fails before the download starts. `--anilist` needs no API key, so it never fails this check.
|
|
|
|
#### Episode ordering
|
|
|
|
A service does not always number a series the way TVDB's aired order does. Some services use
|
|
TVDB's `alternate` (Streaming) order for Futurama, for example. `--tvdb-order` works out which
|
|
order the service used, then renumbers the episodes into the order you asked for.
|
|
|
|
!!! note "Orders that do not cover the whole series"
|
|
An order can ignore episodes the service carries. TVDB's `dvd` order for Futurama leaves
|
|
out the four movies. Those episodes keep their original numbering. If that would give two
|
|
episodes the same season/episode slot, and so the same filename, unshackle logs an error
|
|
and keeps the service's numbering unchanged. Pick an order that covers the whole series.
|
|
|
|
### DRM, keys & decryption
|
|
|
|
| Flag | Description |
|
|
|---|---|
|
|
| `--cdm-only` / `--vaults-only` | Use only the CDM, or only Key Vaults, for key acquisition. |
|
|
| `--cdm <name>` | Use the named CDM device from the `cdm` config mapping for this run, ignoring the service/default mapping. |
|
|
| `--skip-dl` | Skip the download but still retrieve keys. |
|
|
| `--export` | Export track info and keys to a `mediaexport` JSON file in the exports directory. |
|
|
|
|
### Network & proxy
|
|
|
|
| Flag | Description |
|
|
|---|---|
|
|
| `--proxy` | Proxy URI, a country or location code resolved from configured providers, or `provider:region` (e.g. `nordvpn:ca`, `gluetun:us`, `protonvpn:de:berlin`, `controld:yul`). |
|
|
| `--no-proxy` | Force-disable all proxy use. |
|
|
| `--no-proxy-download` | Bypass the proxy for **all downloads** (manifest, licence, and auth stay proxied). |
|
|
| `--proxy-download` | Use a different proxy for **all downloads**, in the same forms as `--proxy` (manifest, licence, and auth stay on `--proxy`). |
|
|
| `--remote` | Use a remote unshackle server. |
|
|
| `--server` | Name a remote server from the `remote_services` config. |
|
|
|
|
### Concurrency, caching & listing
|
|
|
|
| Flag | Default | Description |
|
|
|---|---|---|
|
|
| `--workers` | downloader default | Per-track download threads. |
|
|
| `--adaptive-workers` | off | Scale per-track segment workers dynamically (up to the `--workers` cap) based on measured CDN throughput and errors. |
|
|
| `--download-processes` | `1` | Split large segment batches (24+) across this many download processes to exceed the single-process throughput cap on multi-gigabit connections. Ignored while a speed limit is set: the cap is one shared budget, which extra processes cannot share, so the download stays in a single process. Also ignored when the service HTTP session carries state a child process cannot rebuild, such as a custom TLS adapter. |
|
|
| `--continue-downloads` | off | Keep completed segment files across runs and resume a previously failed download. One-off enable of the [`continue_downloads`](../reference/configuration/download.md#continue_downloads) config option. |
|
|
| `--downloads` | `1` | Number of tracks downloaded concurrently. |
|
|
| `--speed-limit` | unlimited | Cap total download speed across all threads and tracks, e.g. `500k`, `5M`, `1.5G` or plain bytes/sec. Values are bytes, not bits (`5M` = 5.0 MB/s). `off` disables a configured limit. |
|
|
| `--no-cache` | off | Bypass the title cache. |
|
|
| `--reset-cache` | off | Clear the title cache. |
|
|
| `--list` | off | List available/would-be-downloaded tracks; do not download. |
|
|
| `--slow` | - | Inter-title delay. Bare `--slow` = 60-120s; `--slow 20-40` = custom range (minimum 20s). |
|
|
|
|
!!! warning "Some flags cannot be combined"
|
|
`--select-titles` and `--wanted` are mutually exclusive. `--worst` needs `--quality`. `--vbitrate` and `--vbitrate-range` (and the audio equivalents) are mutually exclusive.
|
|
|
|
---
|
|
|
|
## `search`
|
|
|
|
Find titles on a service. Like `dl`, `search` is a group whose subcommands are the installed services, and it reuses `dl`'s authentication, cookie, and proxy machinery.
|
|
|
|
```
|
|
unshackle search [OPTIONS] SERVICE [QUERY...]
|
|
```
|
|
|
|
Each service defines its own query syntax. unshackle prints the results as a tree of titles with their service IDs. Feed an ID straight into `dl`.
|
|
|
|
| Option | Description |
|
|
|---|---|
|
|
| `-p`, `--profile` | Profile for credentials and cookies. |
|
|
| `--proxy` | Proxy URI, country or location code, or `provider:region` (e.g. `controld:ca`). |
|
|
| `--no-proxy` | Force-disable all proxy use. |
|
|
|
|
!!! example
|
|
```shell
|
|
unshackle search EXAMPLE "My Show"
|
|
unshackle search -p myprofile EXAMPLE "Another Show"
|
|
unshackle search --proxy nordvpn:ca SERVICE "query"
|
|
```
|
|
|
|
---
|
|
|
|
## `import`
|
|
|
|
Reconstruct a download (download → decrypt → mux) from an `--export` JSON file without re-contacting the service. It re-fetches the manifest, injects the stored keys, and then runs the normal `dl` pipeline. The service tag is read from the export file, not passed by you.
|
|
|
|
```
|
|
unshackle import EXPORT_FILE [DL_ARGS...]
|
|
```
|
|
|
|
unshackle forwards any `dl` options after the file verbatim, so you can override quality, range, proxy, and so on.
|
|
|
|
!!! example
|
|
```shell
|
|
unshackle import export.json
|
|
unshackle import export.json -r HDR10 --proxy US
|
|
```
|
|
|
|
The export file can be a `mediaexport` file from `dl --export`, an export from an older version of unshackle, or an export from unidl. The file must name the service it came from.
|
|
|
|
---
|
|
|
|
## `cfg`
|
|
|
|
Read, set, delete, or show configuration values in `unshackle.yaml` without hand-editing YAML.
|
|
|
|
```
|
|
unshackle cfg [KEY] [VALUE] [OPTIONS]
|
|
```
|
|
|
|
| Argument / Option | Description |
|
|
|---|---|
|
|
| `KEY` | Dotted path into the config, e.g. `tag`, `serve.api_secret`, `directories.downloads`. |
|
|
| `VALUE` | Value to set. Parsed as a Python literal when possible, so `true`, `123`, `['a','b']`, and `{'k':1}` become real types; bare words stay strings. |
|
|
| `--unset` | Remove the configuration value. |
|
|
| `--list` | List all set configuration values. |
|
|
|
|
!!! warning "Comments are stripped"
|
|
Writing a value through `cfg` rewrites the configuration file and **removes all comments** from it. If your config relies on comments, edit it by hand instead. Setting a value and using `--unset` together is an error.
|
|
|
|
!!! example
|
|
```shell
|
|
unshackle cfg --list # print entire config
|
|
unshackle cfg serve.api_secret # read a nested key
|
|
unshackle cfg tag MYGROUP # set a string
|
|
unshackle cfg update_checks false # literal → boolean False
|
|
unshackle cfg directories.downloads /mnt/dl # set a nested path
|
|
unshackle cfg tag --unset # remove a key
|
|
```
|
|
|
|
---
|
|
|
|
## `env`
|
|
|
|
Inspect and manage the project environment.
|
|
|
|
```
|
|
unshackle env COMMAND [ARGS]...
|
|
```
|
|
|
|
### `env check`
|
|
|
|
```
|
|
unshackle env check
|
|
```
|
|
|
|
Prints a dependency table (Category / Tool / Status / Required / Purpose) that shows which external tools unshackle finds on your `PATH`. It also gives a summary of how many required tools are present.
|
|
|
|
| Category | Tools |
|
|
|---|---|
|
|
| Core | FFmpeg*, FFprobe*, MKVToolNix*, mkvpropedit* |
|
|
| DRM | shaka-packager*, mp4decrypt |
|
|
| HDR | dovi_tool, HDR10Plus_tool |
|
|
| Subtitle | SubtitleEdit, CCExtractor |
|
|
| Player | FFplay, MPV |
|
|
| Network | HolaProxy, Caddy, Docker, git |
|
|
|
|
<small>* required. All others are optional.</small>
|
|
|
|
### `env info`
|
|
|
|
```
|
|
unshackle env info
|
|
```
|
|
|
|
Shows the location unshackle loaded the configuration file from. If it found no file, it shows the candidate locations instead. It then prints a table of every configured directory (downloads, temp, cache, cookies, logs, exports, WVDs, PRDs, services, and more).
|
|
|
|
### `env theme`
|
|
|
|
```
|
|
unshackle env theme
|
|
```
|
|
|
|
Prints a sample of every available CLI theme. Each sample has colour swatches, help text with option rows, and a track listing with video, audio and subtitle entries. It also has log lines, a progress bar, and the gradient pulse bar. unshackle marks the active theme and shows each theme's aliases. Set your choice with the [`theme`](../reference/configuration/misc.md#appearance) config key.
|
|
|
|
### `env clear`
|
|
|
|
Clear an environment directory. unshackle empties the directory, makes it again, and reports the number of files and bytes it freed.
|
|
|
|
| Command | Description |
|
|
|---|---|
|
|
| `unshackle env clear cache [SERVICE]` | Clear the cache directory, or only one service's cache subdirectory. |
|
|
| `unshackle env clear temp` | Clear the temp directory. |
|
|
|
|
!!! example
|
|
```shell
|
|
unshackle env check
|
|
unshackle env info
|
|
unshackle env theme
|
|
unshackle env clear cache
|
|
unshackle env clear cache EXAMPLE # one service only
|
|
unshackle env clear temp
|
|
```
|
|
|
|
---
|
|
|
|
## `kv`
|
|
|
|
Manage Key Vaults. You configure vaults under `key_vaults` in `unshackle.yaml`, each with a `name`, a `type` (`sqlite`, `mysql`, `http`, `api`), and type-specific options. unshackle normalises service tags automatically.
|
|
|
|
```
|
|
unshackle kv COMMAND [ARGS]...
|
|
```
|
|
|
|
### `kv copy TO_VAULT FROM_VAULT...`
|
|
|
|
Copy content keys from one or more source vaults into a destination vault. unshackle skips rows whose KIDs match, unless the existing row has no content key. unshackle never alters or deletes existing data.
|
|
|
|
| Option | Description |
|
|
|---|---|
|
|
| `-s`, `--service` | Only copy data for a specific service. |
|
|
| `-l`, `--local-only` | Only copy data for services installed locally. Mutually exclusive with `--service`. |
|
|
|
|
### `kv sync VAULT...`
|
|
|
|
Make sure that two or more vaults hold the same set of content keys, essentially a chained bidirectional copy. More than one vault is necessary. Accepts the same `--service` / `--local-only` options as `copy`.
|
|
|
|
### `kv add FILE SERVICE VAULT...`
|
|
|
|
Add content keys to one or more vaults for a service. `FILE` contains one `KID:KEY` pair per line (32 hex : 32 hex, UTF-8). unshackle skips every line that does not match that form.
|
|
|
|
### `kv search KID`
|
|
|
|
Find a KID (32 hex characters, no dashes) in the configured vaults and report its content key.
|
|
|
|
| Option | Description |
|
|
|---|---|
|
|
| `-s`, `--service` | Limit the search to a specific service tag. |
|
|
| `-v`, `--vault` | Limit the search to a specific configured vault by name. |
|
|
|
|
!!! note
|
|
unshackle cannot enumerate remote vaults without a service, so pass `--service` when you examine them.
|
|
|
|
### `kv prepare VAULT...`
|
|
|
|
Make service tables on vaults that use tables, for every installed service, where they do not already exist.
|
|
|
|
!!! example
|
|
```shell
|
|
unshackle kv copy main backup1 backup2
|
|
unshackle kv copy main backup -s EXAMPLE
|
|
unshackle kv sync main mysql_vault
|
|
unshackle kv add keys.txt EXAMPLE main backup
|
|
unshackle kv search 0123456789abcdef0123456789abcdef -s EXAMPLE -v main
|
|
unshackle kv prepare main mysql_vault
|
|
```
|
|
|
|
---
|
|
|
|
## `wvd`
|
|
|
|
Manage Widevine Device (`.wvd`) files. Devices live in the configured WVDs directory.
|
|
|
|
```
|
|
unshackle wvd COMMAND [ARGS]...
|
|
```
|
|
|
|
| Command | Description |
|
|
|---|---|
|
|
| `wvd add PATHS...` | Validate and move one or more `.wvd` files into the WVDs directory. |
|
|
| `wvd delete NAMES...` | Delete `.wvd` files by name (without extension). Prompts for confirmation. |
|
|
| `wvd parse PATH` | Parse a `.wvd` and print its System ID, security level, type, flags, and client info. Relative paths resolve against the WVDs directory. |
|
|
| `wvd dump WVD_PATHS... OUT_DIR` | Extract a device's contents (metadata, private key, client ID, VMP) into `OUT_DIR/<name>/`. With no paths, dumps every WVD in the WVDs directory. |
|
|
| `wvd new NAME PRIVATE_KEY CLIENT_ID [FILE_HASHES]` | Create a new `.wvd` from a PEM private key and a `ClientIdentification` blob, optionally with a VMP (`FileHashes`) blob. |
|
|
|
|
`wvd new` options:
|
|
|
|
| Option | Default | Description |
|
|
|---|---|---|
|
|
| `-t`, `--type` | `Android` | Device type. |
|
|
| `-l`, `--level` | `1` | Security level (1-3). |
|
|
| `-o`, `--output` | WVDs dir | Output directory. |
|
|
|
|
!!! example
|
|
```shell
|
|
unshackle wvd add device.wvd
|
|
unshackle wvd parse nexus_6p_1234_l1
|
|
unshackle wvd dump device.wvd ./out_dir
|
|
unshackle wvd new "Nexus 6P" private_key.pem client_id.bin vmp.bin -t ANDROID -l 3
|
|
```
|
|
|
|
---
|
|
|
|
## `prd`
|
|
|
|
Manage PlayReady Device (`.prd`) files. Devices live in the configured PRDs directory. Built on `pyplayready`.
|
|
|
|
```
|
|
unshackle prd COMMAND [ARGS]...
|
|
```
|
|
|
|
### `prd new PATHS...`
|
|
|
|
Make a new `.prd`. Give either a single folder that contains `zgpriv.dat` (group key) and `bgroupcert.dat` (group certificate), or two file paths (group key, then group certificate).
|
|
|
|
| Option | Description |
|
|
|---|---|
|
|
| `-e`, `--encryption_key` | Optional device ECC private encryption key (generated if omitted). |
|
|
| `-s`, `--signing_key` | Optional device ECC private signing key (generated if omitted). |
|
|
| `-o`, `--output` | Output directory or `.prd` file path. |
|
|
|
|
`prd new` will not overwrite an existing file.
|
|
|
|
### `prd reprovision PRD_PATH`
|
|
|
|
Reprovision an existing device by replacing its leaf certificate and keys. Only a device of version 3 or higher can do reprovisioning. Accepts the same `-e` / `-s` / `-o` options. By default it overwrites the device in place.
|
|
|
|
### `prd test DEVICE`
|
|
|
|
Do a test of a device against the Microsoft PlayReady demo server and print the returned content keys.
|
|
|
|
| Option | Default | Description |
|
|
|---|---|---|
|
|
| `-c`, `--ckt` | `aesctr` | Content key encryption type: `aesctr` or `aescbc`. |
|
|
| `-sl`, `--security-level` | `2000` | Minimum security level: `150`, `2000`, or `3000`. |
|
|
|
|
!!! example
|
|
```shell
|
|
unshackle prd new ./device_folder/
|
|
unshackle prd new zgpriv.dat bgroupcert.dat -o /out/dir
|
|
unshackle prd reprovision mydevice.prd
|
|
unshackle prd test mydevice.prd -sl 3000 -c aescbc
|
|
```
|
|
|
|
---
|
|
|
|
## `serve`
|
|
|
|
Serve your local Widevine/PlayReady devices and the REST API for remote access. Built on `aiohttp`.
|
|
|
|
```
|
|
unshackle serve [OPTIONS]
|
|
```
|
|
|
|
| Option | Default | Description |
|
|
|---|---|---|
|
|
| `-h`, `--host` | `127.0.0.1` | Host to serve from. |
|
|
| `-p`, `--port` | `8786` | Port to serve from. |
|
|
| `--caddy` | off | Also serve through Caddy (requires the `caddy` binary and a `Caddyfile`). |
|
|
| `--api-only` | off | Serve only the REST API, not the CDM endpoints. Incompatible with `--no-widevine`/`--no-playready`. |
|
|
| `--no-widevine` | off | Disable the Widevine CDM endpoints. |
|
|
| `--no-playready` | off | Disable the PlayReady CDM endpoints. |
|
|
| `--no-key` | off | Disable API-key authentication (allows all requests). |
|
|
| `--debug-api` | off | Include tracebacks/stderr in API error responses. |
|
|
| `--debug` | off | Enable debug logging for API operations. |
|
|
| `--remote-only` | off | Expose only the remote service session endpoints (health, services, search, session). Implies `--api-only`. |
|
|
|
|
WVD files in the WVDs directory and PRD files in the PRDs directory are auto-loaded. The REST API lives under `http://<host>:<port>/api/`, with Swagger UI at `/api/docs/` and a health check at `/api/health` (exempt from auth).
|
|
|
|
!!! warning "Configure `api_secret` first"
|
|
Unless you pass `--no-key`, `serve.api_secret` must be set in your config. Requests authenticate with the `X-Secret-Key` header. `--no-key` disables authentication entirely. Only use it on a trusted, private network.
|
|
|
|
```yaml title="unshackle.yaml"
|
|
serve:
|
|
api_secret: "your-api-secret"
|
|
users:
|
|
your-secret-key:
|
|
devices: ["device_name"] # Widevine devices
|
|
playready_devices: ["device_name"] # PlayReady devices
|
|
username: user
|
|
```
|
|
|
|
!!! example
|
|
```shell
|
|
unshackle serve
|
|
unshackle serve -h 0.0.0.0 -p 8080
|
|
unshackle serve --api-only
|
|
unshackle serve --remote-only
|
|
unshackle serve --caddy
|
|
```
|
|
|
|
---
|
|
|
|
## `util`
|
|
|
|
Various helper media utilities. When you give a command a directory, it processes every `.mkv`/`.mp4` inside it in natural (S01E01 before S01E10) order.
|
|
|
|
```
|
|
unshackle util COMMAND [ARGS]...
|
|
```
|
|
|
|
### `util refresh-services`
|
|
|
|
```
|
|
unshackle util refresh-services
|
|
```
|
|
|
|
Force a refresh (git pull / hard reset) of all service repos configured under `directories.services`. This updates the clones on disk. A server that is already running reloads the changed services through `POST /api/maintenance/refresh-services` or `serve.services_refresh_interval` instead.
|
|
|
|
### `util crop PATH ASPECT`
|
|
|
|
Losslessly crop H.264/H.265 video at the bitstream level. `ASPECT` is a `W:H` target such as `2.39:1`.
|
|
|
|
| Option | Default | Description |
|
|
|---|---|---|
|
|
| `--letter` / `--pillar` | `--letter` | Crop top/bottom (`--letter`) or the sides (`--pillar`). |
|
|
| `-o`, `--offset` | `0` | Fine-tune the computed crop area if not perfectly centred. |
|
|
| `-p`, `--preview` | off | Preview the crop in MPV (or FFplay) instead of writing a file. |
|
|
|
|
### `util range PATH`
|
|
|
|
Losslessly set the video range flag to full or limited at the bitstream level.
|
|
|
|
| Option | Default | Description |
|
|
|---|---|---|
|
|
| `--full` / `--limited` | - | Full (0-255) or limited (16-235) range. |
|
|
| `-p`, `--preview` | off | Preview instead of writing a file. |
|
|
|
|
### `util test PATH`
|
|
|
|
Decode an entire video with FFmpeg and report any corruptions or errors. By default it does a test of every track. It cannot do a test of subtitles.
|
|
|
|
| Option | Default | Description |
|
|
|---|---|---|
|
|
| `-m`, `--map` | `0` | Do a test of specific tracks with FFmpeg's `-map`, for example `0:v:0` or `0:a`. |
|
|
|
|
!!! example
|
|
```shell
|
|
unshackle util refresh-services
|
|
unshackle util crop video.mkv 2.39:1
|
|
unshackle util crop ./season/ 16:9 --pillar -o 10
|
|
unshackle util range video.mkv --full
|
|
unshackle util test video.mkv -m 0:v:0
|
|
```
|
|
|
|
---
|
|
|
|
## See also
|
|
|
|
- [Installation](../getting-started/installation.md): install unshackle and its dependencies.
|
|
- [Quickstart](../getting-started/quickstart.md): your first download.
|
|
- [Configuration file](../getting-started/configuration-file.md): set defaults for any `dl` flag and configure vaults, proxies, and directories.
|