Files
unshackle/getting-started/installation/index.html
T
2026-11-02 20:38:29 +00:00

2920 lines
69 KiB
HTML

<!doctype html>
<html lang="en" class="no-js">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="description" content="Movie, TV, and Music archival software. User guide and REST API reference">
<link rel="canonical" href="https://docs.unshackle.dev/getting-started/installation/">
<link rel="prev" href="../..">
<link rel="next" href="../quickstart/">
<link rel="icon" href="../../assets/favicon.svg">
<meta name="generator" content="mkdocs-1.6.1, mkdocs-material-9.8.0">
<title>Installation - unshackle</title>
<link rel="stylesheet" href="../../assets/stylesheets/main.57a0d79d.min.css">
<link rel="stylesheet" href="../../assets/stylesheets/palette.fb2fffe2.min.css">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,300i,400,400i,700,700i%7CRoboto+Mono:400,400i,700,700i&display=fallback">
<style>:root{--md-text-font:"Roboto";--md-code-font:"Roboto Mono"}</style>
<link rel="stylesheet" href="../../assets/_mkdocstrings.css">
<link rel="stylesheet" href="../../assets/extra.css">
<script>__md_scope=new URL("../..",location),__md_hash=e=>[...e].reduce(((e,_)=>(e<<5)-e+_.charCodeAt(0)),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
</head>
<body dir="ltr" data-md-color-scheme="default" data-md-color-primary="black" data-md-color-accent="indigo">
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
<label class="md-overlay" for="__drawer"></label>
<div data-md-component="skip">
<a href="#installation" class="md-skip">
Skip to content
</a>
</div>
<div data-md-component="announce">
</div>
<header class="md-header" data-md-component="header">
<nav class="md-header__inner md-grid" aria-label="Header">
<a href="../.." title="unshackle" class="md-header__button md-logo" aria-label="unshackle" data-md-component="logo">
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="m800-274-80-80v-206H514l-80-80h166v-80q0-50-34.5-85T481-840q-50 0-84 34.5T363-720v9l-73-73q22-61 75-98.5T481-920q83 0 141 58.5T680-720v80h40q33 0 56.5 23.5T800-560v286Zm20 246-62-62q-11 5-20 7.5T720-80H240q-33 0-56.5-23.5T160-160v-400q0-25 14.5-46t37.5-30L28-820l56-56L876-84l-56 56ZM686-160 539-309q-11 11-25.5 17t-31.5 6q-33 0-56.5-23.5T402-366q0-17 6-31.5t17-25.5L286-560h-46v400h446ZM486-360Zm131-97Z"/></svg>
</a>
<label class="md-header__button md-icon" for="__drawer">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 6h18v2H3zm0 5h18v2H3zm0 5h18v2H3z"/></svg>
</label>
<div class="md-header__title" data-md-component="header-title">
<div class="md-header__ellipsis">
<div class="md-header__topic">
<span class="md-ellipsis">
unshackle
</span>
</div>
<div class="md-header__topic" data-md-component="header-topic">
<span class="md-ellipsis">
Installation
</span>
</div>
</div>
</div>
<form class="md-header__option" data-md-component="palette">
<input class="md-option" data-md-color-media="(prefers-color-scheme)" data-md-color-scheme="default" data-md-color-primary="black" data-md-color-accent="indigo" aria-label="Switch to light mode" type="radio" name="__palette" id="__palette_0">
<label class="md-header__button md-icon" title="Switch to light mode" for="__palette_1" hidden>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7a5 5 0 0 0-5 5 5 5 0 0 0 5 5h4v-1.9H7c-1.71 0-3.1-1.39-3.1-3.1M8 13h8v-2H8zm9-6h-4v1.9h4c1.71 0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4a5 5 0 0 0 5-5 5 5 0 0 0-5-5"/></svg>
</label>
<input class="md-option" data-md-color-media="(prefers-color-scheme: light)" data-md-color-scheme="default" data-md-color-primary="black" data-md-color-accent="indigo" aria-label="Switch to dark mode" type="radio" name="__palette" id="__palette_1">
<label class="md-header__button md-icon" title="Switch to dark mode" for="__palette_2" hidden>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M17 7H7a5 5 0 0 0-5 5 5 5 0 0 0 5 5h10a5 5 0 0 0 5-5 5 5 0 0 0-5-5m0 8a3 3 0 0 1-3-3 3 3 0 0 1 3-3 3 3 0 0 1 3 3 3 3 0 0 1-3 3"/></svg>
</label>
<input class="md-option" data-md-color-media="(prefers-color-scheme: dark)" data-md-color-scheme="slate" data-md-color-primary="black" data-md-color-accent="indigo" aria-label="Switch to system preference" type="radio" name="__palette" id="__palette_2">
<label class="md-header__button md-icon" title="Switch to system preference" for="__palette_0" hidden>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M17 7H7a5 5 0 0 0-5 5 5 5 0 0 0 5 5h10a5 5 0 0 0 5-5 5 5 0 0 0-5-5M7 15a3 3 0 0 1-3-3 3 3 0 0 1 3-3 3 3 0 0 1 3 3 3 3 0 0 1-3 3"/></svg>
</label>
</form>
<script>var palette=__md_get("__palette");if(palette&&palette.color){if("(prefers-color-scheme)"===palette.color.media){var media=matchMedia("(prefers-color-scheme: light)"),input=document.querySelector(media.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']");palette.color.media=input.getAttribute("data-md-color-media"),palette.color.scheme=input.getAttribute("data-md-color-scheme"),palette.color.primary=input.getAttribute("data-md-color-primary"),palette.color.accent=input.getAttribute("data-md-color-accent")}for(var[key,value]of Object.entries(palette.color))document.body.setAttribute("data-md-color-"+key,value)}</script>
<label class="md-header__button md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"/></svg>
</label>
<div class="md-search" data-md-component="search" role="dialog">
<label class="md-search__overlay" for="__search"></label>
<div class="md-search__inner" role="search">
<form class="md-search__form" name="search">
<input type="text" class="md-search__input" name="query" aria-label="Search" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="search-query" required>
<label class="md-search__icon md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11z"/></svg>
</label>
<nav class="md-search__options" aria-label="Search">
<a href="javascript:void(0)" class="md-search__icon md-icon" title="Share" aria-label="Share" data-clipboard data-clipboard-text="" data-md-component="search-share" tabindex="-1">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M18 16.08c-.76 0-1.44.3-1.96.77L8.91 12.7c.05-.23.09-.46.09-.7s-.04-.47-.09-.7l7.05-4.11c.54.5 1.25.81 2.04.81a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3c0 .24.04.47.09.7L8.04 9.81C7.5 9.31 6.79 9 6 9a3 3 0 0 0-3 3 3 3 0 0 0 3 3c.79 0 1.5-.31 2.04-.81l7.12 4.15c-.05.21-.08.43-.08.66 0 1.61 1.31 2.91 2.92 2.91s2.92-1.3 2.92-2.91A2.92 2.92 0 0 0 18 16.08"/></svg>
</a>
<button type="reset" class="md-search__icon md-icon" title="Clear" aria-label="Clear" tabindex="-1">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>
</button>
</nav>
<div class="md-search__suggest" data-md-component="search-suggest"></div>
</form>
<div class="md-search__output">
<div class="md-search__scrollwrap" tabindex="0" data-md-scrollfix>
<div class="md-search-result" data-md-component="search-result">
<div class="md-search-result__meta">
Initializing search
</div>
<ol class="md-search-result__list" role="presentation"></ol>
</div>
</div>
</div>
</div>
</div>
<div class="md-header__source">
<a href="https://github.com/unshackle-dl/unshackle" title="Go to repository" class="md-source" data-md-component="source">
<div class="md-source__icon md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2025 Fonticons, Inc.--><path d="M439.6 236.1 244 40.5c-5.4-5.5-12.8-8.5-20.4-8.5s-15 3-20.4 8.4L162.5 81l51.5 51.5c27.1-9.1 52.7 16.8 43.4 43.7l49.7 49.7c34.2-11.8 61.2 31 35.5 56.7-26.5 26.5-70.2-2.9-56-37.3L240.3 199v121.9c25.3 12.5 22.3 41.8 9.1 55-6.4 6.4-15.2 10.1-24.3 10.1s-17.8-3.6-24.3-10.1c-17.6-17.6-11.1-46.9 11.2-56v-123c-20.8-8.5-24.6-30.7-18.6-45L142.6 101 8.5 235.1C3 240.6 0 247.9 0 255.5s3 15 8.5 20.4l195.6 195.7c5.4 5.4 12.7 8.4 20.4 8.4s15-3 20.4-8.4l194.7-194.7c5.4-5.4 8.4-12.8 8.4-20.4s-3-15-8.4-20.4"/></svg>
</div>
<div class="md-source__repository">
unshackle-dl/unshackle
</div>
</a>
</div>
</nav>
</header>
<div class="md-container" data-md-component="container">
<nav class="md-tabs" aria-label="Tabs" data-md-component="tabs">
<div class="md-grid">
<ul class="md-tabs__list">
<li class="md-tabs__item">
<a href="../.." class="md-tabs__link">
Home
</a>
</li>
<li class="md-tabs__item md-tabs__item--active">
<a href="./" class="md-tabs__link">
Getting Started
</a>
</li>
<li class="md-tabs__item">
<a href="../../guide/downloading/" class="md-tabs__link">
User Guide
</a>
</li>
<li class="md-tabs__item">
<a href="../../reference/configuration/" class="md-tabs__link">
Configuration
</a>
</li>
<li class="md-tabs__item">
<a href="../../dev/creating-a-service/" class="md-tabs__link">
Developer
</a>
</li>
<li class="md-tabs__item">
<a href="../../reference/api/service/" class="md-tabs__link">
API Reference
</a>
</li>
</ul>
</div>
</nav>
<main class="md-main" data-md-component="main">
<div class="md-main__inner md-grid">
<div class="md-sidebar md-sidebar--primary" data-md-component="sidebar" data-md-type="navigation" >
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--primary md-nav--lifted" aria-label="Navigation" data-md-level="0">
<label class="md-nav__title" for="__drawer">
<a href="../.." title="unshackle" class="md-nav__button md-logo" aria-label="unshackle" data-md-component="logo">
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="m800-274-80-80v-206H514l-80-80h166v-80q0-50-34.5-85T481-840q-50 0-84 34.5T363-720v9l-73-73q22-61 75-98.5T481-920q83 0 141 58.5T680-720v80h40q33 0 56.5 23.5T800-560v286Zm20 246-62-62q-11 5-20 7.5T720-80H240q-33 0-56.5-23.5T160-160v-400q0-25 14.5-46t37.5-30L28-820l56-56L876-84l-56 56ZM686-160 539-309q-11 11-25.5 17t-31.5 6q-33 0-56.5-23.5T402-366q0-17 6-31.5t17-25.5L286-560h-46v400h446ZM486-360Zm131-97Z"/></svg>
</a>
unshackle
</label>
<div class="md-nav__source">
<a href="https://github.com/unshackle-dl/unshackle" title="Go to repository" class="md-source" data-md-component="source">
<div class="md-source__icon md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2025 Fonticons, Inc.--><path d="M439.6 236.1 244 40.5c-5.4-5.5-12.8-8.5-20.4-8.5s-15 3-20.4 8.4L162.5 81l51.5 51.5c27.1-9.1 52.7 16.8 43.4 43.7l49.7 49.7c34.2-11.8 61.2 31 35.5 56.7-26.5 26.5-70.2-2.9-56-37.3L240.3 199v121.9c25.3 12.5 22.3 41.8 9.1 55-6.4 6.4-15.2 10.1-24.3 10.1s-17.8-3.6-24.3-10.1c-17.6-17.6-11.1-46.9 11.2-56v-123c-20.8-8.5-24.6-30.7-18.6-45L142.6 101 8.5 235.1C3 240.6 0 247.9 0 255.5s3 15 8.5 20.4l195.6 195.7c5.4 5.4 12.7 8.4 20.4 8.4s15-3 20.4-8.4l194.7-194.7c5.4-5.4 8.4-12.8 8.4-20.4s-3-15-8.4-20.4"/></svg>
</div>
<div class="md-source__repository">
unshackle-dl/unshackle
</div>
</a>
</div>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../.." class="md-nav__link">
<span class="md-ellipsis">
Home
</span>
</a>
</li>
<li class="md-nav__item md-nav__item--active md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2" checked>
<label class="md-nav__link" for="__nav_2" id="__nav_2_label" tabindex="">
<span class="md-ellipsis">
Getting Started
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_2_label" aria-expanded="true">
<label class="md-nav__title" for="__nav_2">
<span class="md-nav__icon md-icon"></span>
Getting Started
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item md-nav__item--active">
<input class="md-nav__toggle md-toggle" type="checkbox" id="__toc">
<label class="md-nav__link md-nav__link--active" for="__toc">
<span class="md-ellipsis">
Installation
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<a href="./" class="md-nav__link md-nav__link--active">
<span class="md-ellipsis">
Installation
</span>
</a>
<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
<label class="md-nav__title" for="__toc">
<span class="md-nav__icon md-icon"></span>
Table of contents
</label>
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
<li class="md-nav__item">
<a href="#install-from-a-git-clone-recommended" class="md-nav__link">
<span class="md-ellipsis">
Install from a git clone (recommended)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#what-unshackle-setup-does" class="md-nav__link">
<span class="md-ellipsis">
What unshackle setup does
</span>
</a>
<nav class="md-nav" aria-label="What unshackle setup does">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#where-setup-puts-files" class="md-nav__link">
<span class="md-ellipsis">
Where setup puts files
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#requirements-at-a-glance" class="md-nav__link">
<span class="md-ellipsis">
Requirements at a glance
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#python-versions" class="md-nav__link">
<span class="md-ellipsis">
Python versions
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#installing-by-hand" class="md-nav__link">
<span class="md-ellipsis">
Installing by hand
</span>
</a>
<nav class="md-nav" aria-label="Installing by hand">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#running-from-a-clone" class="md-nav__link">
<span class="md-ellipsis">
Running from a clone
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#advanced-install-as-a-uv-tool" class="md-nav__link">
<span class="md-ellipsis">
Advanced: install as a uv tool
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#external-tools-on-your-path" class="md-nav__link">
<span class="md-ellipsis">
External tools on your PATH
</span>
</a>
<nav class="md-nav" aria-label="External tools on your PATH">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#required-tools" class="md-nav__link">
<span class="md-ellipsis">
Required tools
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#recommended-and-optional-tools" class="md-nav__link">
<span class="md-ellipsis">
Recommended and optional tools
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#verifying-your-installation" class="md-nav__link">
<span class="md-ellipsis">
Verifying your installation
</span>
</a>
<nav class="md-nav" aria-label="Verifying your installation">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#examine-the-external-dependencies" class="md-nav__link">
<span class="md-ellipsis">
Examine the external dependencies
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#inspect-environment-paths" class="md-nav__link">
<span class="md-ellipsis">
Inspect environment paths
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#next-steps" class="md-nav__link">
<span class="md-ellipsis">
Next steps
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../quickstart/" class="md-nav__link">
<span class="md-ellipsis">
Quick Start
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../configuration-file/" class="md-nav__link">
<span class="md-ellipsis">
The Configuration File
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_3" >
<label class="md-nav__link" for="__nav_3" id="__nav_3_label" tabindex="0">
<span class="md-ellipsis">
User Guide
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_3_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_3">
<span class="md-nav__icon md-icon"></span>
User Guide
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../guide/downloading/" class="md-nav__link">
<span class="md-ellipsis">
Downloading
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../guide/cli-reference/" class="md-nav__link">
<span class="md-ellipsis">
CLI Reference
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../guide/drm-and-cdm/" class="md-nav__link">
<span class="md-ellipsis">
DRM & CDM Setup
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../guide/proxies-and-vpn/" class="md-nav__link">
<span class="md-ellipsis">
Proxies & VPN
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../guide/vaults/" class="md-nav__link">
<span class="md-ellipsis">
Key Vaults
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../guide/output-and-naming/" class="md-nav__link">
<span class="md-ellipsis">
Output & Naming
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../guide/subtitles/" class="md-nav__link">
<span class="md-ellipsis">
Subtitles
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../guide/troubleshooting/" class="md-nav__link">
<span class="md-ellipsis">
Troubleshooting
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_4" >
<div class="md-nav__link md-nav__container">
<a href="../../reference/configuration/" class="md-nav__link ">
<span class="md-ellipsis">
Configuration
</span>
</a>
<label class="md-nav__link " for="__nav_4" id="__nav_4_label" tabindex="0">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_4_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_4">
<span class="md-nav__icon md-icon"></span>
Configuration
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../reference/configuration/directories/" class="md-nav__link">
<span class="md-ellipsis">
Directories
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../reference/configuration/services/" class="md-nav__link">
<span class="md-ellipsis">
Services & Authentication
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../reference/configuration/download/" class="md-nav__link">
<span class="md-ellipsis">
Download & Processing
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../reference/configuration/output/" class="md-nav__link">
<span class="md-ellipsis">
Output & Naming
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../reference/configuration/drm/" class="md-nav__link">
<span class="md-ellipsis">
DRM & CDM
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../reference/configuration/network/" class="md-nav__link">
<span class="md-ellipsis">
Network & Proxy
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../reference/configuration/vaults/" class="md-nav__link">
<span class="md-ellipsis">
Key Vaults
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../reference/configuration/post-scripts/" class="md-nav__link">
<span class="md-ellipsis">
Post-Scripts
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../reference/configuration/misc/" class="md-nav__link">
<span class="md-ellipsis">
Other Settings
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../reference/configuration/example/" class="md-nav__link">
<span class="md-ellipsis">
Annotated Example
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_5" >
<label class="md-nav__link" for="__nav_5" id="__nav_5_label" tabindex="0">
<span class="md-ellipsis">
Developer
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_5_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_5">
<span class="md-nav__icon md-icon"></span>
Developer
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../dev/creating-a-service/" class="md-nav__link">
<span class="md-ellipsis">
Creating a Service
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../dev/service-architecture/" class="md-nav__link">
<span class="md-ellipsis">
Service Architecture
</span>
</a>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_5_3" >
<div class="md-nav__link md-nav__container">
<a href="../../dev/rest-api/" class="md-nav__link ">
<span class="md-ellipsis">
REST API
</span>
</a>
<label class="md-nav__link " for="__nav_5_3" id="__nav_5_3_label" tabindex="0">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_5_3_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_5_3">
<span class="md-nav__icon md-icon"></span>
REST API
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../dev/rest-api/quickstart/" class="md-nav__link">
<span class="md-ellipsis">
Quick Start
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../dev/rest-api/authentication/" class="md-nav__link">
<span class="md-ellipsis">
Authentication
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../dev/rest-api/endpoints/" class="md-nav__link">
<span class="md-ellipsis">
Endpoints
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../dev/rest-api/job-lifecycle/" class="md-nav__link">
<span class="md-ellipsis">
Job Lifecycle
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../dev/rest-api/dashboard/" class="md-nav__link">
<span class="md-ellipsis">
Dashboard
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../dev/rest-api/remote-sessions/" class="md-nav__link">
<span class="md-ellipsis">
Remote Sessions
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../dev/rest-api/errors/" class="md-nav__link">
<span class="md-ellipsis">
Error Responses
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_6" >
<label class="md-nav__link" for="__nav_6" id="__nav_6_label" tabindex="0">
<span class="md-ellipsis">
API Reference
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_6_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_6">
<span class="md-nav__icon md-icon"></span>
API Reference
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../reference/api/service/" class="md-nav__link">
<span class="md-ellipsis">
Service
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../reference/api/config/" class="md-nav__link">
<span class="md-ellipsis">
Config
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../reference/api/tracks/" class="md-nav__link">
<span class="md-ellipsis">
Tracks
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../reference/api/titles/" class="md-nav__link">
<span class="md-ellipsis">
Titles
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../reference/api/drm/" class="md-nav__link">
<span class="md-ellipsis">
DRM
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-sidebar md-sidebar--secondary" data-md-component="sidebar" data-md-type="toc" >
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
<label class="md-nav__title" for="__toc">
<span class="md-nav__icon md-icon"></span>
Table of contents
</label>
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
<li class="md-nav__item">
<a href="#install-from-a-git-clone-recommended" class="md-nav__link">
<span class="md-ellipsis">
Install from a git clone (recommended)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#what-unshackle-setup-does" class="md-nav__link">
<span class="md-ellipsis">
What unshackle setup does
</span>
</a>
<nav class="md-nav" aria-label="What unshackle setup does">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#where-setup-puts-files" class="md-nav__link">
<span class="md-ellipsis">
Where setup puts files
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#requirements-at-a-glance" class="md-nav__link">
<span class="md-ellipsis">
Requirements at a glance
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#python-versions" class="md-nav__link">
<span class="md-ellipsis">
Python versions
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#installing-by-hand" class="md-nav__link">
<span class="md-ellipsis">
Installing by hand
</span>
</a>
<nav class="md-nav" aria-label="Installing by hand">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#running-from-a-clone" class="md-nav__link">
<span class="md-ellipsis">
Running from a clone
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#advanced-install-as-a-uv-tool" class="md-nav__link">
<span class="md-ellipsis">
Advanced: install as a uv tool
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#external-tools-on-your-path" class="md-nav__link">
<span class="md-ellipsis">
External tools on your PATH
</span>
</a>
<nav class="md-nav" aria-label="External tools on your PATH">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#required-tools" class="md-nav__link">
<span class="md-ellipsis">
Required tools
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#recommended-and-optional-tools" class="md-nav__link">
<span class="md-ellipsis">
Recommended and optional tools
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#verifying-your-installation" class="md-nav__link">
<span class="md-ellipsis">
Verifying your installation
</span>
</a>
<nav class="md-nav" aria-label="Verifying your installation">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#examine-the-external-dependencies" class="md-nav__link">
<span class="md-ellipsis">
Examine the external dependencies
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#inspect-environment-paths" class="md-nav__link">
<span class="md-ellipsis">
Inspect environment paths
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#next-steps" class="md-nav__link">
<span class="md-ellipsis">
Next steps
</span>
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-content" data-md-component="content">
<article class="md-content__inner md-typeset">
<h1 id="installation">Installation<a class="headerlink" href="#installation" title="Permanent link">&para;</a></h1>
<p>unshackle is a modular archival tool for movies, TV, and music. It ships as a
single Python package named <code>unshackle</code> that installs one console command, also
called <code>unshackle</code>. This page covers the install script, the <code>unshackle setup</code>
command, the Python version unshackle needs, and the external command-line tools
it expects to find.</p>
<div class="admonition note">
<p class="admonition-title">What you get</p>
<p>Installing the package registers a single entry point, the <code>unshackle</code>
command. It covers everything: downloading, key-vault management, device
provisioning, the REST server, and the helper utilities.</p>
</div>
<h2 id="install-from-a-git-clone-recommended">Install from a git clone (recommended)<a class="headerlink" href="#install-from-a-git-clone-recommended" title="Permanent link">&para;</a></h2>
<p>A git clone with the install script is the recommended way to install unshackle.
A clone keeps unshackle, its external tools, its config, its data folders, and
your services together in one folder that you can see.</p>
<p>The repository has an install script for Linux (<code>install.sh</code>) and for Windows
(<code>install.bat</code>). The script installs <code>uv</code> if it is not found, installs unshackle,
and then runs <a href="#what-unshackle-setup-does"><code>unshackle setup</code></a>.</p>
<div class="tabbed-set tabbed-alternate" data-tabs="1:2"><input checked="checked" id="__tabbed_1_1" name="__tabbed_1" type="radio" /><input id="__tabbed_1_2" name="__tabbed_1" type="radio" /><div class="tabbed-labels"><label for="__tabbed_1_1">Linux</label><label for="__tabbed_1_2">Windows</label></div>
<div class="tabbed-content">
<div class="tabbed-block">
<div class="language-shell highlight"><pre><span></span><code><span id="__span-0-1"><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a>git<span class="w"> </span>clone<span class="w"> </span>https://github.com/unshackle-dl/unshackle.git
</span><span id="__span-0-2"><a id="__codelineno-0-2" name="__codelineno-0-2" href="#__codelineno-0-2"></a><span class="nb">cd</span><span class="w"> </span>unshackle
</span><span id="__span-0-3"><a id="__codelineno-0-3" name="__codelineno-0-3" href="#__codelineno-0-3"></a>sh<span class="w"> </span>install.sh
</span></code></pre></div>
</div>
<div class="tabbed-block">
<div class="language-bat highlight"><pre><span></span><code><span id="__span-1-1"><a id="__codelineno-1-1" name="__codelineno-1-1" href="#__codelineno-1-1"></a>git clone https://github.com/unshackle-dl/unshackle.git
</span><span id="__span-1-2"><a id="__codelineno-1-2" name="__codelineno-1-2" href="#__codelineno-1-2"></a><span class="k">cd</span> unshackle
</span><span id="__span-1-3"><a id="__codelineno-1-3" name="__codelineno-1-3" href="#__codelineno-1-3"></a>.\install.bat
</span></code></pre></div>
</div>
</div>
</div>
<p>In a clone, the script runs <code>uv sync</code> and then <code>uv run unshackle setup</code>. The last
lines of setup tell you to check your tools with <code>uv run unshackle env check</code>.
Run unshackle from the clone with <code>uv run unshackle ...</code>.</p>
<p>To install without a clone, see
<a href="#advanced-install-as-a-uv-tool">Advanced: install as a uv tool</a>.</p>
<h2 id="what-unshackle-setup-does">What <code>unshackle setup</code> does<a class="headerlink" href="#what-unshackle-setup-does" title="Permanent link">&para;</a></h2>
<p><code>unshackle setup</code> prepares a new installation. The install script runs it for
you, and you can run it yourself at any time:</p>
<div class="tabbed-set tabbed-alternate" data-tabs="2:2"><input checked="checked" id="__tabbed_2_1" name="__tabbed_2" type="radio" /><input id="__tabbed_2_2" name="__tabbed_2" type="radio" /><div class="tabbed-labels"><label for="__tabbed_2_1">From a clone</label><label for="__tabbed_2_2">Installed as a uv tool</label></div>
<div class="tabbed-content">
<div class="tabbed-block">
<div class="language-shell highlight"><pre><span></span><code><span id="__span-2-1"><a id="__codelineno-2-1" name="__codelineno-2-1" href="#__codelineno-2-1"></a>uv<span class="w"> </span>run<span class="w"> </span>unshackle<span class="w"> </span>setup
</span></code></pre></div>
</div>
<div class="tabbed-block">
<div class="language-shell highlight"><pre><span></span><code><span id="__span-3-1"><a id="__codelineno-3-1" name="__codelineno-3-1" href="#__codelineno-3-1"></a>unshackle<span class="w"> </span>setup
</span></code></pre></div>
</div>
</div>
</div>
<p>The command does these steps:</p>
<ol>
<li>It shows which <a href="#external-tools-on-your-path">external tools</a> are missing,
and where to get the ones that it cannot download.</li>
<li>It asks once for each tool or group of tools to download. The required
tools come first. shaka-packager and <code>mp4decrypt</code> share one DRM question, so
<code>mp4decrypt</code> comes with the required tools, but <code>env check</code> still shows it
as optional. The HDR and subtitle groups are optional. The prompts show the
version that setup downloads. On Windows, the subtitle question also shows
the download size of CCExtractor, which is much larger than the other tools.
It puts the downloads in a <code>binaries</code> folder
(see <a href="#where-setup-puts-files">Where setup puts files</a>).</li>
<li>If no <code>unshackle.yaml</code> exists, it asks for a downloads folder and writes a
minimal config file.</li>
<li>It makes the data folders for cookies, WVDs, PRDs, and services.</li>
<li>It asks for <code>.wvd</code> and <code>.prd</code> devices to import. You can give a file or a
folder of devices, and it asks again until you give an empty answer. It
validates each file, copies it into the WVDs or PRDs folder, and prints one
line for each file. If setup wrote a new config in this run, it sets
<code>cdm.default</code> to the imported device. If you imported more than one, it
asks which one is the default.</li>
<li>It prints a summary of the tools that it found. If it wrote a config, it
gives the path of that config and a link to the
<a href="../../reference/configuration/">configuration reference</a>. Then it
tells you to run <code>env check</code> next.</li>
</ol>
<p>You can run the command again. It skips the tools that it finds and never
overwrites an existing config.</p>
<div class="admonition note">
<p class="admonition-title">Not every tool has a download</p>
<p>Setup downloads tools only on Linux and Windows, and only when the tool
has a portable build for your system. For other tools, setup prints where
to get them, for example a package manager. On macOS, setup downloads
nothing and prints these links for each missing tool.</p>
<p>On Linux, setup cannot download MKVToolNix, which is a required tool.
Install the <code>mkvtoolnix</code> package with your package manager (for example
<code>apt</code>, <code>dnf</code>, or <code>pacman</code>).</p>
</div>
<div class="admonition warning">
<p class="admonition-title">CCExtractor on Linux needs FUSE</p>
<p>On Linux, setup downloads CCExtractor as an AppImage, which needs FUSE to
run. Setup runs the AppImage once after the download. If it does not run, setup removes it and prints the
manual install link. Install FUSE with your package manager and run setup
again, or install the <code>ccextractor</code> package instead.</p>
</div>
<h3 id="where-setup-puts-files">Where setup puts files<a class="headerlink" href="#where-setup-puts-files" title="Permanent link">&para;</a></h3>
<table>
<thead>
<tr>
<th>Item</th>
<th>From a git clone</th>
<th>From a <code>uv</code> tool install</th>
</tr>
</thead>
<tbody>
<tr>
<td>External tools</td>
<td><code>unshackle/binaries</code> in the clone</td>
<td><code>binaries</code> in the user data directory</td>
</tr>
<tr>
<td>New config (<code>unshackle.yaml</code>)</td>
<td><code>unshackle/unshackle.yaml</code> in the clone</td>
<td>The user config directory</td>
</tr>
<tr>
<td>Data folders (cookies, WVDs, PRDs, cache, logs, services, temp)</td>
<td>The default folders in the clone</td>
<td>The user data directory</td>
</tr>
<tr>
<td>Downloads</td>
<td>The folder that you give at the prompt</td>
<td>The folder that you give at the prompt</td>
</tr>
</tbody>
</table>
<p>On Windows, CCExtractor and its libraries go into their own <code>ccextractor</code>
subfolder of the tools folder.</p>
<p>On Linux, the user data directory is usually <code>~/.local/share/unshackle</code> and the
user config directory is usually <code>~/.config/unshackle</code>. On Windows, both are
<code>%LOCALAPPDATA%\unshackle</code>. Run <code>uv run unshackle env info</code> to see the paths that
unshackle uses. Its <code>User_Binaries</code> row shows the <code>binaries</code> folder in the user
data directory.</p>
<p>Setup writes a new config only when it finds no <code>unshackle.yaml</code> in any of the
<a href="../configuration-file/">config locations</a>. It keeps an existing config where it
is. In a clone, the new config sets only <code>directories.downloads</code>, so the data
folders stay at their defaults in the clone.</p>
<p>A <code>uv</code> tool upgrade replaces the package folder. For a <code>uv</code> tool install, setup
puts the tools in the user data directory and writes a <code>directories</code> block that
moves the data folders there, so an upgrade keeps them. If an existing config
keeps data folders inside the package of a <code>uv</code> tool install, setup shows a
warning and prints the <code>directories</code> lines to add.</p>
<h2 id="requirements-at-a-glance">Requirements at a glance<a class="headerlink" href="#requirements-at-a-glance" title="Permanent link">&para;</a></h2>
<table>
<thead>
<tr>
<th>Requirement</th>
<th>Recommended version</th>
<th>Needed for</th>
</tr>
</thead>
<tbody>
<tr>
<td><a href="https://www.python.org/">Python</a></td>
<td>3.11 to 3.14</td>
<td>Running unshackle itself</td>
</tr>
<tr>
<td><a href="https://docs.astral.sh/uv/">uv</a></td>
<td>≥ 0.5</td>
<td>Installing and running unshackle</td>
</tr>
<tr>
<td><a href="https://ffmpeg.org/">FFmpeg</a></td>
<td>≥ 6.0</td>
<td>Media processing and analysis</td>
</tr>
<tr>
<td><a href="https://mkvtoolnix.download/">MKVToolNix</a></td>
<td>≥ 80</td>
<td>MKV muxing and metadata editing</td>
</tr>
<tr>
<td><a href="https://github.com/shaka-project/shaka-packager">shaka-packager</a></td>
<td>2.6.1, or ≥ 3.10.0</td>
<td>DRM decryption</td>
</tr>
<tr>
<td><a href="https://github.com/axiomatic-systems/Bento4">Bento4</a></td>
<td>≥ 1.6.0-639</td>
<td>Alternate DRM decryption (<code>mp4decrypt</code>)</td>
</tr>
<tr>
<td><a href="https://github.com/quietvoid/dovi_tool">dovi_tool</a></td>
<td>≥ 2.1</td>
<td>Dolby Vision handling</td>
</tr>
<tr>
<td><a href="https://github.com/SubtitleEdit/subtitleedit/releases">SubtitleEdit</a></td>
<td>≥ 5.0</td>
<td>Subtitle conversion (optional)</td>
</tr>
</tbody>
</table>
<p>The sections below tell you about each of these, and how to make sure that your
setup is complete.</p>
<h2 id="python-versions">Python versions<a class="headerlink" href="#python-versions" title="Permanent link">&para;</a></h2>
<p>unshackle requires <strong>Python 3.11 or newer, up to and including 3.14</strong>
(<code>requires-python = "&gt;=3.11,&lt;3.15"</code>). Anything older than 3.11 or 3.15 and
later is unsupported, and the installer refuses to assemble the environment.</p>
<p>You do not usually need to install a matching Python interpreter by hand, since
<code>uv</code> can download and manage one for you. If you work inside an existing
virtual environment, make sure that it is on a supported version.</p>
<h2 id="installing-by-hand">Installing by hand<a class="headerlink" href="#installing-by-hand" title="Permanent link">&para;</a></h2>
<p>If you do not use the install script, install unshackle with <code>uv</code> and then run
<code>unshackle setup</code>, or install the <a href="#external-tools-on-your-path">external tools</a>
yourself.</p>
<h3 id="running-from-a-clone">Running from a clone<a class="headerlink" href="#running-from-a-clone" title="Permanent link">&para;</a></h3>
<p>Use <code>uv run</code> inside the clone. It keeps the project's virtual environment active
for the duration of the command, so you do not have to activate it yourself. It
also installs the dependencies on the first run.</p>
<div class="language-shell highlight"><span class="filename">Run from a git clone</span><pre><span></span><code><span id="__span-4-1"><a id="__codelineno-4-1" name="__codelineno-4-1" href="#__codelineno-4-1"></a>git<span class="w"> </span>clone<span class="w"> </span>https://github.com/unshackle-dl/unshackle.git
</span><span id="__span-4-2"><a id="__codelineno-4-2" name="__codelineno-4-2" href="#__codelineno-4-2"></a><span class="nb">cd</span><span class="w"> </span>unshackle
</span><span id="__span-4-3"><a id="__codelineno-4-3" name="__codelineno-4-3" href="#__codelineno-4-3"></a>uv<span class="w"> </span>run<span class="w"> </span>unshackle<span class="w"> </span>setup
</span></code></pre></div>
<p>Every command shown elsewhere in these docs works the same way from a clone.
Prefix it with <code>uv run</code>:</p>
<div class="language-shell highlight"><pre><span></span><code><span id="__span-5-1"><a id="__codelineno-5-1" name="__codelineno-5-1" href="#__codelineno-5-1"></a>uv<span class="w"> </span>run<span class="w"> </span>unshackle<span class="w"> </span>env<span class="w"> </span>check
</span></code></pre></div>
<h3 id="advanced-install-as-a-uv-tool">Advanced: install as a uv tool<a class="headerlink" href="#advanced-install-as-a-uv-tool" title="Permanent link">&para;</a></h3>
<p>This way is for users who know <code>uv</code> tools and want the <code>unshackle</code> command on
their <code>PATH</code> without a clone.</p>
<div class="admonition note">
<p class="admonition-title">Where a uv tool install keeps files</p>
<p><code>uv tool install</code> puts unshackle into the tool folder of <code>uv</code>, not into a
folder that you choose. <code>unshackle setup</code> therefore puts the external
tools, the config, and the data folders in your user data and config
directories (see <a href="#where-setup-puts-files">Where setup puts files</a>). A git
clone is the easier setup: its tools, config, data, and services stay in
one folder that you can see. On the first run from a <code>uv</code> tool install,
<code>unshackle setup</code> tells you this and asks if you want to continue.</p>
</div>
<p>Install the tool and run setup:</p>
<div class="language-shell highlight"><span class="filename">Install as a uv tool</span><pre><span></span><code><span id="__span-6-1"><a id="__codelineno-6-1" name="__codelineno-6-1" href="#__codelineno-6-1"></a>uv<span class="w"> </span>tool<span class="w"> </span>install<span class="w"> </span>git+https://github.com/unshackle-dl/unshackle.git
</span><span id="__span-6-2"><a id="__codelineno-6-2" name="__codelineno-6-2" href="#__codelineno-6-2"></a>unshackle<span class="w"> </span>setup
</span></code></pre></div>
<p>The install scripts also do this when you run one alone, without a clone: when
the script does not find the unshackle <code>pyproject.toml</code> next to it, it runs
<code>uv tool install</code> and then <code>unshackle setup</code>. When it finishes, it tells you to
open a new terminal, because the <code>PATH</code> change only applies to new terminals.
Run <code>unshackle env check</code> there.</p>
<div class="admonition tip">
<p class="admonition-title">Upgrading and removing</p>
<p>Because you installed it from a git URL, re-run the same
<code>uv tool install</code> command (uv will update in place) to get a newer version,
and use <code>uv tool uninstall unshackle</code> to remove it.</p>
</div>
<div class="admonition note">
<p class="admonition-title">Developer note</p>
<p>Contributors will also want the development and test dependency groups. The
project defines <code>dev</code> (linters, type checkers) and <code>test</code> (pytest and
friends) groups in <code>pyproject.toml</code>. Install them with
<code>uv sync --group dev --group test</code> inside the clone. End users can ignore
these entirely.</p>
</div>
<h2 id="external-tools-on-your-path">External tools on your PATH<a class="headerlink" href="#external-tools-on-your-path" title="Permanent link">&para;</a></h2>
<p>unshackle shells out to a number of external command-line programs for media
processing and DRM work. It looks for each one first in the <code>binaries/</code> folder
inside the installed package, then in the <code>binaries</code> folder of your user data
directory, and then on your system <code>PATH</code>. <code>unshackle setup</code> installs tools into
the first folder in a clone and into the second for a <code>uv</code> tool install. Installing a tool system-wide or putting it into one of those folders
both work.</p>
<p><code>unshackle setup</code> installs the required tools and some optional ones for you.
Use the tables below when you install a tool by hand.</p>
<h3 id="required-tools">Required tools<a class="headerlink" href="#required-tools" title="Permanent link">&para;</a></h3>
<p>These must be present for core downloading, decryption, and muxing to work:</p>
<table>
<thead>
<tr>
<th>Tool</th>
<th>Binary looked up</th>
<th>Why it is needed</th>
</tr>
</thead>
<tbody>
<tr>
<td>FFmpeg</td>
<td><code>ffmpeg</code></td>
<td>Media processing: remuxing, conversion, track handling</td>
</tr>
<tr>
<td>FFprobe</td>
<td><code>ffprobe</code></td>
<td>Media analysis: inspecting tracks and container details</td>
</tr>
<tr>
<td>MKVToolNix</td>
<td><code>mkvmerge</code></td>
<td>Muxing downloaded tracks into a final MKV</td>
</tr>
<tr>
<td>mkvpropedit</td>
<td><code>mkvpropedit</code></td>
<td>Editing MKV metadata after muxing</td>
</tr>
<tr>
<td>shaka-packager</td>
<td><code>shaka-packager</code> / <code>packager</code></td>
<td>Decrypting DRM-protected content (the default decryptor)</td>
</tr>
</tbody>
</table>
<div class="admonition warning">
<p class="admonition-title">shaka-packager is the default decryptor</p>
<p>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 <a href="../../reference/configuration/drm/#decryption">configuration reference</a> for the
<code>decryption</code> config key if you want to switch to <code>mp4decrypt</code>.</p>
</div>
<div class="admonition danger">
<p class="admonition-title">Do not use shaka-packager 3.0 through 3.9.x</p>
<p>These versions stop with a segmentation fault on a single-track MP4 whose
internal <code>track_id</code> is 2 or more. A track that unshackle downloads from a
DASH or HLS manifest usually has such a <code>track_id</code>.</p>
</div>
<h3 id="recommended-and-optional-tools">Recommended and optional tools<a class="headerlink" href="#recommended-and-optional-tools" title="Permanent link">&para;</a></h3>
<p>These extend unshackle's capabilities. Install the ones relevant to what you
download. For example, <code>dovi_tool</code> only matters if you download Dolby Vision video.</p>
<table>
<thead>
<tr>
<th>Tool</th>
<th>Binary looked up</th>
<th>Why it is needed</th>
</tr>
</thead>
<tbody>
<tr>
<td>Bento4 (<code>mp4decrypt</code>)</td>
<td><code>mp4decrypt</code></td>
<td>Alternative DRM decryptor to shaka-packager</td>
</tr>
<tr>
<td>MP4Box (GPAC)</td>
<td><code>MP4Box</code></td>
<td>Muxing DTS:X Profile 2 (DTS-UHD) and MPEG-H audio</td>
</tr>
<tr>
<td>dovi_tool</td>
<td><code>dovi_tool</code></td>
<td>Dolby Vision metadata handling</td>
</tr>
<tr>
<td>HDR10Plus_tool</td>
<td><code>hdr10plus_tool</code></td>
<td>HDR10+ metadata handling</td>
</tr>
<tr>
<td>SubtitleEdit</td>
<td><code>seconv</code>, <code>SubtitleEdit</code></td>
<td>Subtitle conversion (the <code>SeConv</code> CLI from 5.x)</td>
</tr>
<tr>
<td>CCExtractor</td>
<td><code>ccextractor</code>, <code>ccextractorwin</code>, <code>ccextractorwinfull</code></td>
<td>Extracting closed captions</td>
</tr>
<tr>
<td>FFplay</td>
<td><code>ffplay</code></td>
<td>Simple preview player</td>
</tr>
<tr>
<td>MPV</td>
<td><code>mpv</code></td>
<td>Advanced preview player (used by <code>util crop</code>/<code>util range</code> previews)</td>
</tr>
<tr>
<td>HolaProxy</td>
<td><code>hola-proxy</code></td>
<td>Hola proxy provider support</td>
</tr>
<tr>
<td>Caddy</td>
<td><code>caddy</code></td>
<td>Optional reverse proxy for <code>unshackle serve --caddy</code></td>
</tr>
<tr>
<td>Docker</td>
<td><code>docker</code></td>
<td>Gluetun VPN proxy support</td>
</tr>
<tr>
<td>Git</td>
<td><code>git</code></td>
<td>Fetching and updating remote service repositories</td>
</tr>
</tbody>
</table>
<div class="admonition info">
<p class="admonition-title">MP4Box is only used for DTS:X Profile 2 and MPEG-H</p>
<p>Titles with DTS:X Profile 2 (DTS-UHD) or MPEG-H audio mux to MP4; everything else muxes to MKV
with <code>mkvmerge</code>. Install with <code>apt install gpac</code>.</p>
</div>
<div class="admonition tip">
<p class="admonition-title">SubtitleEdit specifics</p>
<p>unshackle looks for <code>seconv</code> first, the batch CLI shipped with
SubtitleEdit 5.x, before falling back to a <code>SubtitleEdit</code> (4.x) binary. The
5.0 GUI has no batch mode, so the <code>SeConv</code> CLI is what you want for
automated subtitle conversion.</p>
</div>
<h2 id="verifying-your-installation">Verifying your installation<a class="headerlink" href="#verifying-your-installation" title="Permanent link">&para;</a></h2>
<p>After installation, make sure that unshackle can see the tools it depends on.</p>
<h3 id="examine-the-external-dependencies">Examine the external dependencies<a class="headerlink" href="#examine-the-external-dependencies" title="Permanent link">&para;</a></h3>
<p>The <code>env check</code> subcommand is the first check. It inspects your environment and
reports which tools it found:</p>
<div class="tabbed-set tabbed-alternate" data-tabs="3:2"><input checked="checked" id="__tabbed_3_1" name="__tabbed_3" type="radio" /><input id="__tabbed_3_2" name="__tabbed_3" type="radio" /><div class="tabbed-labels"><label for="__tabbed_3_1">From a clone</label><label for="__tabbed_3_2">Installed as a uv tool</label></div>
<div class="tabbed-content">
<div class="tabbed-block">
<div class="language-shell highlight"><pre><span></span><code><span id="__span-7-1"><a id="__codelineno-7-1" name="__codelineno-7-1" href="#__codelineno-7-1"></a>uv<span class="w"> </span>run<span class="w"> </span>unshackle<span class="w"> </span>env<span class="w"> </span>check
</span></code></pre></div>
</div>
<div class="tabbed-block">
<div class="language-shell highlight"><pre><span></span><code><span id="__span-8-1"><a id="__codelineno-8-1" name="__codelineno-8-1" href="#__codelineno-8-1"></a>unshackle<span class="w"> </span>env<span class="w"> </span>check
</span></code></pre></div>
</div>
</div>
</div>
<p>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. A version column shows the version that each
tool reports, or <code>-</code> when it reports none. It ends with a summary line such as
<code>All required tools installed ✓</code> or <code>Missing required: &lt;names&gt;</code>.</p>
<p>If a required tool shows as missing, <code>env check</code> tells you to run
<code>unshackle setup</code>. You can also install the tool by hand and put it on your
<code>PATH</code> (or in one of the <code>binaries</code> folders), then re-run the check.</p>
<div class="admonition tip">
<p class="admonition-title"><code>unshackle</code> is not found after a uv tool install</p>
<p>The bin directory of <code>uv</code> tools is probably not on your <code>PATH</code>. Run
<code>uv tool update-shell</code> and open a new terminal.</p>
</div>
<h3 id="inspect-environment-paths">Inspect environment paths<a class="headerlink" href="#inspect-environment-paths" title="Permanent link">&para;</a></h3>
<p>To see where unshackle will read its configuration from and where it stores
downloads, caches, cookies, and devices, use:</p>
<div class="language-shell highlight"><pre><span></span><code><span id="__span-9-1"><a id="__codelineno-9-1" name="__codelineno-9-1" href="#__codelineno-9-1"></a>uv<span class="w"> </span>run<span class="w"> </span>unshackle<span class="w"> </span>env<span class="w"> </span>info
</span></code></pre></div>
<p>If no configuration file exists yet, this command lists the locations unshackle
searches for one, so you know where to make it. See the
<a href="../configuration-file/">configuration guide</a> for the details of that file.</p>
<h2 id="next-steps">Next steps<a class="headerlink" href="#next-steps" title="Permanent link">&para;</a></h2>
<ul>
<li>Set up your <a href="../configuration-file/">configuration</a> file (<code>unshackle.yaml</code>), or
let <code>unshackle setup</code> write a first one.</li>
<li>Start <a href="../../guide/downloading/">downloading</a> titles when <code>env check</code> finds every required tool.</li>
</ul>
</article>
</div>
<script>var tabs=__md_get("__tabs");if(Array.isArray(tabs))e:for(var set of document.querySelectorAll(".tabbed-set")){var labels=set.querySelector(".tabbed-labels");for(var tab of tabs)for(var label of labels.getElementsByTagName("label"))if(label.innerText.trim()===tab){var input=document.getElementById(label.htmlFor);input.checked=!0;continue e}}</script>
<script>var target=document.getElementById(location.hash.slice(1));target&&target.name&&(target.checked=target.name.startsWith("__tabbed_"))</script>
</div>
<button type="button" class="md-top md-icon" data-md-component="top" hidden>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M13 20h-2V8l-5.5 5.5-1.42-1.42L12 4.16l7.92 7.92-1.42 1.42L13 8z"/></svg>
Back to top
</button>
</main>
<footer class="md-footer">
<nav class="md-footer__inner md-grid" aria-label="Footer" >
<a href="../.." class="md-footer__link md-footer__link--prev" aria-label="Previous: Home">
<div class="md-footer__button md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11z"/></svg>
</div>
<div class="md-footer__title">
<span class="md-footer__direction">
Previous
</span>
<div class="md-ellipsis">
Home
</div>
</div>
</a>
<a href="../quickstart/" class="md-footer__link md-footer__link--next" aria-label="Next: Quick Start">
<div class="md-footer__title">
<span class="md-footer__direction">
Next
</span>
<div class="md-ellipsis">
Quick Start
</div>
</div>
<div class="md-footer__button md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M4 11v2h12l-5.5 5.5 1.42 1.42L19.84 12l-7.92-7.92L10.5 5.5 16 11z"/></svg>
</div>
</a>
</nav>
<div class="md-footer-meta md-typeset">
<div class="md-footer-meta__inner md-grid">
<div class="md-copyright">
Made with
<a href="https://squidfunk.github.io/mkdocs-material/" target="_blank" rel="noopener">
Material for MkDocs
</a>
</div>
</div>
</div>
</footer>
</div>
<div class="md-dialog" data-md-component="dialog">
<div class="md-dialog__inner md-typeset"></div>
</div>
<script id="__config" type="application/json">{"annotate": null, "base": "../..", "features": ["content.code.annotate", "content.code.copy", "content.tabs.link", "content.tooltips", "navigation.footer", "navigation.indexes", "navigation.sections", "navigation.tabs", "navigation.top", "navigation.tracking", "search.highlight", "search.share", "search.suggest", "toc.follow"], "search": "../../assets/javascripts/workers/search.a7633da7.min.js", "tags": null, "translations": {"clipboard.copied": "Copied to clipboard", "clipboard.copy": "Copy to clipboard", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.placeholder": "Type to start searching", "search.result.term.missing": "Missing", "select.version": "Select version"}, "version": null}</script>
<script src="../../assets/javascripts/bundle.c21346df.min.js"></script>
</body>
</html>