docs: add configuration documentation WIP

This commit is contained in:
Andy
2026-01-30 16:34:49 -07:00
parent c352884c17
commit 5cf488cb34
9 changed files with 1170 additions and 169 deletions

104
docs/ADVANCED_CONFIG.md Normal file
View File

@@ -0,0 +1,104 @@
# Advanced & System Configuration
This document covers advanced features, debugging, and system-level configuration options.
## serve (dict)
Configuration data for pywidevine's serve functionality run through unshackle.
This effectively allows you to run `unshackle serve` to start serving pywidevine Serve-compliant CDMs right from your
local widevine device files.
- `api_secret` - Secret key for REST API authentication. When set, enables the REST API server alongside the CDM serve functionality. This key is required for authenticating API requests.
- `devices` - List of Widevine device files (.wvd). If not specified, auto-populated from the WVDs directory.
- `playready_devices` - List of PlayReady device files (.prd). If not specified, auto-populated from the PRDs directory.
- `users` - Dictionary mapping user secret keys to their access configuration:
- `devices` - List of Widevine devices this user can access
- `playready_devices` - List of PlayReady devices this user can access
- `username` - Internal logging name for the user (not visible to users)
For example,
```yaml
serve:
api_secret: "your-secret-key-here"
users:
secret_key_for_jane: # 32bit hex recommended, case-sensitive
devices: # list of allowed Widevine devices for this user
- generic_nexus_4464_l3
playready_devices: # list of allowed PlayReady devices for this user
- my_playready_device
username: jane # only for internal logging, users will not see this name
secret_key_for_james:
devices:
- generic_nexus_4464_l3
username: james
secret_key_for_john:
devices:
- generic_nexus_4464_l3
username: john
# devices can be manually specified by path if you don't want to add it to
# unshackle's WVDs directory for whatever reason
# devices:
# - 'C:\Users\john\Devices\test_devices_001.wvd'
```
---
## debug (bool)
Enables comprehensive debug logging. Default: `false`
When enabled (either via config or the `-d`/`--debug` CLI flag):
- Sets console log level to DEBUG for verbose output
- Creates JSON Lines (`.jsonl`) debug log files with structured logging
- Logs detailed information about sessions, service configuration, DRM operations, and errors with full stack traces
For example,
```yaml
debug: true
```
---
## debug_keys (bool)
Controls whether actual decryption keys (CEKs) are included in debug logs. Default: `false`
When enabled:
- Content encryption keys are logged in debug output
- Only affects `content_key` and `key` fields (the actual CEKs)
- Key metadata (`kid`, `keys_count`, `key_id`) is always logged regardless of this setting
- Passwords, tokens, cookies, and session tokens remain redacted even when enabled
For example,
```yaml
debug_keys: true
```
---
## set_terminal_bg (bool)
Controls whether unshackle should set the terminal background color. Default: `false`
For example,
```yaml
set_terminal_bg: true
```
---
## update_checks (bool)
Check for updates from the GitHub repository on startup. Default: `true`.
---
## update_check_interval (int)
How often to check for updates, in hours. Default: `24`.
---

174
docs/DOWNLOAD_CONFIG.md Normal file
View File

