docs: restructure documentation into MkDocs Material site

This commit is contained in:
imSp4rky
2026-07-03 19:24:11 -06:00
parent b892e3ce70
commit 1d8cec6d2b
51 changed files with 9398 additions and 4356 deletions
+193
View File
@@ -0,0 +1,193 @@
# The Configuration File
Almost everything about how unshackle behaves is controlled by a single YAML file named `unshackle.yaml`: where it saves downloads, which CDM it uses, your credentials, proxies, filename templates, and more. This page covers where that file lives, how unshackle finds it, the shape of its contents, the directory layout unshackle builds around it, and how to edit values from the command line.
!!! note "Where the exhaustive key list lives"
This page is an overview. For the complete, key-by-key breakdown of every setting, its type, and its default, see the [Configuration Reference](../reference/configuration.md).
## The config filename
The main configuration file is always named `unshackle.yaml`. It is a plain YAML file. You can open and edit it in any text editor, or manage individual values with the [`unshackle cfg`](#editing-the-config-with-unshackle-cfg) command.
If you have never created one, that is fine: unshackle runs entirely on built-in defaults when no config file exists. The file only needs to contain the keys you want to change from their defaults.
## Where the config file lives
When unshackle starts, it searches a fixed list of locations and uses the **first one that exists**. In order of priority:
| # | Location | Typical path |
|---|----------|--------------|
| 1 | The unshackle package folder | `.../site-packages/unshackle/unshackle.yaml` |
| 2 | The parent of the package folder | `.../site-packages/unshackle.yaml` |
| 3 | Your OS user-config directory | see the table below |
The third location, your per-user config directory, is the recommended place for most installations, because it lives outside the package and survives reinstalls and upgrades. Its exact path depends on your operating system:
=== "Linux"
```text
~/.config/unshackle/unshackle.yaml
```
=== "Windows"
```text
%LOCALAPPDATA%\unshackle\unshackle.yaml
```
=== "macOS"
```text
~/Library/Application Support/unshackle/unshackle.yaml
```
!!! tip "Not sure which file is being used?"
Run `unshackle env info`. It prints the path the config was loaded from (or tells you none was found), along with every directory unshackle is currently using.
The config is read exactly once, when unshackle starts. If you edit the file, the change takes effect on the next command you run.
## Top-level structure
`unshackle.yaml` is a flat map of top-level keys. Each key configures one area of the program. You only include the keys you want to change; everything else falls back to its default.
Here is a small, realistic example that sets a download location, a release tag, a default CDM, and one service's credentials:
```yaml title="unshackle.yaml"
# Where finished downloads are written
directories:
downloads: ~/Videos/unshackle
# Release group tag appended to filenames
tag: MYGRP
# Default Widevine/PlayReady device to use, with per-service overrides
cdm:
default: my_device_l3
AMZN: my_device_l1
# Per-service login details (service tag -> "username:password")
credentials:
AMZN: my_email@example.com:hunter2
# Default HTTP headers merged into every request
headers:
Accept-Language: en-US,en;q=0.9
```
The top-level keys group loosely into these areas:
| Area | Example keys |
|------|--------------|
| Downloading & DRM | `dl`, `cdm`, `remote_cdm`, `decryption` |
| Networking | `network`, `headers` |
| Credentials & cookies | `credentials`, `firefox_cookies` |
| Tracks & muxing | `subtitle`, `audio`, `muxing`, `language_tags` |
| Key vaults | `key_vaults`, `vault_timeout` |
| Proxies & remote | `proxy_providers`, `remote_services`, `serve`, `services` |
| Naming & tagging | `tag`, `output_template`, `chapter_fallback_name` |
| External API keys | `tmdb_api_key`, `simkl_client_id`, `ipinfo_api_key` |
| Behavior & logging | `update_checks`, `redact_paths`, `debug`, `unicode_filenames` |
| Paths | `directories`, `filenames` |
For the full list with types and defaults, see the [Configuration Reference](../reference/configuration.md).
!!! warning "Unknown keys are silently ignored"
unshackle does not validate your config against a schema. If you misspell a key, it is simply skipped and the default is used. You will not get an error. Double-check key names (and their nesting) if a setting does not seem to apply.
## The directory layout
The `directories` key controls where unshackle reads and writes its various files. Each directory has a sensible default, and you can override most of them by giving a new path. Paths support `~` for your home directory.
```yaml title="unshackle.yaml"
directories:
downloads: ~/Videos/unshackle
temp: /mnt/fast/unshackle-temp
cache: ~/.cache/unshackle
```
The directories unshackle uses:
| Name | Purpose | Overridable |
|------|---------|-------------|
| `downloads` | Default output folder for finished downloads | Yes |
| `temp` | Temporary working files during a download | Yes |
| `cache` | Cache store (title cache, update checks, service caches) | Yes |
| `cookies` | Per-service cookie files | Yes |
| `logs` | Log files | Yes |
| `exports` | Export JSONs | Yes |
| `wvds` | Widevine devices (`.wvd` files) | Yes |
| `prds` | PlayReady devices (`.prd` files) | Yes |
| `dcsl` | DCSL data | Yes |
| `services` | Search paths for service code (see below) | Yes |
| `commands` | CLI command modules | Yes |
| `vaults` | Vault modules | Yes |
| `fonts` | Bundled fonts | Yes |
!!! note "Some directories cannot be moved"
A handful of internal locations are protected: the package root, the core directory, the user-config directory, and the data base. If you list them under `directories`, unshackle silently ignores the override. This is intentional; those paths are tied to where the package is installed.
### The `services` directory is special
Unlike the other entries, `services` is a **list**, and each entry can be either a local folder or a remote repository. This lets you mix your own local service code with services pulled from Git:
```yaml title="unshackle.yaml"
directories:
services:
- unshackle-dl/services # a GitHub owner/repo shorthand
- https://github.com/me/my-services.git
- ~/code/local-services # a local folder
```
Entries are searched in the order listed, and **the first source to define a given service tag wins**, so put local folders last if you want them to act as fallbacks rather than overrides. Remote repositories are cloned and periodically updated for you. See [Services](../dev/creating-a-service.md) for the full details on how service discovery and repositories work.
## The `filenames` key
Alongside `directories`, the `filenames` key lets you override the templates unshackle uses when naming its own working and log files (for example the log filename or the temporary chapters file). Most users never need to touch this. The available names and their default templates are listed in the [Configuration Reference](../reference/configuration.md#filenames).
## Editing the config with `unshackle cfg`
You do not have to edit `unshackle.yaml` by hand. The `unshackle cfg` command reads and writes individual values for you, creating the config file (and its parent directory) if it does not exist yet.
**Read a single value** by passing its key. Nested keys use dot notation:
```console
$ unshackle cfg tag
$ unshackle cfg cdm.default
```
**Set a value** by passing a key and a value:
```console
$ unshackle cfg tag MYGRP
$ unshackle cfg cdm.default my_device_l3
```
Values are parsed as Python literals where possible, so numbers, booleans, and lists work naturally, while bare text is treated as a string:
```console
$ unshackle cfg update_checks false
$ unshackle cfg vault_timeout 30
```
**Remove a value** with `--unset`:
```console
$ unshackle cfg cdm.default --unset
```
**List everything** currently set with `--list`:
```console
$ unshackle cfg --list
```
When it writes, `unshackle cfg` targets the config file that was loaded. If none exists yet, it creates `unshackle.yaml` in your OS user-config directory.
!!! warning "Editing with `cfg` strips comments"
Because `unshackle cfg` rewrites the whole file when it saves, any comments in `unshackle.yaml` are removed by a write. If you keep important notes as comments, edit the file by hand instead, or keep those notes elsewhere.
## Next steps
- Browse the [Configuration Reference](../reference/configuration.md) for every key and default.
- Set up your first download in [Downloading](../guide/downloading.md).
- Learn how services are discovered and updated in [Services](../dev/creating-a-service.md).
+196
View File
@@ -0,0 +1,196 @@
# Installation
unshackle is a modular archival tool for movies, TV, and music. It ships as a
single Python package named `unshackle` that installs one console command, also
called `unshackle`. This page covers installing that command, the Python
version it needs, and the external command-line tools it expects to find on your
`PATH`.
!!! note "What you get"
Installing the package registers a single entry point, the `unshackle`
command. It covers everything: downloading, key-vault management, device
provisioning, the REST server, and the helper utilities.
## Requirements at a glance
| Requirement | Recommended version | Needed for |
| --- | --- | --- |
| [Python](https://www.python.org/) | 3.11 to 3.14 | Running unshackle itself |
| [uv](https://docs.astral.sh/uv/) | ≥ 0.5 | Installing and running unshackle |
| [FFmpeg](https://ffmpeg.org/) | ≥ 6.0 | Media processing and analysis |
| [MKVToolNix](https://mkvtoolnix.download/) | ≥ 80 | MKV muxing and metadata editing |
| [shaka-packager](https://github.com/shaka-project/shaka-packager) | 2.6.1 | DRM decryption |
| [Bento4](https://github.com/axiomatic-systems/Bento4) | ≥ 1.6.0-639 | Alternate DRM decryption (`mp4decrypt`) |
| [dovi_tool](https://github.com/quietvoid/dovi_tool) | ≥ 2.1 | Dolby Vision handling |
| [SubtitleEdit](https://github.com/SubtitleEdit/subtitleedit/releases) | ≥ 5.0 | Subtitle conversion (optional) |
The sections below explain each of these and how to confirm your setup is
complete.
## Python version support
unshackle requires **Python 3.11 or newer, up to and including 3.14**
(`requires-python = ">=3.11,<3.15"`). Anything older than 3.11 or 3.15 and
later is unsupported and the installer will refuse to build the environment.
You do not usually need to install a matching Python interpreter by hand, since
`uv` can download and manage one for you. If you are working inside an existing
virtual environment, make sure it is on a supported version.
## Installing with uv
The recommended way to install unshackle is as a `uv` tool. This creates an
isolated environment for the package and puts the `unshackle` command on your
`PATH` without touching your system Python.
```shell title="Install as a uv tool"
uv tool install git+https://github.com/unshackle-dl/unshackle.git
```
Once it finishes, the `unshackle` command is available globally:
```shell
unshackle --help
```
!!! tip "Upgrading and removing"
Because it is installed from a git URL, re-run the same
`uv tool install` command (uv will update in place) to pull a newer build,
and use `uv tool uninstall unshackle` to remove it.
### Running from a clone
If you would rather work from a checkout of the repository (for example to try
an in-development branch or to keep local service code alongside unshackle), use
`uv run` inside the clone. This keeps the project's virtual environment active
for the duration of the command, so you do not have to activate it yourself.
```shell title="Run from a git clone"
git clone https://github.com/unshackle-dl/unshackle.git
cd unshackle
uv run unshackle --help
```
Every command shown elsewhere in these docs works the same way from a clone,
just prefix it with `uv run`:
```shell
uv run unshackle env check
```
!!! note "Developer note"
Contributors will also want the development and test dependency groups. The
project defines `dev` (linters, type checkers) and `test` (pytest and
friends) groups in `pyproject.toml`; install them with
`uv sync --group dev --group test` inside the clone. End users can ignore
these entirely.
## External tools on your PATH
unshackle shells out to a number of external command-line programs for media
processing and DRM work. It looks for each one first in a `binaries/` folder
next to the installed package, and then falls back to your system `PATH`, so
installing these tools system-wide (or dropping them into that folder) both
work.
### Required tools
These must be present for core downloading, decryption, and muxing to work:
| Tool | Binary looked up | Why it is needed |
| --- | --- | --- |
| FFmpeg | `ffmpeg` | Media processing: remuxing, conversion, stream handling |
| FFprobe | `ffprobe` | Media analysis: inspecting tracks and container details |
| MKVToolNix | `mkvmerge` | Muxing downloaded tracks into a final MKV |
| mkvpropedit | `mkvpropedit` | Editing MKV metadata after muxing |
| shaka-packager | `shaka-packager` / `packager` | Decrypting DRM-protected content (the default decryptor) |
!!! warning "shaka-packager is the default decryptor"
unshackle decrypts with shaka-packager unless you explicitly configure a
different decryptor. If it is missing, protected downloads will fail at the
decryption step. See the [configuration reference](configuration-file.md) for the
`decryption` key if you want to switch to `mp4decrypt`.
### Recommended and optional tools
These extend unshackle's capabilities. Install the ones relevant to what you
download. For example, `dovi_tool` only matters if you handle Dolby Vision.
| Tool | Binary looked up | Why it is needed |
| --- | --- | --- |
| Bento4 (`mp4decrypt`) | `mp4decrypt` | Alternative DRM decryptor to shaka-packager |
| dovi_tool | `dovi_tool` | Dolby Vision metadata handling |
| HDR10Plus_tool | `hdr10plus_tool` | HDR10+ metadata handling |
| SubtitleEdit | `seconv`, `SubtitleEdit` | Subtitle conversion (the `SeConv` CLI from 5.x) |
| CCExtractor | `ccextractor` | Extracting closed captions |
| FFplay | `ffplay` | Simple preview player |
| MPV | `mpv` | Advanced preview player (used by `util crop`/`util range` previews) |
| HolaProxy | `hola-proxy` | Hola proxy provider support |
| Caddy | `caddy` | Optional reverse proxy for `unshackle serve --caddy` |
| Docker | `docker` | Gluetun VPN proxy support |
| Git | `git` | Fetching and updating remote service repositories |
!!! tip "SubtitleEdit specifics"
unshackle looks for `seconv` first, the batch CLI shipped with
SubtitleEdit 5.x, before falling back to a `SubtitleEdit` (4.x) binary. The
5.0 GUI has no batch mode, so the `SeConv` CLI is what you want for
automated subtitle conversion.
## Verifying your installation
After installing, confirm the command runs and that unshackle can see the tools
it depends on.
### Confirm the command is available
```shell
unshackle --help
```
This prints the banner and the list of available commands (`dl`, `env`, `kv`,
`serve`, `wvd`, `prd`, `search`, `util`, `cfg`, `import`). If your shell reports
that `unshackle` is not found, the `uv tool` bin directory is probably not on
your `PATH`. Run `uv tool update-shell` and open a new terminal.
### Check external dependencies
The `env check` subcommand inspects your environment and reports which tools it
found:
```shell
unshackle env check
```
=== "Output"
It prints a table grouped by category (Core, DRM, HDR, Subtitle, Player,
Network) with a status column: a green check for tools that resolved and a
red cross for those it could not find, plus a summary line such as
`All required tools installed ✓` or `Missing required: <names>`.
=== "From a clone"
```shell
uv run unshackle env check
```
If a required tool shows as missing, install it and put it on your `PATH` (or in
the package's `binaries/` folder), then re-run the check.
### Inspect environment paths
To see where unshackle will read its configuration from and where it stores
downloads, caches, cookies, and devices, use:
```shell
unshackle env info
```
If no configuration file exists yet, this command lists the locations unshackle
searches for one, so you know where to create it. See the
[configuration guide](configuration-file.md) for the details of that file.
## Next steps
- Set up your [configuration](configuration-file.md) file (`unshackle.yaml`).
- Start [downloading](../guide/downloading.md) content once your tools check out.
+274
View File
@@ -0,0 +1,274 @@
# Quick Start
This page takes you from a fresh install to your first downloaded file. You will
create the one piece of configuration unshackle insists on, add a streaming
service and a CDM so it can actually fetch and decrypt media, run a basic
`unshackle dl` command, and learn where the finished file lands.
!!! note "Before you start"
This guide assumes unshackle is already installed and on your `PATH`. If
`unshackle --help` does not print a help screen, work through
[Installation](installation.md) first.
## 1. Check your environment
unshackle drives several external tools (FFmpeg, MKVToolNix, shaka-packager, and
others) to decrypt, repack, and mux media. Confirm they are visible before you
download anything:
```shell
unshackle env check
```
This prints a dependency table. The **required** tools (FFmpeg, FFprobe,
MKVToolNix, mkvpropedit, and shaka-packager) must show a green check. Optional
tools such as `dovi_tool` (Dolby Vision) and CCExtractor (closed captions) only
matter for the features that use them.
!!! tip
The summary line at the bottom reports `installed/total` and lists anything
required that is still missing, so you know exactly what to install next.
## 2. Create a minimal config
unshackle reads a single YAML file named `unshackle.yaml`. To see where it looks
for that file, and where it *would* accept one if you have not made it yet, run:
```shell
unshackle env info
```
If no config exists, this prints the candidate locations. In search order they are:
1. `unshackle.yaml` inside the unshackle package folder.
2. `unshackle.yaml` in that folder's parent.
3. `unshackle.yaml` in your OS user-config directory
(`~/.config/unshackle/` on Linux, `%LOCALAPPDATA%\unshackle\` on Windows,
`~/Library/Application Support/unshackle/` on macOS).
The **first** file that exists wins. Create `unshackle.yaml` in one of those
locations.
### The one key you must set
unshackle refuses to start a download unless it knows how to name the output file.
That means `output_template` is the one setting a first run genuinely requires.
Everything else has a sensible default. A minimal, working config looks like this:
```yaml title="unshackle.yaml"
output_template:
movies: "{title} ({year}) {quality} {source}"
series: "{title} S{season}E{episode} {episode_name} {quality} {source}"
```
Each `{variable}` is filled in from the title and the tracks you downloaded. The
full set of valid variables, including `resolution`, `video`, `audio`, `hdr`,
`edition`, `tag`, and more, is documented in [Configuration](configuration-file.md).
!!! note "Spaces or dots?"
unshackle auto-detects your naming style from the template: if the separators
between variables are mostly spaces, it uses spaces; if they are mostly dots,
it produces scene-style `Title.S01E01.1080p` names. Write the template in the
style you want the filenames to look.
!!! warning "Editing config from the CLI strips comments"
You can read and set keys with `unshackle cfg` (for example
`unshackle cfg tag MYGROUP` or `unshackle cfg --list`), but writing a value
rewrites the file and **removes any comments** it contained. If you keep notes
in your config, edit the file by hand instead.
## 3. Add a service
The service tag you pass to `dl` (like `NF`) maps to a **service module**, a small
plugin that knows how to talk to one streaming platform. unshackle ships without
any bundled services, so you add the one(s) you want.
Services live under the `directories.services` path (run `unshackle env info` to
see where that is). unshackle discovers them by looking for `*/__init__.py`: the
folder name becomes the **service tag**, and the folder must contain a class with
that exact same name.
=== "Local folder"
Drop a service folder into your services directory. A service tagged `NF`
lives at:
```
<services>/NF/__init__.py # defines a class named NF
```
Once the folder is in place, the tag `NF` is immediately available to `dl`,
`search`, and the other service-aware commands.
=== "Git repository"
`directories.services` may also list git repositories. unshackle clones them
on first use and keeps them up to date:
```yaml title="unshackle.yaml"
directories:
services:
- owner/unshackle-services # a GitHub owner/repo shorthand
- /path/to/local/services # local folders still work too
```
Force a refresh of every configured service repo at any time with:
```shell
unshackle util refresh-services
```
!!! info "Where to get services"
Service modules are kept separate from the core project. Ask in the community
[Discord](https://discord.gg/mHYyPaCbFK) for where to find the service you
need. The core repository deliberately does not host them.
## 4. Add a CDM for DRM
Most streaming content is encrypted. To fetch decryption keys, unshackle needs a
**CDM**, a Widevine device (`.wvd`) or a PlayReady device (`.prd`). Register a
Widevine device you already have with:
```shell
unshackle wvd add /path/to/device.wvd
```
This validates the file and moves it into your WVDs directory. Then point services
at it in your config. The `cdm` map is keyed by service tag, with a `default` that
covers everything else:
```yaml title="unshackle.yaml"
cdm:
default: my_device # the .wvd file's name, without the extension
NF: my_other_device # override for a specific service
```
PlayReady works the same way with `.prd` files created and managed by the
[`prd`](configuration-file.md) command. If a title is DRM-free, no CDM is needed.
!!! tip
Run `unshackle wvd parse my_device` to inspect a device's security level and
contents, and `unshackle env info` to confirm where WVDs and PRDs are stored.
## 5. Provide authentication
Services that require a login read either **cookies** or **credentials**.
- **Cookies**: export the service's cookies to a Netscape-format text file and
place it in your cookies directory. unshackle looks for, in order:
`cookies/{SERVICE}.txt`, then `cookies/{SERVICE}/{profile}.txt`, then
`cookies/{SERVICE}/default.txt`. So a file at `cookies/NF.txt` is picked up
automatically for the `NF` service.
- **Credentials**: store a username and password per service in your config:
```yaml title="unshackle.yaml"
credentials:
NF: "email@example.com:your-password"
```
Use the `-p/--profile` flag to switch between multiple accounts for the same
service. Whether a given service needs cookies, credentials, or nothing at all
depends on the service module.
## 6. Find a title (optional)
If you have a URL or ID already, skip this. Otherwise, search the service for a
title and note the `id` it prints, since that is what you feed to `dl`:
```shell
unshackle search NF "The Office"
```
You can also list what a service exposes for a given title without downloading:
```shell
unshackle dl --list-titles NF 81234567 # show seasons/episodes
unshackle dl --list NF 81234567 # show available tracks
```
## 7. Run your first download
A download always has three parts:
```
unshackle dl <FLAGS> <SERVICE-TAG> <TITLE>
```
- **`dl`** carries every quality, language, track, and output flag.
- **`<SERVICE-TAG>`** picks which service to talk to (`NF`, `DSNP`, …).
- **`<TITLE>`** is the URL, ID, or slug the service understands.
A good first command asks for 1080p with English audio and subtitles:
```shell title="Your first download"
unshackle dl -q 1080 -l en NF 81234567
```
unshackle will fetch the title, select the tracks matching your flags, acquire
keys through your CDM (and any key vaults), then decrypt, mux, and tag the result.
### Handy first flags
| Flag | Meaning |
|---|---|
| `-q`, `--quality` | Target resolution(s), e.g. `-q 1080` or `-q 1080,720`. Defaults to best available. |
| `-l`, `--lang` | Language(s) for video and audio, e.g. `-l en` or `-l orig,en`. `orig` = the title's original language. |
| `-sl`, `--s-lang` | Subtitle language(s); defaults to `all`. |
| `-v`, `--vcodec` | Video codec, e.g. `-v H.265`. Defaults to any. |
| `-r`, `--range` | Dynamic range, e.g. `-r HDR10` or `-r DV`. Defaults to `SDR`. |
| `-w`, `--wanted` | Which episodes, e.g. `-w S01` or `-w S01E01-S01E03`. |
| `-o`, `--output` | Override the output directory for this run. |
| `--list` | List the tracks that would be downloaded, then stop. |
!!! example "A few realistic variations"
```shell
# A whole first season in the best available quality
unshackle dl -w S01 NF 81234567
# 2160p HDR10 with the original-language audio plus English subtitles
unshackle dl -q 2160 -r HDR10 -l orig -sl en NF 81234567
# Just the newest episode of an ongoing show
unshackle dl --latest-episode NF 81234567
```
See [Downloading](../guide/downloading.md) for the complete flag reference, including
codec, bitrate, channel-layout, and track-type selection.
## 8. Where the output lands
By default, finished files are written to the `downloads` directory
(`unshackle env info` shows its exact path; the built-in default is a `downloads`
folder alongside the project). Override it per run with `-o`:
```shell
unshackle dl -q 1080 -o /mnt/media/incoming NF 81234567
```
- **Movies** are written as a single `.mkv` file named from your `movies` template.
- **TV episodes** are grouped into a per-show / per-season folder (from your
`series` template) unless you pass `--no-folder`.
- The filename is built from your `output_template`, and IMDb/TMDB IDs are added to
the file's metadata tags when available.
To change the default output location permanently, set it in your config:
```yaml title="unshackle.yaml"
directories:
downloads: /mnt/media/incoming
```
## Where to go next
- **[Downloading](../guide/downloading.md)**. The full `dl` command: quality, codecs,
languages, track selection, hybrid Dolby Vision, and output control.
- **[Configuration](configuration-file.md)**. Every `unshackle.yaml` key, plus
directories, key vaults, proxies, and naming templates.
- **[REST API](../dev/rest-api/index.md)**. Run the `serve` server to drive downloads over
HTTP.
!!! tip "You are never far from help"
`unshackle --help`, `unshackle dl --help`, and `unshackle <command> --help`
list every option with its default. When in doubt, add `--list` to a `dl`
command to preview what it would do before it downloads anything.