mirror of
https://github.com/unshackle-dl/unshackle.git
synced 2026-11-12 20:15:10 +00:00
Merge branch 'dev' into feat/downloader-speed
# Conflicts: # unshackle/core/downloaders/requests.py # unshackle/core/manifests/dash.py
This commit is contained in:
+182
-29
@@ -37,7 +37,7 @@ This page assumes you already know the basics and want precise details.
|
||||
| [DRM & CDM](#drm-cdm) | `cdm`, `remote_cdm`, `decryption` |
|
||||
| [Network & proxy](#network-proxy) | `network`, `headers`, `proxy_providers` |
|
||||
| [Key vaults](#key-vaults) | `key_vaults`, `vault_timeout` |
|
||||
| [External API keys](#external-api-keys) | `tmdb_api_key`, `simkl_client_id`, `decrypt_labs_api_key`, `ipinfo_api_key` |
|
||||
| [External API keys](#external-api-keys) | `imdb_api_enabled`, `omdb_api_key`, `tmdb_api_key`, `simkl_client_id`, `decrypt_labs_api_key`, `ipinfo_api_key` |
|
||||
| [Caching & updates](#caching-updates) | `title_cache_enabled`, `title_cache_time`, `title_cache_max_retention`, `update_checks`, `update_check_interval` |
|
||||
| [Logging, privacy & debug](#logging-privacy-debug) | `redact_paths`, `debug`, `debug_keys`, `debug_requests`, `set_terminal_bg` |
|
||||
| [Deprecated & removed](#deprecated-removed-keys) | `curl_impersonate`, `downloader`, `scene_naming` |
|
||||
@@ -79,11 +79,11 @@ directories:
|
||||
| `data` | path | `unshackle/` | ❌ protected | Base for the data subdirectories above. |
|
||||
| `core_dir` | path | `unshackle/core` | ❌ protected | Package core. |
|
||||
| `namespace_dir` | path | `unshackle/` | ❌ protected | Package root. |
|
||||
| `app_dirs` | — | `AppDirs("unshackle", False)` | ❌ protected | Internal AppDirs instance. |
|
||||
| `app_dirs` | - | `AppDirs("unshackle", False)` | ❌ protected | Internal AppDirs instance. |
|
||||
|
||||
!!! note "The `services` directory is special"
|
||||
`services` may be a **list**, and each entry can be either a local directory or a
|
||||
**repository spec**: a git URL (`https://…`, `ssh://…`, `git@…`, or anything ending in
|
||||
**repository spec**: a git URL (`https://...`, `ssh://...`, `git@...`, or anything ending in
|
||||
`.git`) or `owner/repo` shorthand. Repo specs are cloned and updated automatically; plain
|
||||
paths are used as-is. **List order is priority**: the first source to define a service
|
||||
tag wins, so put your own local service directories **last** to make them fallbacks.
|
||||
@@ -142,8 +142,8 @@ runtime.
|
||||
|
||||
- **Type:** `dict` keyed by service tag · **Default:** `{}`
|
||||
|
||||
Per-service configuration, keyed by the canonical service tag (for example `AMZN`, `NF`,
|
||||
`DSNP`). unshackle reads several well-known sub-keys out of each service's block:
|
||||
Per-service configuration, keyed by the canonical service tag (for example `EXAMPLE1`, `EXAMPLE2`,
|
||||
`EXAMPLE3`). unshackle reads several well-known sub-keys out of each service's block:
|
||||
|
||||
- **`proxy_map`**: a dict mapping `"provider:query"` or `"query"` to a proxy value, used to
|
||||
auto-select a proxy for that service.
|
||||
@@ -163,11 +163,11 @@ the service as `self.config`.
|
||||
|
||||
```yaml
|
||||
services:
|
||||
AMZN:
|
||||
EXAMPLE1:
|
||||
proxy_map:
|
||||
default: us
|
||||
title_map:
|
||||
"The Grand Tour: The Movie": "The Grand Tour Presents The Movie"
|
||||
"My Show: The Movie": "My Show Presents The Movie"
|
||||
```
|
||||
|
||||
### `credentials`
|
||||
@@ -180,8 +180,8 @@ objects; the credential's SHA-1 is also used as an account hash for cache keys.
|
||||
|
||||
```yaml
|
||||
credentials:
|
||||
NF: user@example.com:hunter2
|
||||
AMZN:
|
||||
EXAMPLE2: user@example.com:hunter2
|
||||
EXAMPLE1:
|
||||
- primary@example.com:pw1
|
||||
- secondary@example.com:pw2
|
||||
```
|
||||
@@ -230,13 +230,46 @@ CLI commands that run against the remote server.
|
||||
|
||||
- **Type:** `dict` · **Default:** `{}`
|
||||
|
||||
Configuration for the `serve` command (the built-in REST API server).
|
||||
Configuration for the `serve` command (the built-in REST API server). The full server guide
|
||||
is the [REST API](../dev/rest-api/index.md) section; these are the config keys.
|
||||
|
||||
| Sub-key | Type | Default | Description |
|
||||
|---------|------|---------|-------------|
|
||||
| `api_secret` | str | *(unset)* | Master secret accepted in the `X-Secret-Key` header. |
|
||||
| `users` | dict | `{}` | Per-user API keys and their allowlists (see below). |
|
||||
| `services` | list | *(unset)* | Global service allowlist. Omit to allow all. |
|
||||
| `remote_only` | bool | `false` | Run without a local `output_template` (CORS/Cloudflare-friendly). |
|
||||
| `session_ttl` | int (s) | `300` | Lifetime of an interactive auth session. |
|
||||
| `max_sessions` | int | `100` | Maximum concurrent sessions. |
|
||||
| `history_limit` | int | `100` | How many finished jobs to retain in history. |
|
||||
| `compression_level` | int | `1` | gzip level for responses. |
|
||||
| `cdm_overrides` | dict | *(unset)* | Allowed per-request CDM overrides. |
|
||||
| `allow_job_credentials` | bool | `false` | Permit clients to supply credentials per job. |
|
||||
| `devices` | list | *(auto)* | Widevine devices offered; auto-filled from `directories.wvds`. |
|
||||
| `playready_devices` | list | *(auto)* | PlayReady devices; auto-filled from `directories.prds`. |
|
||||
| `country` / `locations` | str / dict | *(unset)* | Advertised region metadata. |
|
||||
|
||||
Each entry under `users` is keyed by that user's API key and may set its own `services`,
|
||||
`devices`, and `playready_devices` allowlists, narrowing the global ones.
|
||||
|
||||
```yaml
|
||||
serve:
|
||||
api_secret: change-me
|
||||
remote_only: true
|
||||
services: [EXAMPLE1, EXAMPLE2]
|
||||
# server-wide download defaults (same keys as the `dl:` block)
|
||||
downloads: 3
|
||||
best_available: true
|
||||
users:
|
||||
a1b2c3d4: # this user's API key
|
||||
services: [EXAMPLE1] # may only use EXAMPLE1
|
||||
```
|
||||
|
||||
!!! tip "Declaring `dl` defaults under `serve`"
|
||||
You can nest `dl` flags (`downloads`, `workers`, `best_available`, and so on) inside
|
||||
`serve`. The point is to raise concurrency and behaviour defaults **server-wide** (every
|
||||
request the server handles picks them up) without having to change each client call
|
||||
individually.
|
||||
You can set any [`dl`](#dl) flag key (`downloads`, `workers`, `best_available`, and so on)
|
||||
directly inside `serve`. The point is to raise concurrency and behaviour defaults
|
||||
**server-wide** (every request the server handles picks them up) without having to change
|
||||
each client call individually.
|
||||
|
||||
---
|
||||
|
||||
@@ -246,15 +279,117 @@ Configuration for the `serve` command (the built-in REST API server).
|
||||
|
||||
- **Type:** `dict` · **Default:** `{}`
|
||||
|
||||
Default options forwarded to the `dl` command. Anything you would otherwise pass as a `dl`
|
||||
flag can be given a persistent default here. See [Downloading](../guide/downloading.md) for
|
||||
the flags themselves.
|
||||
Persistent defaults for the `dl` command. This block is used as Click's `default_map`, so
|
||||
**any** `dl` flag can be given a default here and it applies to every download without you
|
||||
typing it. See [Downloading](../guide/downloading.md) and the
|
||||
[CLI Reference](../guide/cli-reference.md) for what each flag does.
|
||||
|
||||
**Key naming.** A key is the flag's long name with dashes replaced by underscores
|
||||
(`--best-available` → `best_available`, `--sub-format` → `sub_format`). A few keys are named
|
||||
after the flag's internal destination rather than its visible name; set these exact keys:
|
||||
|
||||
| Flag | Config key |
|
||||
|------|-----------|
|
||||
| `-r` / `--range` | `range` |
|
||||
| `--list` | `list` |
|
||||
| `--tmdb` | `tmdb_id` |
|
||||
| `--imdb` | `imdb_id` |
|
||||
| `--animeapi` | `animeapi_id` |
|
||||
| `-naa` / `--noatmos` | `no_atmos` |
|
||||
| `-o` / `--output` | `output_dir` |
|
||||
| `--cdm-only` / `--vaults-only` | `cdm_only` |
|
||||
|
||||
**Precedence** (highest first): an explicit CLI flag or environment variable → a per-service
|
||||
[`services.<TAG>.dl`](#services-auth) override → this global `dl:` block → the built-in
|
||||
default. In other words, config only fills in options you did not set on the command line.
|
||||
|
||||
Common keys (a useful subset; every `dl` flag works):
|
||||
|
||||
| Key | Type | Default | Sets |
|
||||
|-----|------|---------|------|
|
||||
| `lang` | list | `["orig"]` | Video/audio language(s); `orig` = original language. |
|
||||
| `a_lang` / `v_lang` | list | `[]` | Audio- / video-only language override. |
|
||||
| `s_lang` | list | `["all"]` | Subtitle language(s). |
|
||||
| `quality` | list | `[]` (best) | Resolution(s), e.g. `[1080]`. |
|
||||
| `vcodec` | list | `[]` (any) | Video codec(s), e.g. `[H265]`. |
|
||||
| `acodec` | list | `[]` (any) | Audio codec(s), e.g. `[EC3]`. |
|
||||
| `range` | list | `["SDR"]` | Colour range(s): `SDR`, `HDR10`, `HDR10+`, `DV`. |
|
||||
| `channels` | float | *(unset)* | Audio channels, e.g. `6` for 5.1. |
|
||||
| `sub_format` | str | *(unset)* | Convert subtitles to this format (`srt`, `vtt`, `original`, ...). |
|
||||
| `forced_subs` | bool | `false` | Include forced subtitle tracks. |
|
||||
| `no_subs` / `no_audio` / `no_chapters` | bool | `false` | Skip that track type. |
|
||||
| `downloads` | int | `1` | Tracks downloaded concurrently. |
|
||||
| `workers` | int | *(downloader default)* | Threads per track. |
|
||||
| `slow` | str | *(unset)* | Inter-title delay, e.g. `"20-40"`. |
|
||||
| `best_available` | bool | `false` | Fall back to best quality if the request is unavailable. |
|
||||
| `proxy` | str | *(unset)* | Default proxy URI or 2-letter country. |
|
||||
| `no_folder` | bool | `false` | Do not create a per-title folder. |
|
||||
|
||||
```yaml title="Global download defaults"
|
||||
dl:
|
||||
lang: [en]
|
||||
quality: [1080]
|
||||
range: [HDR10]
|
||||
vcodec: [H265]
|
||||
sub_format: srt
|
||||
downloads: 2
|
||||
```
|
||||
|
||||
!!! tip "Per-service overrides"
|
||||
Nest a `dl` block under a service in [`services`](#services-auth) to override these defaults
|
||||
for just that service. It uses the same keys and wins over the global `dl:` block (but still
|
||||
loses to an explicit CLI flag).
|
||||
|
||||
```yaml
|
||||
dl:
|
||||
lang: [en] # global default
|
||||
services:
|
||||
EXAMPLE1:
|
||||
dl:
|
||||
lang: [en, ja] # EXAMPLE1 downloads both; everything else stays English
|
||||
range: [DV]
|
||||
```
|
||||
|
||||
!!! note "`serve` uses these same keys"
|
||||
The [`serve`](#serve) block accepts the same `dl` option keys at its top level to set
|
||||
server-wide download defaults for every request it handles.
|
||||
|
||||
### `subtitle`
|
||||
|
||||
- **Type:** `dict` · **Default:** `{}`
|
||||
|
||||
Subtitle handling options. See [Subtitles](../guide/subtitles.md).
|
||||
Subtitle handling: SDH stripping, format conversion, and whether subtitles are muxed in or
|
||||
written as sidecar files. See [Subtitles](../guide/subtitles.md) for the full guide.
|
||||
|
||||
| Sub-key | Type | Default | Description |
|
||||
|---------|------|---------|-------------|
|
||||
| `strip_sdh` | bool | `true` | Strip SDH/CC cues (hearing-impaired annotations) into a clean track. |
|
||||
| `sdh_method` | str | `"auto"` | SDH-stripping backend to use. |
|
||||
| `preserve_formatting` | bool | `true` | Keep styling/positioning when converting or stripping. |
|
||||
| `convert_before_strip` | bool | `true` | Convert to the working format before stripping SDH. |
|
||||
| `conversion_method` | str | `"auto"` | Subtitle conversion backend. |
|
||||
| `preferred_conversion_method` | str | *(unset)* | Preferred converter when several are available. |
|
||||
| `output_mode` | str | `"mux"` | `mux` embeds subtitles in the MKV; `sidecar` writes separate files. |
|
||||
| `sidecar_format` | str | `"srt"` | Format for sidecar files when `output_mode: sidecar`. |
|
||||
| `type_priority` | list | *(unset)* | Ordered ranking of subtitle types (`forced`, `normal`, `sdh`; CC counts as SDH) that sorts the variants within each language. Types you leave out fall to the end. |
|
||||
|
||||
```yaml
|
||||
subtitle:
|
||||
strip_sdh: true
|
||||
output_mode: sidecar
|
||||
sidecar_format: srt
|
||||
```
|
||||
|
||||
!!! note "`type_priority` also picks the default subtitle"
|
||||
`type_priority` sorts the tracks within each language, and at mux time the first track
|
||||
in the default subtitle language gets the `default` flag. The built-in order is `forced`,
|
||||
`normal`, `sdh`, which means a forced track becomes default whenever one exists. If you
|
||||
want the full dialogue track as default instead, set:
|
||||
|
||||
```yaml
|
||||
subtitle:
|
||||
type_priority: [normal, sdh, forced]
|
||||
```
|
||||
|
||||
### `audio`
|
||||
|
||||
@@ -284,6 +419,21 @@ audio:
|
||||
|
||||
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}`. |
|
||||
| `merge_audio` | bool | `true` | Merge all audio into one file. `--split-audio` on the CLI flips this off. |
|
||||
| `merge_video` | bool | `false` | Merge all video tracks into one file. `--merge-video` on the CLI flips this on. |
|
||||
|
||||
```yaml
|
||||
muxing:
|
||||
set_title: true
|
||||
default_language:
|
||||
audio: en
|
||||
subtitle: en
|
||||
```
|
||||
|
||||
### `language_tags`
|
||||
|
||||
- **Type:** `dict` · **Default:** `{}`
|
||||
@@ -381,7 +531,7 @@ then `default`.
|
||||
```yaml
|
||||
cdm:
|
||||
default: chromecdm_l3
|
||||
NF: android_l1
|
||||
EXAMPLE2: android_l1
|
||||
```
|
||||
|
||||
A value may also be a **nested dict** for advanced selection by quality, DRM system, or
|
||||
@@ -389,7 +539,7 @@ profile:
|
||||
|
||||
```yaml
|
||||
cdm:
|
||||
AMZN:
|
||||
EXAMPLE1:
|
||||
">=1080": android_l1 # by track height
|
||||
"<1080": chromecdm_l3
|
||||
widevine: android_l1 # by DRM system
|
||||
@@ -523,13 +673,13 @@ the full provider guide. Recognised providers and their exit ports:
|
||||
| Provider | Config key | Credentials | Proxy scheme/port |
|
||||
|----------|-----------|-------------|-------------------|
|
||||
| Basic (static) | `basic` | country → URI(s) | as specified |
|
||||
| NordVPN | `nordvpn` | 48-char **service** credentials | `https://…:89` |
|
||||
| Surfshark | `surfsharkvpn` | 48-char **service** credentials | `https://…:443` |
|
||||
| Windscribe | `windscribevpn` | service credentials | `https://…:443` |
|
||||
| ExpressVPN | `expressvpn` | browser cookies / token cache | `https://cat:…@…:443` |
|
||||
| ProtonVPN | `protonvpn` | TV login or exported cookies | `https://…:4443` (or `:443` Secure Core) |
|
||||
| NordVPN | `nordvpn` | 48-char **service** credentials | `https://...:89` |
|
||||
| Surfshark | `surfsharkvpn` | 48-char **service** credentials | `https://...:443` |
|
||||
| Windscribe | `windscribevpn` | service credentials | `https://...:443` |
|
||||
| ExpressVPN | `expressvpn` | device login (`enable: true`) / token cache | `https://cat:...@...:443` |
|
||||
| ProtonVPN | `protonvpn` | TV login or exported cookies | `https://...:4443` (or `:443` Secure Core) |
|
||||
| Gluetun | `gluetun` | per-VPN keys/creds | `http://localhost:{port}` (local Docker) |
|
||||
| Hola | *(none, auto)* | none | `http://…:{peer}` |
|
||||
| Hola | *(none, auto)* | none | `http://...:{peer}` |
|
||||
|
||||
```yaml
|
||||
proxy_providers:
|
||||
@@ -546,7 +696,7 @@ proxy_providers:
|
||||
!!! note "Provider loading differs between CLI and REST server"
|
||||
The `dl` CLI loads all providers, including `windscribevpn` and `gluetun`. The REST API /
|
||||
remote-client path uses a separate resolver that does **not** load `windscribevpn` or
|
||||
`gluetun`. ExpressVPN and ProtonVPN also auto-load when their cookie file exists, and Hola
|
||||
`gluetun`. ExpressVPN and ProtonVPN also auto-load when their cached session exists, and Hola
|
||||
auto-loads whenever the `hola-proxy` binary is present.
|
||||
|
||||
---
|
||||
@@ -606,6 +756,8 @@ All default to an empty string and enable optional metadata/geolocation features
|
||||
|
||||
| Key | Type | Default | Description |
|
||||
|-----|------|---------|-------------|
|
||||
| `imdb_api_enabled` | bool | `false` | Use the free IMDxAPI (api.tiffara.com) metadata provider, which needs no API key. Off by default since the site has been unreliable. |
|
||||
| `omdb_api_key` | str | `""` | [OMDb](https://www.omdbapi.com/) API key for IMDb metadata lookups; a more reliable alternative to IMDxAPI. Free keys are available on the OMDb site. |
|
||||
| `tmdb_api_key` | str | `""` | TMDB API key for metadata enrichment and external-ID tags. |
|
||||
| `simkl_client_id` | str | `""` | SIMKL client ID for metadata lookups; an alternative/fallback source to TMDB. |
|
||||
| `decrypt_labs_api_key` | str | `""` | Global Decrypt Labs API key (used by remote CDM / vault). |
|
||||
@@ -704,12 +856,12 @@ headers:
|
||||
|
||||
cdm:
|
||||
default: chromecdm_l3
|
||||
NF: android_l1
|
||||
EXAMPLE2: android_l1
|
||||
|
||||
decryption: shaka
|
||||
|
||||
credentials:
|
||||
NF: user@example.com:hunter2
|
||||
EXAMPLE2: user@example.com:hunter2
|
||||
|
||||
output_template:
|
||||
movies: "{title}.{year}.{quality?}.{source}-{tag}"
|
||||
@@ -729,6 +881,7 @@ proxy_providers:
|
||||
basic:
|
||||
us: http://user:pass@1.2.3.4:8080
|
||||
|
||||
omdb_api_key: "your-omdb-key"
|
||||
tmdb_api_key: "your-tmdb-key"
|
||||
title_cache_time: 3600
|
||||
redact_paths: true
|
||||
|
||||
Reference in New Issue
Block a user