@@ -0,0 +1,174 @@
# Download & Processing Configuration
This document covers configuration options related to downloading and processing media content.
## aria2c (dict)
- `max_concurrent_downloads`
Maximum number of parallel downloads. Default: `min(32,(cpu_count+4))`
Note: Overrides the `max_workers` parameter of the aria2(c) downloader function.
- `max_connection_per_server`
Maximum number of connections to one server for each download. Default: `1`
- `split`
Split a file into N chunks and download each chunk on its own connection. Default: `5`
- `file_allocation`
Specify file allocation method. Default: `"prealloc"`
- `"none"` doesn't pre-allocate file space.
- `"prealloc"` pre-allocates file space before download begins. This may take some time depending on the size of the
file.
- `"falloc"` is your best choice if you are using newer file systems such as ext4 (with extents support), btrfs, xfs
or NTFS (MinGW build only). It allocates large(few GiB) files almost instantly. Don't use falloc with legacy file
systems such as ext3 and FAT32 because it takes almost same time as prealloc, and it blocks aria2 entirely until
allocation finishes. falloc may not be available if your system doesn't have posix_fallocate(3) function.
- `"trunc"` uses ftruncate(2) system call or platform-specific counterpart to truncate a file to a specified length.
---
## curl_impersonate (dict)
- `browser` - The Browser to impersonate as. A list of available Browsers and Versions are listed here:
<https://github.com/yifeikong/curl_cffi#sessions>
Default: `"chrome124"`
For example,
```yaml
curl_impersonate:
browser: "chrome120"
```
---
## downloader (str | dict)
Choose what software to use to download data throughout unshackle where needed.
You may provide a single downloader globally or a mapping of service tags to
downloaders.
Options:
- `requests` (default) - <https://github.com/psf/requests>
- `aria2c` - <https://github.com/aria2/aria2>
- `curl_impersonate` - <https://github.com/yifeikong/curl-impersonate> (via <https://github.com/yifeikong/curl_cffi>)
- `n_m3u8dl_re` - <https://github.com/nilaoda/N_m3u8DL-RE>
Note that aria2c can reach the highest speeds as it utilizes threading and more connections than the other downloaders. However, aria2c can also be one of the more unstable downloaders. It will work one day, then not another day. It also does not support HTTP(S) proxies while the other downloaders do.
Example mapping:
```yaml
downloader:
NF: requests
AMZN: n_m3u8dl_re
DSNP: n_m3u8dl_re
default: requests
```
The `default` entry is optional. If omitted, `requests` will be used for services not listed.
---
## n_m3u8dl_re (dict)
Configuration for N_m3u8DL-RE downloader. This downloader is particularly useful for HLS streams.
- `thread_count`
Number of threads to use for downloading. Default: Uses the same value as max_workers from the command.
- `ad_keyword`
Keyword to identify and potentially skip advertisement segments. Default: `None`
- `use_proxy`
Whether to use proxy when downloading. Default: `true`
- `retry_count`
Number of times to retry failed downloads. Default: `10`
For example,
```yaml
n_m3u8dl_re:
thread_count: 16
ad_keyword: "advertisement"
use_proxy: true
retry_count: 10
```
---
## dl (dict)
Pre-define default options and switches of the `dl` command.
The values will be ignored if explicitly set in the CLI call.
The Key must be the same value Python click would resolve it to as an argument.
E.g., `@click.option("-r", "--range", "range_", type=...` actually resolves as `range_` variable.
For example to set the default primary language to download to German,
```yaml
lang: de
```
You can also set multiple preferred languages using a list, e.g.,
```yaml
lang:
- en
- fr
```
to set how many tracks to download concurrently to 4 and download threads to 16,
```yaml
downloads: 4
workers: 16
```
to set `--bitrate=CVBR` for the AMZN service,
```yaml
lang: de
AMZN:
bitrate: CVBR
```
or to change the output subtitle format from the default (original format) to WebVTT,
```yaml
sub_format: vtt
```
---
## decryption (str | dict)
Choose what software to use to decrypt DRM-protected content throughout unshackle where needed.
You may provide a single decryption method globally or a mapping of service tags to
decryption methods.
Options:
- `shaka` (default) - Shaka Packager - <https://github.com/shaka-project/shaka-packager>
- `mp4decrypt` - mp4decrypt from Bento4 - <https://github.com/axiomatic-systems/Bento4>
Note that Shaka Packager is the traditional method and works with most services. mp4decrypt
is an alternative that may work better with certain services that have specific encryption formats.
Example mapping:
```yaml
decryption:
ATVP: mp4decrypt
AMZN: shaka
default: shaka
```
The `default` entry is optional. If omitted, `shaka` will be used for services not listed.
Simple configuration (single method for all services):
```yaml
decryption: mp4decrypt
```
---

403
docs/DRM_CONFIG.md Normal file
View File

@@ -0,0 +1,403 @@
# DRM & CDM Configuration
This document covers Digital Rights Management (DRM) and Content Decryption Module (CDM) configuration options.
## cdm (dict)
Pre-define which Widevine or PlayReady device to use for each Service by Service Tag as Key (case-sensitive).
The value should be a WVD or PRD filename without the file extension. When
loading the device, unshackle will look in both the `WVDs` and `PRDs` directories
for a matching file.
For example,
```yaml
AMZN: chromecdm_903_l3
NF: nexus_6_l1
```
You may also specify this device based on the profile used.
For example,
```yaml
AMZN: chromecdm_903_l3
NF: nexus_6_l1
DSNP:
john_sd: chromecdm_903_l3
jane_uhd: nexus_5_l1
```
You can also specify a fallback value to predefine if a match was not made.
This can be done using `default` key. This can help reduce redundancy in your specifications.
For example, the following has the same result as the previous example, as well as all other
services and profiles being pre-defined to use `chromecdm_903_l3`.
```yaml
NF: nexus_6_l1
DSNP:
jane_uhd: nexus_5_l1
default: chromecdm_903_l3
```
---
## remote_cdm (list\[dict])
Configure remote CDM (Content Decryption Module) APIs to use for decrypting DRM-protected content.
Remote CDMs allow you to use high-security CDMs (L1/L2 for Widevine, SL2000/SL3000 for PlayReady) without
having the physical device files locally.
unshackle supports multiple types of remote CDM providers:
1. **DecryptLabs CDM** - Official DecryptLabs KeyXtractor API with intelligent caching
2. **Custom API CDM** - Highly configurable adapter for any third-party CDM API
3. **Legacy PyWidevine Serve** - Standard pywidevine serve-compliant APIs
The name of each defined remote CDM can be referenced in the `cdm` configuration as if it was a local device file.
### DecryptLabs Remote CDM
DecryptLabs provides a professional CDM API service with support for multiple device types and intelligent key caching.
**Supported Devices:**
- **Widevine**: `ChromeCDM` (L3), `L1` (Security Level 1), `L2` (Security Level 2)
- **PlayReady**: `SL2` (SL2000), `SL3` (SL3000)
**Configuration:**
```yaml
remote_cdm:
# Widevine L1 Device
- name: decrypt_labs_l1
type: decrypt_labs # Required: identifies as DecryptLabs CDM
device_name: L1 # Required: must match exactly (L1, L2, ChromeCDM, SL2, SL3)
host: https://keyxtractor.decryptlabs.com
secret: YOUR_API_KEY # Your DecryptLabs API key
# Widevine L2 Device
- name: decrypt_labs_l2
type: decrypt_labs
device_name: L2
host: https://keyxtractor.decryptlabs.com
secret: YOUR_API_KEY
# Chrome CDM (L3)
- name: decrypt_labs_chrome
type: decrypt_labs
device_name: ChromeCDM
host: https://keyxtractor.decryptlabs.com
secret: YOUR_API_KEY
# PlayReady SL2000
- name: decrypt_labs_playready_sl2
type: decrypt_labs
device_name: SL2
device_type: PLAYREADY # Required for PlayReady
host: https://keyxtractor.decryptlabs.com
secret: YOUR_API_KEY
# PlayReady SL3000
- name: decrypt_labs_playready_sl3
type: decrypt_labs
device_name: SL3
device_type: PLAYREADY
host: https://keyxtractor.decryptlabs.com
secret: YOUR_API_KEY
```
**Features:**
- Intelligent key caching system (reduces API calls)
- Automatic integration with unshackle's vault system
- Support for both Widevine and PlayReady
- Multiple security levels (L1, L2, L3, SL2000, SL3000)
**Note:** The `device_type` and `security_level` fields are optional metadata. They don't affect API communication
but are used for internal device identification.
### Custom API Remote CDM
A highly configurable CDM adapter that can work with virtually any third-party CDM API through YAML configuration.
This allows you to integrate custom CDM services without writing code.
**Basic Example:**
```yaml
remote_cdm:
- name: custom_chrome_cdm
type: custom_api # Required: identifies as Custom API CDM
host: https://your-cdm-api.com
timeout: 30 # Optional: request timeout in seconds
device:
name: ChromeCDM
type: CHROME # CHROME, ANDROID, PLAYREADY
system_id: 27175
security_level: 3
auth:
type: bearer # bearer, header, basic, body
key: YOUR_API_TOKEN
endpoints:
get_request:
path: /get-challenge
method: POST
decrypt_response:
path: /get-keys
method: POST
caching:
enabled: true # Enable key caching
use_vaults: true # Integrate with vault system
```
**Advanced Example with Field Mapping:**
```yaml
remote_cdm:
- name: advanced_custom_api
type: custom_api
host: https://api.example.com
device:
name: L1
type: ANDROID
security_level: 1
# Authentication configuration
auth:
type: header
header_name: X-API-Key
key: YOUR_SECRET_KEY
custom_headers:
User-Agent: Unshackle/2.0.0
X-Client-Version: "1.0"
# Endpoint configuration
endpoints:
get_request:
path: /v2/challenge
method: POST
timeout: 30
decrypt_response:
path: /v2/decrypt
method: POST
timeout: 30
# Request parameter mapping
request_mapping:
get_request:
param_names:
init_data: pssh # Rename 'init_data' to 'pssh'
scheme: device_type # Rename 'scheme' to 'device_type'
static_params:
api_version: "2.0" # Add static parameter
decrypt_response:
param_names:
license_request: challenge
license_response: license
# Response field mapping
response_mapping:
get_request:
fields:
challenge: data.challenge # Deep field access
session_id: session.id
success_conditions:
- status == 'ok' # Validate response
decrypt_response:
fields:
keys: data.keys
key_fields:
kid: key_id # Map 'kid' field
key: content_key # Map 'key' field
caching:
enabled: true
use_vaults: true
check_cached_first: true # Check cache before API calls
```
**Supported Authentication Types:**
- `bearer` - Bearer token authentication
- `header` - Custom header authentication
- `basic` - HTTP Basic authentication
- `body` - Credentials in request body
### Legacy PyWidevine Serve Format
Standard [pywidevine] serve-compliant remote CDM configuration (backwards compatibility).
```yaml
remote_cdm:
- name: legacy_chrome_cdm
device_name: chrome
device_type: CHROME
system_id: 27175
security_level: 3
host: https://domain.com/api
secret: secret_key
```
**Note:** If the `type` field is not specified, the entry is treated as a legacy pywidevine serve CDM.
[pywidevine]: https://github.com/rlaphoenix/pywidevine
---
## decrypt_labs_api_key (str)
API key for DecryptLabs CDM service integration.
When set, enables the use of DecryptLabs remote CDM services in your `remote_cdm` configuration.
This is used specifically for `type: "decrypt_labs"` entries in the remote CDM list.
For example,
```yaml
decrypt_labs_api_key: "your_api_key_here"
```
**Note**: This is different from the per-CDM `secret` field in `remote_cdm` entries. This provides a global
API key that can be referenced across multiple DecryptLabs CDM configurations. If a `remote_cdm` entry with
`type: "decrypt_labs"` does not have a `secret` field specified, the global `decrypt_labs_api_key` will be
used as a fallback.
---
## key_vaults (list\[dict])
Key Vaults store your obtained Content Encryption Keys (CEKs) and Key IDs per-service.
This can help reduce unnecessary License calls even during the first download. This is because a Service may
provide the same Key ID and CEK for both Video and Audio, as well as for multiple resolutions or bitrates.
You can have as many Key Vaults as you would like. It's nice to share Key Vaults or use a unified Vault on
Teams as sharing CEKs immediately can help reduce License calls drastically.
Four types of Vaults are in the Core codebase: API, SQLite, MySQL, and HTTP. API and HTTP make HTTP requests to a RESTful API,
whereas SQLite and MySQL directly connect to an SQLite or MySQL Database.
Note: SQLite and MySQL vaults have to connect directly to the Host/IP. It cannot be in front of a PHP API or such.
Beware that some Hosting Providers do not let you access the MySQL server outside their intranet and may not be
accessible outside their hosting platform.
Additional behavior:
- `no_push` (bool): Optional per-vault flag. When `true`, the vault will not receive pushed keys (writes) but
will still be queried and can provide keys for lookups. Useful for read-only/backup vaults.
### Using an API Vault
API vaults use a specific HTTP request format, therefore API or HTTP Key Vault APIs from other projects or services may
not work in unshackle. The API format can be seen in the [API Vault Code](unshackle/vaults/API.py).
```yaml
- type: API
name: "John#0001's Vault" # arbitrary vault name
uri: "https://key-vault.example.com" # api base uri (can also be an IP or IP:Port)
# uri: "127.0.0.1:80/key-vault"
# uri: "https://api.example.com/key-vault"
token: "random secret key" # authorization token
# no_push: true # optional; make this API vault read-only (lookups only)
```
### Using a MySQL Vault
MySQL vaults can be either MySQL or MariaDB servers. I recommend MariaDB.
A MySQL Vault can be on a local or remote network, but I recommend SQLite for local Vaults.
```yaml
- type: MySQL
name: "John#0001's Vault" # arbitrary vault name
host: "127.0.0.1" # host/ip
# port: 3306 # port (defaults to 3306)
database: vault # database used for unshackle
username: jane11
password: Doe123
# no_push: false # optional; defaults to false
```
I recommend giving only a trustable user (or yourself) CREATE permission and then use unshackle to cache at least one CEK
per Service to have it create the tables. If you don't give any user permissions to create tables, you will need to
make tables yourself.
- Use a password on all user accounts.
- Never use the root account with unshackle (even if it's you).
- Do not give multiple users the same username and/or password.
- Only give users access to the database used for unshackle.
- You may give trusted users CREATE permission so unshackle can create tables if needed.
- Other uses should only be given SELECT and INSERT permissions.
### Using an SQLite Vault
SQLite Vaults are usually only used for locally stored vaults. This vault may be stored on a mounted Cloud storage
drive, but I recommend using SQLite exclusively as an offline-only vault. Effectively this is your backup vault in
case something happens to your MySQL Vault.
```yaml
- type: SQLite
name: "My Local Vault" # arbitrary vault name
path: "C:/Users/Jane11/Documents/unshackle/data/key_vault.db"
# no_push: true # optional; commonly true for local backup vaults
```
**Note**: You do not need to create the file at the specified path.
SQLite will create a new SQLite database at that path if one does not exist.
Try not to accidentally move the `db` file once created without reflecting the change in the config, or you will end
up with multiple databases.
If you work on a Team I recommend every team member having their own SQLite Vault even if you all use a MySQL vault
together.
### Using an HTTP Vault
HTTP Vaults provide flexible HTTP-based key storage with support for multiple API modes. This vault type
is useful for integrating with various third-party key vault APIs.
```yaml
- type: HTTP
name: "My HTTP Vault"
host: "https://vault-api.example.com"
api_key: "your_api_key" # or use 'password' field
api_mode: "json" # query, json, or decrypt_labs
# username: "user" # required for query mode only
# no_push: false # optional; defaults to false
```
**Supported API Modes:**
- `query` - Uses GET requests with query parameters. Requires `username` field.
- `json` - Uses POST requests with JSON payloads. Token-based authentication.
- `decrypt_labs` - DecryptLabs API format. Read-only mode (`no_push` is forced to `true`).
**Example configurations:**
```yaml
# Query mode (requires username)
- type: HTTP
name: "Query Vault"
host: "https://api.example.com/keys"
username: "myuser"
password: "mypassword"
api_mode: "query"
# JSON mode
- type: HTTP
name: "JSON Vault"
host: "https://api.example.com/vault"
api_key: "secret_token"
api_mode: "json"
# DecryptLabs mode (read-only)
- type: HTTP
name: "DecryptLabs Cache"
host: "https://keyxtractor.decryptlabs.com/cache"
api_key: "your_decrypt_labs_api_key"
api_mode: "decrypt_labs"
```
**Note**: The `decrypt_labs` mode is always read-only and cannot receive pushed keys.
---

View File

@@ -25,10 +25,11 @@ Add to `~/.config/unshackle/unshackle.yaml`:
proxy_providers:
gluetun:
providers:
nordvpn:
vpn_type: wireguard
windscribe:
vpn_type: openvpn
credentials:
private_key: YOUR_PRIVATE_KEY
username: "YOUR_OPENVPN_USERNAME"
password: "YOUR_OPENVPN_PASSWORD"
```
### 2. Usage
@@ -36,57 +37,80 @@ proxy_providers:
Use 2-letter country codes directly:
```bash
uv run unshackle dl SERVICE CONTENT --proxy gluetun:nordvpn:us
uv run unshackle dl SERVICE CONTENT --proxy gluetun:nordvpn:uk
unshackle dl SERVICE CONTENT --proxy gluetun:windscribe:us
unshackle dl SERVICE CONTENT --proxy gluetun:windscribe:uk
```
Format: `gluetun:provider:region`
## Provider Credential Requirements
Each provider has different credential requirements. See the [Gluetun Wiki](https://github.com/qdm12/gluetun-wiki/tree/main/setup/providers) for complete details.
**OpenVPN (Recommended)**: Most providers support OpenVPN with just `username` and `password` - the simplest setup.
| Provider | VPN Type | Required Credentials |
|----------|----------|---------------------|
| NordVPN | WireGuard | `private_key` only |
| ProtonVPN | WireGuard | `private_key` only |
| Windscribe | WireGuard | `private_key`, `addresses`, `preshared_key` (all required) |
| Surfshark | WireGuard | `private_key`, `addresses` |
| Mullvad | WireGuard | `private_key`, `addresses` |
| IVPN | WireGuard | `private_key`, `addresses` |
| ExpressVPN | OpenVPN | `username`, `password` (no WireGuard support) |
| Any | OpenVPN | `username`, `password` |
**WireGuard**: Requires private keys and varies by provider. See the [Gluetun Wiki](https://github.com/qdm12/gluetun-wiki/tree/main/setup/providers) for provider-specific requirements.
### Configuration Examples
## Getting Your Credentials
### Windscribe (OpenVPN)
1. Go to [windscribe.com/getconfig/openvpn](https://windscribe.com/getconfig/openvpn)
2. Log in with your Windscribe account
3. Select any location and click "Get Config"
4. Copy the username and password shown
### NordVPN (OpenVPN)
1. Go to [NordVPN Service Credentials](https://my.nordaccount.com/dashboard/nordvpn/manual-configuration/service-credentials/)
2. Log in with your NordVPN account
3. Generate or view your service credentials
4. Copy the username and password
> **Note**: Use service credentials, NOT your account email/password.
### WireGuard Credentials (Advanced)
WireGuard requires private keys instead of username/password. See the [Gluetun Wiki](https://github.com/qdm12/gluetun-wiki/tree/main/setup/providers) for provider-specific WireGuard setup.
## Configuration Examples
**OpenVPN (Recommended)**
Most providers support OpenVPN with just username and password:
**NordVPN/ProtonVPN** (only private_key needed):
```yaml
providers:
windscribe:
vpn_type: openvpn
credentials:
username: YOUR_OPENVPN_USERNAME
password: YOUR_OPENVPN_PASSWORD
nordvpn:
vpn_type: openvpn
credentials:
username: YOUR_SERVICE_USERNAME
password: YOUR_SERVICE_PASSWORD
```
**WireGuard (Advanced)**
WireGuard can be faster but requires more complex credential setup:
```yaml
# NordVPN/ProtonVPN (only private_key needed)
providers:
nordvpn:
vpn_type: wireguard
credentials:
private_key: YOUR_PRIVATE_KEY
```
**Windscribe** (all three credentials required):
```yaml
providers:
# Windscribe (all three credentials required)
windscribe:
vpn_type: wireguard
credentials:
private_key: YOUR_PRIVATE_KEY
addresses: 10.x.x.x/32
preshared_key: YOUR_PRESHARED_KEY # Required, can be empty string
```
**OpenVPN** (any provider):
```yaml
providers:
expressvpn:
vpn_type: openvpn
credentials:
username: YOUR_USERNAME
password: YOUR_PASSWORD
preshared_key: YOUR_PRESHARED_KEY
```
## Server Selection

154
docs/NETWORK_CONFIG.md Normal file
View File

@@ -0,0 +1,154 @@
# Network & Proxy Configuration
This document covers network and proxy configuration options for bypassing geofencing and managing connections.
## proxy_providers (dict)
Enable external proxy provider services. These proxies will be used automatically where needed as defined by the
Service's GEOFENCE class property, but can also be explicitly used with `--proxy`. You can specify which provider
to use by prefixing it with the provider key name, e.g., `--proxy basic:de` or `--proxy nordvpn:de`. Some providers
support specific query formats for selecting a country/server.
### basic (dict[str, str|list])
Define a mapping of country to proxy to use where required.
The keys are region Alpha 2 Country Codes. Alpha 2 Country Codes are `[a-z]{2}` codes, e.g., `us`, `gb`, and `jp`.
Don't get this mixed up with language codes like `en` vs. `gb`, or `ja` vs. `jp`.
Do note that each key's value can be a list of strings, or a string. For example,
```yaml
us:
- "http://john%40email.tld:password123@proxy-us.domain.tld:8080"
- "http://jane%40email.tld:password456@proxy-us.domain2.tld:8080"
de: "https://127.0.0.1:8080"
```
Note that if multiple proxies are defined for a region, then by default one will be randomly chosen.
You can choose a specific one by specifying it's number, e.g., `--proxy basic:us2` will choose the
second proxy of the US list.
### nordvpn (dict)
Set your NordVPN Service credentials with `username` and `password` keys to automate the use of NordVPN as a Proxy
system where required.
You can also specify specific servers to use per-region with the `server_map` key.
Sometimes a specific server works best for a service than others, so hard-coding one for a day or two helps.
For example,
```yaml
username: zxqsR7C5CyGwmGb6KSvk8qsZ # example of the login format
password: wXVHmht22hhRKUEQ32PQVjCZ
server_map:
us: 12 # force US server #12 for US proxies
```
The username and password should NOT be your normal NordVPN Account Credentials.
They should be the `Service credentials` which can be found on your Nord Account Dashboard.
Once set, you can also specifically opt in to use a NordVPN proxy by specifying `--proxy=gb` or such.
You can even set a specific server number this way, e.g., `--proxy=gb2366`.
Note that `gb` is used instead of `uk` to be more consistent across regional systems.
### surfsharkvpn (dict)
Enable Surfshark VPN proxy service using Surfshark Service credentials (not your login password).
You may pin specific server IDs per region using `server_map`.
```yaml
username: your_surfshark_service_username # https://my.surfshark.com/vpn/manual-setup/main/openvpn
password: your_surfshark_service_password # service credentials, not account password
server_map:
us: 3844 # force US server #3844
gb: 2697 # force GB server #2697
au: 4621 # force AU server #4621
```
### hola (dict)
Enable Hola VPN proxy service. Requires the `hola-proxy` binary to be installed and available in your PATH.
```yaml
proxy_providers:
hola: {}
```
Once configured, use `--proxy hola:us` or similar to connect through Hola.
### windscribevpn (dict)
Enable Windscribe VPN proxy service using static OpenVPN service credentials.
Use the service credentials from https://windscribe.com/getconfig/openvpn (not your account login credentials).
```yaml
proxy_providers:
windscribevpn:
username: openvpn_username # From https://windscribe.com/getconfig/openvpn
password: openvpn_password # Service credentials, NOT your account password
```
#### Server Mapping
You can optionally pin specific servers using `server_map`:
```yaml
proxy_providers:
windscribevpn:
username: openvpn_username
password: openvpn_password
server_map:
us: us-central-096.totallyacdn.com # Force specific US server
gb: uk-london-001.totallyacdn.com # Force specific UK server
```
Once configured, use `--proxy windscribe:us` or `--proxy windscribe:gb` etc. to connect through Windscribe.
### Legacy nordvpn Configuration
**Legacy configuration. Use `proxy_providers.nordvpn` instead.**
Set your NordVPN Service credentials with `username` and `password` keys to automate the use of NordVPN as a Proxy
system where required.
You can also specify specific servers to use per-region with the `server_map` key.
Sometimes a specific server works best for a service than others, so hard-coding one for a day or two helps.
For example,
```yaml
nordvpn:
username: zxqsR7C5CyGwmGb6KSvk8qsZ # example of the login format
password: wXVHmht22hhRKUEQ32PQVjCZ
server_map:
us: 12 # force US server #12 for US proxies
```
The username and password should NOT be your normal NordVPN Account Credentials.
They should be the `Service credentials` which can be found on your Nord Account Dashboard.
Note that `gb` is used instead of `uk` to be more consistent across regional systems.
---
## headers (dict)
Case-Insensitive dictionary of headers that all Services begin their Request Session state with.
All requests will use these unless changed explicitly or implicitly via a Server response.
These should be sane defaults and anything that would only be useful for some Services should not
be put here.
Avoid headers like 'Accept-Encoding' as that would be a compatibility header that Python-requests will
set for you.
I recommend using,
```yaml
Accept-Language: "en-US,en;q=0.8"
User-Agent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.75 Safari/537.36"
```
---

123
docs/OUTPUT_CONFIG.md Normal file
View File

@@ -0,0 +1,123 @@
# Output & Naming Configuration
This document covers output file organization and naming configuration options.
## filenames (dict)
Override the default filenames used across unshackle.
The filenames use various variables that are replaced during runtime.
The following filenames are available and may be overridden:
- `log` - Log filenames. Uses `{name}` and `{time}` variables.
- `debug_log` - Debug log filenames. Uses `{service}` and `{time}` variables.
- `config` - Service configuration filenames.
- `root_config` - Root configuration filename.
- `chapters` - Chapter export filenames. Uses `{title}` and `{random}` variables.
- `subtitle` - Subtitle export filenames. Uses `{id}` and `{language}` variables.
For example,
```yaml
filenames:
log: "unshackle_{name}_{time}.log"
debug_log: "unshackle_debug_{service}_{time}.jsonl"
config: "config.yaml"
root_config: "unshackle.yaml"
chapters: "Chapters_{title}_{random}.txt"
subtitle: "Subtitle_{id}_{language}.srt"
```
---
## scene_naming (bool)
Set scene-style naming for titles. When `true` uses scene naming patterns (e.g., `Prime.Suspect.S07E01...`), when
`false` uses a more human-readable style (e.g., `Prime Suspect S07E01 ...`). Default: `true`.
---
## series_year (bool)
Whether to include the series year in series names for episodes and folders. Default: `true`.
---
## tag (str)
Group or Username to postfix to the end of download filenames following a dash.
Only applies when `scene_naming` is enabled.
For example, `tag: "J0HN"` will have `-J0HN` at the end of all download filenames.
---
## tag_group_name (bool)
Enable/disable tagging downloads with your group name when `tag` is set. Default: `true`.
---
## tag_imdb_tmdb (bool)
Enable/disable tagging downloaded files with IMDB/TMDB/TVDB identifiers (when available). Default: `true`.
---
## muxing (dict)
- `set_title`
Set the container title to `Show SXXEXX Episode Name` or `Movie (Year)`. Default: `true`
---
## chapter_fallback_name (str)
The Chapter Name to use when exporting a Chapter without a Name.
The default is no fallback name at all and no Chapter name will be set.
The fallback name can use the following variables in f-string style:
- `{i}`: The Chapter number starting at 1.
E.g., `"Chapter {i}"`: "Chapter 1", "Intro", "Chapter 3".
- `{j}`: A number starting at 1 that increments any time a Chapter has no title.
E.g., `"Chapter {j}"`: "Chapter 1", "Intro", "Chapter 2".
These are formatted with f-strings, directives are supported.
For example, `"Chapter {i:02}"` will result in `"Chapter 01"`.
---
## directories (dict)
Override the default directories used across unshackle.
The directories are set to common values by default.
The following directories are available and may be overridden,
- `commands` - CLI Command Classes.
- `services` - Service Classes.
- `vaults` - Vault Classes.
- `fonts` - Font files (ttf or otf).
- `downloads` - Downloads.
- `temp` - Temporary files or conversions during download.
- `cache` - Expiring data like Authorization tokens, or other misc data.
- `cookies` - Expiring Cookie data.
- `logs` - Logs.
- `wvds` - Widevine Devices.
- `prds` - PlayReady Devices.
- `dcsl` - Device Certificate Status List.
Notes:
- `services` accepts either a single directory or a list of directories to search for service modules.
For example,
```yaml
downloads: "D:/Downloads/unshackle"
temp: "D:/Temp/unshackle"
```
There are directories not listed that cannot be modified as they are crucial to the operation of unshackle.
---

116
docs/SERVICE_CONFIG.md Normal file
View File

@@ -0,0 +1,116 @@
# Service Integration & Authentication Configuration
This document covers service-specific configuration, authentication, and metadata integration options.
## services (dict)
Configuration data for each Service. The Service will have the data within this section merged into the `config.yaml`
before provided to the Service class.
Think of this config to be used for more sensitive configuration data, like user or device-specific API keys, IDs,
device attributes, and so on. A `config.yaml` file is typically shared and not meant to be modified, so use this for
any sensitive configuration data.
The Key is the Service Tag, but can take any arbitrary form for its value. It's expected to begin as either a list or
a dictionary.
For example,
```yaml
NOW:
client:
auth_scheme: MESSO
# ... more sensitive data
```
---
## credentials (dict[str, str|list|dict])
Specify login credentials to use for each Service, and optionally per-profile.
For example,
```yaml
ALL4: jane@gmail.com:LoremIpsum100 # directly
AMZN: # or per-profile, optionally with a default
default: jane@example.tld:LoremIpsum99 # <-- used by default if -p/--profile is not used
james: james@gmail.com:TheFriend97
john: john@example.tld:LoremIpsum98
NF: # the `default` key is not necessary, but no credential will be used by default
john: john@gmail.com:TheGuyWhoPaysForTheNetflix69420
```
The value should be in string form, i.e. `john@gmail.com:password123` or `john:password123`.
Any arbitrary values can be used on the left (username/password/phone) and right (password/secret).
You can also specify these in list form, i.e., `["john@gmail.com", ":PasswordWithAColon"]`.
If you specify multiple credentials with keys like the `AMZN` and `NF` example above, then you should
use a `default` key or no credential will be loaded automatically unless you use `-p/--profile`. You
do not have to use a `default` key at all.
Please be aware that this information is sensitive and to keep it safe. Do not share your config.
---
## tmdb_api_key (str)
API key for The Movie Database (TMDB). This is used for tagging downloaded files with TMDB,
IMDB and TVDB identifiers. Leave empty to disable automatic lookups.
To obtain a TMDB API key:
1. Create an account at <https://www.themoviedb.org/>
2. Go to <https://www.themoviedb.org/settings/api> to register for API access
3. Fill out the API application form with your project details
4. Once approved, you'll receive your API key
For example,
```yaml
tmdb_api_key: cf66bf18956kca5311ada3bebb84eb9a # Not a real key
```
**Note**: Keep your API key secure and do not share it publicly. This key is used by the core/utils/tags.py module to fetch metadata from TMDB for proper file tagging.
---
## simkl_client_id (str)
Client ID for SIMKL API integration. SIMKL is used as a metadata source for improved title matching and tagging,
especially when a TMDB API key is not configured.
To obtain a SIMKL Client ID:
1. Create an account at <https://simkl.com/>
2. Go to <https://simkl.com/settings/developer/>
3. Register a new application to receive your Client ID
For example,
```yaml
simkl_client_id: "your_client_id_here"
```
**Note**: While optional, having a SIMKL Client ID improves metadata lookup reliability. SIMKL serves as an alternative or fallback metadata source to TMDB. This is used by the `core/utils/tags.py` module.
---
## title_cache_enabled (bool)
Enable/disable caching of title metadata to reduce redundant API calls. Default: `true`.
---
## title_cache_time (int)
Cache duration in seconds for title metadata. Default: `1800` (30 minutes).
---
## title_cache_max_retention (int)
Maximum retention time in seconds for serving slightly stale cached title metadata when API calls fail.
Default: `86400` (24 hours). Effective retention is `min(title_cache_time + grace, title_cache_max_retention)`.
---

39
docs/SUBTITLE_CONFIG.md Normal file
View File

@@ -0,0 +1,39 @@
# Subtitle Processing Configuration
This document covers subtitle processing and formatting options.
## subtitle (dict)
Control subtitle conversion and SDH (hearing-impaired) stripping behavior.
- `conversion_method`: How to convert subtitles between formats. Default: `pysubs2`.
- `auto`: Use subby for WebVTT/SAMI, standard for others.
- `subby`: Always use subby with CommonIssuesFixer.
- `subtitleedit`: Prefer SubtitleEdit when available; otherwise fallback to standard conversion.
- `pycaption`: Use only the pycaption library (no SubtitleEdit, no subby).
- `pysubs2`: Use pysubs2 library (supports SRT, SSA, ASS, WebVTT, TTML, SAMI, MicroDVD, MPL2, TMP formats).
- `sdh_method`: How to strip SDH cues. Default: `auto`.
- `auto`: Try subby for SRT first, then SubtitleEdit, then filter-subs.
- `subby`: Use subby's SDHStripper. **Note:** Only works with SRT files; other formats will fall back to alternative methods.
- `subtitleedit`: Use SubtitleEdit's RemoveTextForHI when available.
- `filter-subs`: Use the subtitle-filter library.
- `strip_sdh`: Enable/disable automatic SDH (hearing-impaired) cue stripping. Default: `true`.
- `convert_before_strip`: When using `filter-subs` SDH method, automatically convert subtitles to SRT format first for better compatibility. Default: `true`.
- `preserve_formatting`: Keep original subtitle tags and positioning during conversion. Default: `true`.
Example:
```yaml
subtitle:
conversion_method: pysubs2
sdh_method: auto
strip_sdh: true
convert_before_strip: true
preserve_formatting: true
```
---

View File

@@ -1,136 +0,0 @@
# VPN Proxy Setup for Unshackle
## Overview
Unshackle has **native Gluetun integration** that automatically creates and manages Docker containers to bridge VPN connections to HTTP proxies. Simply configure your VPN credentials in `unshackle.yaml` and use `--proxy gluetun:<provider>:<region>`.
## Why Use VPN Proxies?
- **Network Isolation**: VPN runs in a Docker container, doesn't affect your system's internet
- **Easy Switching**: Switch between regions without reconfiguring anything
- **Multiple Regions**: Use different VPN locations for different downloads
## Requirements
- Docker must be installed and running
- Verify with: `unshackle env check`
## Configuration
Add your VPN provider credentials to `unshackle.yaml`:
```yaml
gluetun:
base_port: 8888 # Starting port for HTTP proxies
auto_cleanup: true # Remove containers when done
container_prefix: "unshackle-gluetun"
verify_ip: true # Verify VPN IP matches expected region
providers:
windscribe:
vpn_type: openvpn
credentials:
username: "YOUR_OPENVPN_USERNAME"
password: "YOUR_OPENVPN_PASSWORD"
server_countries:
us: US
uk: GB
ca: CA
nordvpn:
vpn_type: openvpn
credentials:
username: "YOUR_SERVICE_USERNAME"
password: "YOUR_SERVICE_PASSWORD"
server_countries:
us: US
de: DE
```
## Getting Your VPN Credentials
### Windscribe
1. Go to [windscribe.com/getconfig/openvpn](https://windscribe.com/getconfig/openvpn)
2. Generate a config file for any location
3. Copy the username and password shown
> **Note**: Windscribe uses region names like "US East" instead of country codes. Unshackle automatically converts codes like `us`, `ca`, `uk` to the correct region names.
### NordVPN
1. Log into NordVPN dashboard
2. Go to Services > NordVPN > Manual setup
3. Copy your service credentials (not your account email/password)
### Other Providers
Gluetun supports 50+ VPN providers. See the [Gluetun Wiki](https://github.com/qdm12/gluetun-wiki/tree/main/setup/providers) for provider-specific setup instructions.
## Usage
Use the `--proxy` flag with the format `gluetun:<provider>:<region>`:
```bash
# Connect via Windscribe to US
unshackle dl SERVICE CONTENT_ID --proxy gluetun:windscribe:us
# Connect via NordVPN to Germany
unshackle dl SERVICE CONTENT_ID --proxy gluetun:nordvpn:de
```
Unshackle will automatically:
1. Start a Gluetun Docker container with your credentials
2. Wait for the VPN connection to establish
3. Route your download through the VPN proxy
4. Clean up the container when done (if `auto_cleanup: true`)
## Troubleshooting
### Docker Not Running
```
Error: Docker is not running
```
Start Docker Desktop or the Docker daemon.
### Invalid Credentials
```
Error: VPN authentication failed
```
Verify your credentials are correct. Use VPN service credentials from your provider's manual setup page, not your account login.
### Container Fails to Start
Check Docker logs:
```bash
docker logs unshackle-gluetun-windscribe-us
```
### VPN Connection Timeout
If the VPN connection hangs or times out, your network may be blocking the default UDP port 1194. Try using TCP port 443:
```yaml
windscribe:
vpn_type: openvpn
openvpn_port: 443 # Use TCP 443 for restricted networks
credentials:
username: "YOUR_USERNAME"
password: "YOUR_PASSWORD"
```
### Verify VPN Connection
The `verify_ip` option checks that your IP matches the expected region. If verification fails, try a different server location in your provider's settings.
## References
- [Gluetun GitHub](https://github.com/qdm12/gluetun)
- [Gluetun Wiki - Provider Setup](https://github.com/qdm12/gluetun-wiki)
- [CONFIG.md - Full gluetun options](../CONFIG.md#gluetun-dict)