Deployed 40ae213 with MkDocs version: 1.6.1

This commit is contained in:
2026-07-27 03:22:22 +00:00
parent 27d27311ed
commit 9df7fbe9ea
7 changed files with 130 additions and 153 deletions
@@ -2025,7 +2025,7 @@ turned into underscores (<code>--best-available</code> → <code>best_available<
<div class="language-yaml highlight"><span class="filename">unshackle.yaml</span><pre><span></span><code><span id="__span-4-1"><a id="__codelineno-4-1" name="__codelineno-4-1" href="#__codelineno-4-1"></a><span class="nt">dl</span><span class="p">:</span> <div class="language-yaml highlight"><span class="filename">unshackle.yaml</span><pre><span></span><code><span id="__span-4-1"><a id="__codelineno-4-1" name="__codelineno-4-1" href="#__codelineno-4-1"></a><span class="nt">dl</span><span class="p">:</span>
</span><span id="__span-4-2"><a id="__codelineno-4-2" name="__codelineno-4-2" href="#__codelineno-4-2"></a><span class="w"> </span><span class="nt">lang</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">[</span><span class="nv">en</span><span class="p p-Indicator">]</span><span class="w"> </span><span class="c1"># -l en</span> </span><span id="__span-4-2"><a id="__codelineno-4-2" name="__codelineno-4-2" href="#__codelineno-4-2"></a><span class="w"> </span><span class="nt">lang</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">[</span><span class="nv">en</span><span class="p p-Indicator">]</span><span class="w"> </span><span class="c1"># -l en</span>
</span><span id="__span-4-3"><a id="__codelineno-4-3" name="__codelineno-4-3" href="#__codelineno-4-3"></a><span class="w"> </span><span class="nt">quality</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">[</span><span class="nv">1080</span><span class="p p-Indicator">]</span><span class="w"> </span><span class="c1"># -q 1080</span> </span><span id="__span-4-3"><a id="__codelineno-4-3" name="__codelineno-4-3" href="#__codelineno-4-3"></a><span class="w"> </span><span class="nt">quality</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">[</span><span class="nv">1080</span><span class="p p-Indicator">]</span><span class="w"> </span><span class="c1"># -q 1080</span>
</span><span id="__span-4-4"><a id="__codelineno-4-4" name="__codelineno-4-4" href="#__codelineno-4-4"></a><span class="w"> </span><span class="nt">vcodec</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">[</span><span class="nv">H265</span><span class="p p-Indicator">]</span><span class="w"> </span><span class="c1"># -v H265</span> </span><span id="__span-4-4"><a id="__codelineno-4-4" name="__codelineno-4-4" href="#__codelineno-4-4"></a><span class="w"> </span><span class="nt">vcodec</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">[</span><span class="nv">H.265</span><span class="p p-Indicator">]</span><span class="w"> </span><span class="c1"># -v H.265</span>
</span><span id="__span-4-5"><a id="__codelineno-4-5" name="__codelineno-4-5" href="#__codelineno-4-5"></a><span class="w"> </span><span class="nt">sub_format</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">srt</span><span class="w"> </span><span class="c1"># convert subtitles to SRT</span> </span><span id="__span-4-5"><a id="__codelineno-4-5" name="__codelineno-4-5" href="#__codelineno-4-5"></a><span class="w"> </span><span class="nt">sub_format</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">srt</span><span class="w"> </span><span class="c1"># convert subtitles to SRT</span>
</span><span id="__span-4-6"><a id="__codelineno-4-6" name="__codelineno-4-6" href="#__codelineno-4-6"></a><span class="w"> </span><span class="nt">downloads</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">2</span><span class="w"> </span><span class="c1"># two tracks at once</span> </span><span id="__span-4-6"><a id="__codelineno-4-6" name="__codelineno-4-6" href="#__codelineno-4-6"></a><span class="w"> </span><span class="nt">downloads</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">2</span><span class="w"> </span><span class="c1"># two tracks at once</span>
</span></code></pre></div> </span></code></pre></div>
@@ -2132,17 +2132,17 @@ and every available key.</p>
</table> </table>
<div class="admonition note"> <div class="admonition note">
<p class="admonition-title">Some directories cannot be moved</p> <p class="admonition-title">Some directories cannot be moved</p>
<p>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 <code>directories</code>, unshackle silently ignores the override. This is intentional; those paths are tied to where the package is installed.</p> <p>unshackle protects five internal entries: <code>app_dirs</code>, <code>core_dir</code>, <code>namespace_dir</code>, <code>user_configs</code>, and <code>data</code>. If you list any of them under <code>directories</code>, unshackle ignores the override. This is intentional; those paths are tied to where the package is installed.</p>
</div> </div>
<h3 id="the-services-directory-is-special">The <code>services</code> directory is special<a class="headerlink" href="#the-services-directory-is-special" title="Permanent link">&para;</a></h3> <h3 id="the-services-directory-is-special">The <code>services</code> directory is special<a class="headerlink" href="#the-services-directory-is-special" title="Permanent link">&para;</a></h3>
<p>Unlike the other entries, <code>services</code> is a <strong>list</strong>, 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:</p> <p>Unlike the other entries, <code>services</code> is a <strong>list</strong>, 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:</p>
<div class="language-yaml highlight"><span class="filename">unshackle.yaml</span><pre><span></span><code><span id="__span-7-1"><a id="__codelineno-7-1" name="__codelineno-7-1" href="#__codelineno-7-1"></a><span class="nt">directories</span><span class="p">:</span> <div class="language-yaml highlight"><span class="filename">unshackle.yaml</span><pre><span></span><code><span id="__span-7-1"><a id="__codelineno-7-1" name="__codelineno-7-1" href="#__codelineno-7-1"></a><span class="nt">directories</span><span class="p">:</span>
</span><span id="__span-7-2"><a id="__codelineno-7-2" name="__codelineno-7-2" href="#__codelineno-7-2"></a><span class="w"> </span><span class="nt">services</span><span class="p">:</span> </span><span id="__span-7-2"><a id="__codelineno-7-2" name="__codelineno-7-2" href="#__codelineno-7-2"></a><span class="w"> </span><span class="nt">services</span><span class="p">:</span>
</span><span id="__span-7-3"><a id="__codelineno-7-3" name="__codelineno-7-3" href="#__codelineno-7-3"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">unshackle-dl/services</span><span class="w"> </span><span class="c1"># a GitHub owner/repo shorthand</span> </span><span id="__span-7-3"><a id="__codelineno-7-3" name="__codelineno-7-3" href="#__codelineno-7-3"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">you/your-services</span><span class="w"> </span><span class="c1"># a GitHub owner/repo shorthand</span>
</span><span id="__span-7-4"><a id="__codelineno-7-4" name="__codelineno-7-4" href="#__codelineno-7-4"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">https://github.com/me/my-services.git</span> </span><span id="__span-7-4"><a id="__codelineno-7-4" name="__codelineno-7-4" href="#__codelineno-7-4"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">https://example.com/private-services.git</span>
</span><span id="__span-7-5"><a id="__codelineno-7-5" name="__codelineno-7-5" href="#__codelineno-7-5"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">~/code/local-services</span><span class="w"> </span><span class="c1"># a local folder</span> </span><span id="__span-7-5"><a id="__codelineno-7-5" name="__codelineno-7-5" href="#__codelineno-7-5"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">~/code/local-services</span><span class="w"> </span><span class="c1"># a local folder</span>
</span></code></pre></div> </span></code></pre></div>
<p>Entries are searched in the order listed, and <strong>the first source to define a given service tag wins</strong>, 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 <a href="../../dev/creating-a-service/">Services</a> for the full details on how service discovery and repositories work.</p> <p>unshackle searches entries in the order listed, and <strong>the first source to define a given service tag wins</strong>, so put local folders last if you want them to act as fallbacks rather than overrides. unshackle clones remote repositories on first use and refreshes them at most once a day. See <a href="../../dev/creating-a-service/">Creating a Service</a> for how service discovery and repositories work.</p>
<h2 id="the-filenames-key">The <code>filenames</code> key<a class="headerlink" href="#the-filenames-key" title="Permanent link">&para;</a></h2> <h2 id="the-filenames-key">The <code>filenames</code> key<a class="headerlink" href="#the-filenames-key" title="Permanent link">&para;</a></h2>
<p>Alongside <code>directories</code>, the <code>filenames</code> 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 <a href="../../reference/configuration/#filenames">Configuration Reference</a>.</p> <p>Alongside <code>directories</code>, the <code>filenames</code> 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 <a href="../../reference/configuration/#filenames">Configuration Reference</a>.</p>
<h2 id="editing-the-config-with-unshackle-cfg">Editing the config with <code>unshackle cfg</code><a class="headerlink" href="#editing-the-config-with-unshackle-cfg" title="Permanent link">&para;</a></h2> <h2 id="editing-the-config-with-unshackle-cfg">Editing the config with <code>unshackle cfg</code><a class="headerlink" href="#editing-the-config-with-unshackle-cfg" title="Permanent link">&para;</a></h2>
@@ -2155,8 +2155,8 @@ and every available key.</p>
<div class="language-console highlight"><pre><span></span><code><span id="__span-9-1"><a id="__codelineno-9-1" name="__codelineno-9-1" href="#__codelineno-9-1"></a><span class="gp">$ </span>unshackle<span class="w"> </span>cfg<span class="w"> </span>tag<span class="w"> </span>MYGRP <div class="language-console highlight"><pre><span></span><code><span id="__span-9-1"><a id="__codelineno-9-1" name="__codelineno-9-1" href="#__codelineno-9-1"></a><span class="gp">$ </span>unshackle<span class="w"> </span>cfg<span class="w"> </span>tag<span class="w"> </span>MYGRP
</span><span id="__span-9-2"><a id="__codelineno-9-2" name="__codelineno-9-2" href="#__codelineno-9-2"></a><span class="gp">$ </span>unshackle<span class="w"> </span>cfg<span class="w"> </span>cdm.default<span class="w"> </span>my_device_l3 </span><span id="__span-9-2"><a id="__codelineno-9-2" name="__codelineno-9-2" href="#__codelineno-9-2"></a><span class="gp">$ </span>unshackle<span class="w"> </span>cfg<span class="w"> </span>cdm.default<span class="w"> </span>my_device_l3
</span></code></pre></div> </span></code></pre></div>
<p>Values are parsed as Python literals where possible, so numbers, booleans, and lists work naturally, while bare text is treated as a string:</p> <p>unshackle parses the value as a Python literal, so write booleans as <code>True</code>/<code>False</code> and quote the strings inside a list (<code>"['en']"</code>). Anything that is not valid Python literal syntax is stored as a plain string:</p>
<div class="language-console highlight"><pre><span></span><code><span id="__span-10-1"><a id="__codelineno-10-1" name="__codelineno-10-1" href="#__codelineno-10-1"></a><span class="gp">$ </span>unshackle<span class="w"> </span>cfg<span class="w"> </span>update_checks<span class="w"> </span><span class="nb">false</span> <div class="language-console highlight"><pre><span></span><code><span id="__span-10-1"><a id="__codelineno-10-1" name="__codelineno-10-1" href="#__codelineno-10-1"></a><span class="gp">$ </span>unshackle<span class="w"> </span>cfg<span class="w"> </span>update_checks<span class="w"> </span>False
</span><span id="__span-10-2"><a id="__codelineno-10-2" name="__codelineno-10-2" href="#__codelineno-10-2"></a><span class="gp">$ </span>unshackle<span class="w"> </span>cfg<span class="w"> </span>vault_timeout<span class="w"> </span><span class="m">30</span> </span><span id="__span-10-2"><a id="__codelineno-10-2" name="__codelineno-10-2" href="#__codelineno-10-2"></a><span class="gp">$ </span>unshackle<span class="w"> </span>cfg<span class="w"> </span>vault_timeout<span class="w"> </span><span class="m">30</span>
</span></code></pre></div> </span></code></pre></div>
<p><strong>Remove a value</strong> with <code>--unset</code>:</p> <p><strong>Remove a value</strong> with <code>--unset</code>:</p>
@@ -2165,7 +2165,7 @@ and every available key.</p>
<p><strong>List everything</strong> currently set with <code>--list</code>:</p> <p><strong>List everything</strong> currently set with <code>--list</code>:</p>
<div class="language-console highlight"><pre><span></span><code><span id="__span-12-1"><a id="__codelineno-12-1" name="__codelineno-12-1" href="#__codelineno-12-1"></a><span class="gp">$ </span>unshackle<span class="w"> </span>cfg<span class="w"> </span>--list <div class="language-console highlight"><pre><span></span><code><span id="__span-12-1"><a id="__codelineno-12-1" name="__codelineno-12-1" href="#__codelineno-12-1"></a><span class="gp">$ </span>unshackle<span class="w"> </span>cfg<span class="w"> </span>--list
</span></code></pre></div> </span></code></pre></div>
<p>When it writes, <code>unshackle cfg</code> targets the config file that was loaded. If none exists yet, it creates <code>unshackle.yaml</code> in your OS user-config directory.</p> <p>When it writes, <code>unshackle cfg</code> targets the config file that was loaded. If none exists yet, it creates <code>unshackle.yaml</code> inside the <code>unshackle</code> package folder (search location 1), not your OS user-config directory. To keep the config outside the package, create the file at the user-config path yourself first, then <code>unshackle cfg</code> writes to it.</p>
<div class="admonition warning"> <div class="admonition warning">
<p class="admonition-title">Editing with <code>cfg</code> strips comments</p> <p class="admonition-title">Editing with <code>cfg</code> strips comments</p>
<p>Because <code>unshackle cfg</code> rewrites the whole file when it saves, any comments in <code>unshackle.yaml</code> are removed by a write. If you keep important notes as comments, edit the file by hand instead, or keep those notes elsewhere.</p> <p>Because <code>unshackle cfg</code> rewrites the whole file when it saves, any comments in <code>unshackle.yaml</code> are removed by a write. If you keep important notes as comments, edit the file by hand instead, or keep those notes elsewhere.</p>
@@ -2174,7 +2174,7 @@ and every available key.</p>
<ul> <ul>
<li>Browse the <a href="../../reference/configuration/">Configuration Reference</a> for every key and default.</li> <li>Browse the <a href="../../reference/configuration/">Configuration Reference</a> for every key and default.</li>
<li>Set up your first download in <a href="../../guide/downloading/">Downloading</a>.</li> <li>Set up your first download in <a href="../../guide/downloading/">Downloading</a>.</li>
<li>Learn how services are discovered and updated in <a href="../../dev/creating-a-service/">Services</a>.</li> <li>Learn how services are discovered and updated in <a href="../../dev/creating-a-service/">Creating a Service</a>.</li>
</ul> </ul>
+4 -4
View File
@@ -2080,8 +2080,8 @@ these entirely.</p>
</div> </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> <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 <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 a <code>binaries/</code> folder processing and DRM work. It looks for each one first in the <code>binaries/</code> folder
next to the installed package, and then falls back to your system <code>PATH</code>, so inside the installed package, and then falls back to your system <code>PATH</code>, so
installing these tools system-wide (or dropping them into that folder) both installing these tools system-wide (or dropping them into that folder) both
work.</p> work.</p>
<h3 id="required-tools">Required tools<a class="headerlink" href="#required-tools" title="Permanent link">&para;</a></h3> <h3 id="required-tools">Required tools<a class="headerlink" href="#required-tools" title="Permanent link">&para;</a></h3>
@@ -2126,7 +2126,7 @@ work.</p>
<p class="admonition-title">shaka-packager is the default decryptor</p> <p class="admonition-title">shaka-packager is the default decryptor</p>
<p>unshackle decrypts with shaka-packager unless you explicitly configure a <p>unshackle decrypts with shaka-packager unless you explicitly configure a
different decryptor. If it is missing, protected downloads will fail at the different decryptor. If it is missing, protected downloads will fail at the
decryption step. See the <a href="../configuration-file/">configuration reference</a> for the decryption step. See the <a href="../../reference/configuration/#decryption">configuration reference</a> for the
<code>decryption</code> key if you want to switch to <code>mp4decrypt</code>.</p> <code>decryption</code> key if you want to switch to <code>mp4decrypt</code>.</p>
</div> </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> <h3 id="recommended-and-optional-tools">Recommended and optional tools<a class="headerlink" href="#recommended-and-optional-tools" title="Permanent link">&para;</a></h3>
@@ -2211,7 +2211,7 @@ it depends on.</p>
<h3 id="confirm-the-command-is-available">Confirm the command is available<a class="headerlink" href="#confirm-the-command-is-available" title="Permanent link">&para;</a></h3> <h3 id="confirm-the-command-is-available">Confirm the command is available<a class="headerlink" href="#confirm-the-command-is-available" title="Permanent link">&para;</a></h3>
<div class="language-shell highlight"><pre><span></span><code><span id="__span-4-1"><a id="__codelineno-4-1" name="__codelineno-4-1" href="#__codelineno-4-1"></a>unshackle<span class="w"> </span>--help <div class="language-shell highlight"><pre><span></span><code><span id="__span-4-1"><a id="__codelineno-4-1" name="__codelineno-4-1" href="#__codelineno-4-1"></a>unshackle<span class="w"> </span>--help
</span></code></pre></div> </span></code></pre></div>
<p>This prints the banner and the list of available commands (<code>dl</code>, <code>env</code>, <code>kv</code>, <p>This prints the list of available commands (<code>dl</code>, <code>env</code>, <code>kv</code>,
<code>serve</code>, <code>wvd</code>, <code>prd</code>, <code>search</code>, <code>util</code>, <code>cfg</code>, <code>import</code>). If your shell reports <code>serve</code>, <code>wvd</code>, <code>prd</code>, <code>search</code>, <code>util</code>, <code>cfg</code>, <code>import</code>). If your shell reports
that <code>unshackle</code> is not found, the <code>uv tool</code> bin directory is probably not on that <code>unshackle</code> is not found, the <code>uv tool</code> bin directory is probably not on
your <code>PATH</code>. Run <code>uv tool update-shell</code> and open a new terminal.</p> your <code>PATH</code>. Run <code>uv tool update-shell</code> and open a new terminal.</p>
+53 -77
View File
@@ -638,10 +638,10 @@
</li> </li>
<li class="md-nav__item"> <li class="md-nav__item">
<a href="#3-add-a-service" class="md-nav__link"> <a href="#3-write-a-service" class="md-nav__link">
<span class="md-ellipsis"> <span class="md-ellipsis">
3. Add a service 3. Write a service
</span> </span>
</a> </a>
@@ -1822,10 +1822,10 @@
</li> </li>
<li class="md-nav__item"> <li class="md-nav__item">
<a href="#3-add-a-service" class="md-nav__link"> <a href="#3-write-a-service" class="md-nav__link">
<span class="md-ellipsis"> <span class="md-ellipsis">
3. Add a service 3. Write a service
</span> </span>
</a> </a>
@@ -1937,15 +1937,22 @@
<h1 id="quick-start">Quick Start<a class="headerlink" href="#quick-start" title="Permanent link">&para;</a></h1> <h1 id="quick-start">Quick Start<a class="headerlink" href="#quick-start" title="Permanent link">&para;</a></h1>
<p>This page takes you from a fresh install to your first downloaded file. You will <p>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 create the one piece of configuration unshackle insists on, supply the service
service and a CDM so it can actually fetch and decrypt media, run a basic module and CDM it needs to fetch and decrypt media, run a basic <code>unshackle dl</code>
<code>unshackle dl</code> command, and learn where the finished file lands.</p> command, and learn where the finished file lands.</p>
<div class="admonition note"> <div class="admonition note">
<p class="admonition-title">Before you start</p> <p class="admonition-title">Before you start</p>
<p>This guide assumes unshackle is already installed and on your <code>PATH</code>. If <p>This guide assumes unshackle is already installed and on your <code>PATH</code>. If
<code>unshackle --help</code> does not print a help screen, work through <code>unshackle --help</code> does not print a help screen, work through
<a href="../installation/">Installation</a> first.</p> <a href="../installation/">Installation</a> first.</p>
</div> </div>
<div class="admonition warning">
<p class="admonition-title">unshackle includes no services</p>
<p>unshackle handles manifests, DRM, downloading, and muxing. It does not include a
module for any streaming platform, so you write that part yourself
(<a href="#3-write-a-service">step 3</a>). <code>EXAMPLE</code> in this guide stands in for the tag you
give yours.</p>
</div>
<h2 id="1-check-your-environment">1. Check your environment<a class="headerlink" href="#1-check-your-environment" title="Permanent link">&para;</a></h2> <h2 id="1-check-your-environment">1. Check your environment<a class="headerlink" href="#1-check-your-environment" title="Permanent link">&para;</a></h2>
<p>unshackle drives several external tools (FFmpeg, MKVToolNix, shaka-packager, and <p>unshackle drives several external tools (FFmpeg, MKVToolNix, shaka-packager, and
others) to decrypt, repack, and mux media. Confirm they are visible before you others) to decrypt, repack, and mux media. Confirm they are visible before you
@@ -1982,11 +1989,11 @@ That means <code>output_template</code> is the one setting a first run genuinely
Everything else has a sensible default. A minimal, working config looks like this:</p> Everything else has a sensible default. A minimal, working config looks like this:</p>
<div class="language-yaml highlight"><span class="filename">unshackle.yaml</span><pre><span></span><code><span id="__span-2-1"><a id="__codelineno-2-1" name="__codelineno-2-1" href="#__codelineno-2-1"></a><span class="nt">output_template</span><span class="p">:</span> <div class="language-yaml highlight"><span class="filename">unshackle.yaml</span><pre><span></span><code><span id="__span-2-1"><a id="__codelineno-2-1" name="__codelineno-2-1" href="#__codelineno-2-1"></a><span class="nt">output_template</span><span class="p">:</span>
</span><span id="__span-2-2"><a id="__codelineno-2-2" name="__codelineno-2-2" href="#__codelineno-2-2"></a><span class="w"> </span><span class="nt">movies</span><span class="p">:</span><span class="w"> </span><span class="s">&quot;{title}</span><span class="nv"> </span><span class="s">({year})</span><span class="nv"> </span><span class="s">{quality}</span><span class="nv"> </span><span class="s">{source}&quot;</span> </span><span id="__span-2-2"><a id="__codelineno-2-2" name="__codelineno-2-2" href="#__codelineno-2-2"></a><span class="w"> </span><span class="nt">movies</span><span class="p">:</span><span class="w"> </span><span class="s">&quot;{title}</span><span class="nv"> </span><span class="s">({year})</span><span class="nv"> </span><span class="s">{quality}</span><span class="nv"> </span><span class="s">{source}&quot;</span>
</span><span id="__span-2-3"><a id="__codelineno-2-3" name="__codelineno-2-3" href="#__codelineno-2-3"></a><span class="w"> </span><span class="nt">series</span><span class="p">:</span><span class="w"> </span><span class="s">&quot;{title}</span><span class="nv"> </span><span class="s">S{season}E{episode}</span><span class="nv"> </span><span class="s">{episode_name}</span><span class="nv"> </span><span class="s">{quality}</span><span class="nv"> </span><span class="s">{source}&quot;</span> </span><span id="__span-2-3"><a id="__codelineno-2-3" name="__codelineno-2-3" href="#__codelineno-2-3"></a><span class="w"> </span><span class="nt">series</span><span class="p">:</span><span class="w"> </span><span class="s">&quot;{title}</span><span class="nv"> </span><span class="s">{season_episode}</span><span class="nv"> </span><span class="s">{episode_name?}</span><span class="nv"> </span><span class="s">{quality}</span><span class="nv"> </span><span class="s">{source}&quot;</span>
</span></code></pre></div> </span></code></pre></div>
<p>Each <code>{variable}</code> is filled in from the title and the tracks you downloaded. The <p>Each <code>{variable}</code> is filled in from the title and the tracks you downloaded. The
full set of valid variables, including <code>resolution</code>, <code>video</code>, <code>audio</code>, <code>hdr</code>, full set of valid variables, including <code>resolution</code>, <code>video</code>, <code>audio</code>, <code>hdr</code>,
<code>edition</code>, <code>tag</code>, and more, is documented in <a href="../configuration-file/">Configuration</a>.</p> <code>edition</code>, <code>tag</code>, and more, is documented in <a href="../../guide/output-and-naming/">Output and Naming</a>.</p>
<div class="admonition note"> <div class="admonition note">
<p class="admonition-title">Spaces or dots?</p> <p class="admonition-title">Spaces or dots?</p>
<p>unshackle auto-detects your naming style from the template: if the separators <p>unshackle auto-detects your naming style from the template: if the separators
@@ -2001,59 +2008,28 @@ style you want the filenames to look.</p>
rewrites the file and <strong>removes any comments</strong> it contained. If you keep notes rewrites the file and <strong>removes any comments</strong> it contained. If you keep notes
in your config, edit the file by hand instead.</p> in your config, edit the file by hand instead.</p>
</div> </div>
<h2 id="3-add-a-service">3. Add a service<a class="headerlink" href="#3-add-a-service" title="Permanent link">&para;</a></h2> <h2 id="3-write-a-service">3. Write a service<a class="headerlink" href="#3-write-a-service" title="Permanent link">&para;</a></h2>
<p>The service tag you pass to <code>dl</code> (like <code>EXAMPLE</code>) maps to a <strong>service module</strong>, a small <p>The service tag you pass to <code>dl</code> (like <code>EXAMPLE</code>) maps to a <strong>service module</strong>, the
plugin that knows how to talk to one streaming platform. unshackle ships without plugin that talks to one streaming platform. unshackle includes none, so you write
any bundled services, so you add the one(s) you want.</p> the one you need. <a href="../../dev/creating-a-service/">Creating a Service</a> covers how.</p>
<p>Services live under the <code>directories.services</code> path (run <code>unshackle env info</code> to <p>Put the finished module in your <code>directories.services</code> folder (<code>unshackle env info</code>
see where that is). unshackle discovers them by looking for <code>*/__init__.py</code>: the shows the path). The tag then works with <code>dl</code>, <code>search</code>, and the other service
folder name becomes the <strong>service tag</strong>, and the folder must contain a class with commands.</p>
that exact same name.</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">Local folder</label><label for="__tabbed_1_2">Git repository</label></div>
<div class="tabbed-content">
<div class="tabbed-block">
<p>Drop a service folder into your services directory. A service tagged <code>EXAMPLE</code>
lives at:</p>
<div class="language-text highlight"><pre><span></span><code><span id="__span-3-1"><a id="__codelineno-3-1" name="__codelineno-3-1" href="#__codelineno-3-1"></a>&lt;services&gt;/EXAMPLE/__init__.py # defines a class named EXAMPLE
</span></code></pre></div>
<p>Once the folder is in place, the tag <code>EXAMPLE</code> is immediately available to <code>dl</code>,
<code>search</code>, and the other service-aware commands.</p>
</div>
<div class="tabbed-block">
<p><code>directories.services</code> may also list git repositories. unshackle clones them
on first use and keeps them up to date:</p>
<div class="language-yaml highlight"><span class="filename">unshackle.yaml</span><pre><span></span><code><span id="__span-4-1"><a id="__codelineno-4-1" name="__codelineno-4-1" href="#__codelineno-4-1"></a><span class="nt">directories</span><span class="p">:</span>
</span><span id="__span-4-2"><a id="__codelineno-4-2" name="__codelineno-4-2" href="#__codelineno-4-2"></a><span class="w"> </span><span class="nt">services</span><span class="p">:</span>
</span><span id="__span-4-3"><a id="__codelineno-4-3" name="__codelineno-4-3" href="#__codelineno-4-3"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">owner/unshackle-services</span><span class="w"> </span><span class="c1"># a GitHub owner/repo shorthand</span>
</span><span id="__span-4-4"><a id="__codelineno-4-4" name="__codelineno-4-4" href="#__codelineno-4-4"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">/path/to/local/services</span><span class="w"> </span><span class="c1"># local folders still work too</span>
</span></code></pre></div>
<p>Force a refresh of every configured service repo at any time with:</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>unshackle<span class="w"> </span>util<span class="w"> </span>refresh-services
</span></code></pre></div>
</div>
</div>
</div>
<div class="admonition info">
<p class="admonition-title">Where to get services</p>
<p>Service modules are kept separate from the core project. Ask in the community
<a href="https://discord.gg/mHYyPaCbFK">Discord</a> for where to find the service you
need. The core repository deliberately does not host them.</p>
</div>
<h2 id="4-add-a-cdm-for-drm">4. Add a CDM for DRM<a class="headerlink" href="#4-add-a-cdm-for-drm" title="Permanent link">&para;</a></h2> <h2 id="4-add-a-cdm-for-drm">4. Add a CDM for DRM<a class="headerlink" href="#4-add-a-cdm-for-drm" title="Permanent link">&para;</a></h2>
<p>Most streaming content is encrypted. To fetch decryption keys, unshackle needs a <p>Most streaming content is encrypted. To fetch decryption keys, unshackle needs a
<strong>CDM</strong>, a Widevine device (<code>.wvd</code>) or a PlayReady device (<code>.prd</code>). Register a <strong>CDM</strong>, a Widevine device (<code>.wvd</code>) or a PlayReady device (<code>.prd</code>). Register a
Widevine device you already have with:</p> Widevine device you already have with:</p>
<div class="language-shell highlight"><pre><span></span><code><span id="__span-6-1"><a id="__codelineno-6-1" name="__codelineno-6-1" href="#__codelineno-6-1"></a>unshackle<span class="w"> </span>wvd<span class="w"> </span>add<span class="w"> </span>/path/to/device.wvd <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>wvd<span class="w"> </span>add<span class="w"> </span>/path/to/device.wvd
</span></code></pre></div> </span></code></pre></div>
<p>This validates the file and moves it into your WVDs directory. Then point services <p>This validates the file and moves it into your WVDs directory. Then point services
at it in your config. The <code>cdm</code> map is keyed by service tag, with a <code>default</code> that at it in your config. The <code>cdm</code> map is keyed by service tag, with a <code>default</code> that
covers everything else:</p> covers everything else:</p>
<div class="language-yaml highlight"><span class="filename">unshackle.yaml</span><pre><span></span><code><span id="__span-7-1"><a id="__codelineno-7-1" name="__codelineno-7-1" href="#__codelineno-7-1"></a><span class="nt">cdm</span><span class="p">:</span> <div class="language-yaml highlight"><span class="filename">unshackle.yaml</span><pre><span></span><code><span id="__span-4-1"><a id="__codelineno-4-1" name="__codelineno-4-1" href="#__codelineno-4-1"></a><span class="nt">cdm</span><span class="p">:</span>
</span><span id="__span-7-2"><a id="__codelineno-7-2" name="__codelineno-7-2" href="#__codelineno-7-2"></a><span class="w"> </span><span class="nt">default</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">my_device</span><span class="w"> </span><span class="c1"># the .wvd file&#39;s name, without the extension</span> </span><span id="__span-4-2"><a id="__codelineno-4-2" name="__codelineno-4-2" href="#__codelineno-4-2"></a><span class="w"> </span><span class="nt">default</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">my_device</span><span class="w"> </span><span class="c1"># the .wvd file&#39;s name, without the extension</span>
</span><span id="__span-7-3"><a id="__codelineno-7-3" name="__codelineno-7-3" href="#__codelineno-7-3"></a><span class="w"> </span><span class="nt">EXAMPLE</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">my_other_device</span><span class="w"> </span><span class="c1"># override for a specific service</span> </span><span id="__span-4-3"><a id="__codelineno-4-3" name="__codelineno-4-3" href="#__codelineno-4-3"></a><span class="w"> </span><span class="nt">EXAMPLE</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">my_other_device</span><span class="w"> </span><span class="c1"># override for a specific service</span>
</span></code></pre></div> </span></code></pre></div>
<p>PlayReady works the same way with <code>.prd</code> files created and managed by the <p>PlayReady works the same way with <code>.prd</code> files created and managed by the
<a href="../configuration-file/"><code>prd</code></a> command. If a title is DRM-free, no CDM is needed.</p> <a href="../../guide/cli-reference/#prd"><code>prd</code></a> command. If a title is DRM-free, no CDM is needed.</p>
<div class="admonition tip"> <div class="admonition tip">
<p class="admonition-title">Tip</p> <p class="admonition-title">Tip</p>
<p>Run <code>unshackle wvd parse my_device</code> to inspect a device's security level and <p>Run <code>unshackle wvd parse my_device</code> to inspect a device's security level and
@@ -2071,8 +2047,8 @@ contents, and <code>unshackle env info</code> to confirm where WVDs and PRDs are
</li> </li>
<li> <li>
<p><strong>Credentials</strong>: store a username and password per service in your config:</p> <p><strong>Credentials</strong>: store a username and password per service in your config:</p>
<div class="language-yaml highlight"><span class="filename">unshackle.yaml</span><pre><span></span><code><span id="__span-8-1"><a id="__codelineno-8-1" name="__codelineno-8-1" href="#__codelineno-8-1"></a><span class="nt">credentials</span><span class="p">:</span> <div class="language-yaml highlight"><span class="filename">unshackle.yaml</span><pre><span></span><code><span id="__span-5-1"><a id="__codelineno-5-1" name="__codelineno-5-1" href="#__codelineno-5-1"></a><span class="nt">credentials</span><span class="p">:</span>
</span><span id="__span-8-2"><a id="__codelineno-8-2" name="__codelineno-8-2" href="#__codelineno-8-2"></a><span class="w"> </span><span class="nt">EXAMPLE</span><span class="p">:</span><span class="w"> </span><span class="s">&quot;email@example.com:your-password&quot;</span> </span><span id="__span-5-2"><a id="__codelineno-5-2" name="__codelineno-5-2" href="#__codelineno-5-2"></a><span class="w"> </span><span class="nt">EXAMPLE</span><span class="p">:</span><span class="w"> </span><span class="s">&quot;email@example.com:your-password&quot;</span>
</span></code></pre></div> </span></code></pre></div>
</li> </li>
</ul> </ul>
@@ -2082,23 +2058,23 @@ depends on the service module.</p>
<h2 id="6-find-a-title-optional">6. Find a title (optional)<a class="headerlink" href="#6-find-a-title-optional" title="Permanent link">&para;</a></h2> <h2 id="6-find-a-title-optional">6. Find a title (optional)<a class="headerlink" href="#6-find-a-title-optional" title="Permanent link">&para;</a></h2>
<p>If you have a URL or ID already, skip this. Otherwise, search the service for a <p>If you have a URL or ID already, skip this. Otherwise, search the service for a
title and note the <code>id</code> it prints, since that is what you feed to <code>dl</code>:</p> title and note the <code>id</code> it prints, since that is what you feed to <code>dl</code>:</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>unshackle<span class="w"> </span>search<span class="w"> </span>EXAMPLE<span class="w"> </span><span class="s2">&quot;My Show&quot;</span> <div class="language-shell highlight"><pre><span></span><code><span id="__span-6-1"><a id="__codelineno-6-1" name="__codelineno-6-1" href="#__codelineno-6-1"></a>unshackle<span class="w"> </span>search<span class="w"> </span>EXAMPLE<span class="w"> </span><span class="s2">&quot;My Show&quot;</span>
</span></code></pre></div> </span></code></pre></div>
<p>You can also list what a service exposes for a given title without downloading:</p> <p>You can also list what a service exposes for a given title without downloading:</p>
<div class="language-shell highlight"><pre><span></span><code><span id="__span-10-1"><a id="__codelineno-10-1" name="__codelineno-10-1" href="#__codelineno-10-1"></a>unshackle<span class="w"> </span>dl<span class="w"> </span>--list-titles<span class="w"> </span>EXAMPLE<span class="w"> </span><span class="m">81234567</span><span class="w"> </span><span class="c1"># show seasons/episodes</span> <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>unshackle<span class="w"> </span>dl<span class="w"> </span>--list-titles<span class="w"> </span>EXAMPLE<span class="w"> </span><span class="m">81234567</span><span class="w"> </span><span class="c1"># show seasons/episodes</span>
</span><span id="__span-10-2"><a id="__codelineno-10-2" name="__codelineno-10-2" href="#__codelineno-10-2"></a>unshackle<span class="w"> </span>dl<span class="w"> </span>--list<span class="w"> </span>EXAMPLE<span class="w"> </span><span class="m">81234567</span><span class="w"> </span><span class="c1"># show available tracks</span> </span><span id="__span-7-2"><a id="__codelineno-7-2" name="__codelineno-7-2" href="#__codelineno-7-2"></a>unshackle<span class="w"> </span>dl<span class="w"> </span>--list<span class="w"> </span>EXAMPLE<span class="w"> </span><span class="m">81234567</span><span class="w"> </span><span class="c1"># show available tracks</span>
</span></code></pre></div> </span></code></pre></div>
<h2 id="7-run-your-first-download">7. Run your first download<a class="headerlink" href="#7-run-your-first-download" title="Permanent link">&para;</a></h2> <h2 id="7-run-your-first-download">7. Run your first download<a class="headerlink" href="#7-run-your-first-download" title="Permanent link">&para;</a></h2>
<p>A download always has three parts:</p> <p>A download always has three parts:</p>
<div class="language-text highlight"><pre><span></span><code><span id="__span-11-1"><a id="__codelineno-11-1" name="__codelineno-11-1" href="#__codelineno-11-1"></a>unshackle dl &lt;FLAGS&gt; &lt;SERVICE-TAG&gt; &lt;TITLE&gt; <div class="language-text 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 dl &lt;FLAGS&gt; &lt;SERVICE-TAG&gt; &lt;TITLE&gt;
</span></code></pre></div> </span></code></pre></div>
<ul> <ul>
<li><strong><code>dl</code></strong> carries every quality, language, track, and output flag.</li> <li><strong><code>dl</code></strong> carries every quality, language, track, and output flag.</li>
<li><strong><code>&lt;SERVICE-TAG&gt;</code></strong> picks which service to talk to (e.g. <code>EXAMPLE</code>).</li> <li><strong><code>&lt;SERVICE-TAG&gt;</code></strong> picks which service to talk to (e.g. <code>EXAMPLE</code>).</li>
<li><strong><code>&lt;TITLE&gt;</code></strong> is the URL, ID, or slug the service understands.</li> <li><strong><code>&lt;TITLE&gt;</code></strong> is the URL, ID, or slug the service understands.</li>
</ul> </ul>
<p>A good first command asks for 1080p with English audio and subtitles:</p> <p>A good first command asks for 1080p with English audio:</p>
<div class="language-shell highlight"><span class="filename">Your first download</span><pre><span></span><code><span id="__span-12-1"><a id="__codelineno-12-1" name="__codelineno-12-1" href="#__codelineno-12-1"></a>unshackle<span class="w"> </span>dl<span class="w"> </span>-q<span class="w"> </span><span class="m">1080</span><span class="w"> </span>-l<span class="w"> </span>en<span class="w"> </span>EXAMPLE<span class="w"> </span><span class="m">81234567</span> <div class="language-shell highlight"><span class="filename">Your first download</span><pre><span></span><code><span id="__span-9-1"><a id="__codelineno-9-1" name="__codelineno-9-1" href="#__codelineno-9-1"></a>unshackle<span class="w"> </span>dl<span class="w"> </span>-q<span class="w"> </span><span class="m">1080</span><span class="w"> </span>-l<span class="w"> </span>en<span class="w"> </span>EXAMPLE<span class="w"> </span><span class="m">81234567</span>
</span></code></pre></div> </span></code></pre></div>
<p>unshackle will fetch the title, select the tracks matching your flags, acquire <p>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.</p> keys through your CDM (and any key vaults), then decrypt, mux, and tag the result.</p>
@@ -2117,7 +2093,7 @@ keys through your CDM (and any key vaults), then decrypt, mux, and tag the resul
</tr> </tr>
<tr> <tr>
<td><code>-l</code>, <code>--lang</code></td> <td><code>-l</code>, <code>--lang</code></td>
<td>Language(s) for video and audio, e.g. <code>-l en</code> or <code>-l orig,en</code>. <code>orig</code> = the title's original language.</td> <td>Language(s) for video and audio, e.g. <code>-l en</code> or <code>-l orig,en</code>. <code>orig</code> = the title's original language. Defaults to <code>orig</code>.</td>
</tr> </tr>
<tr> <tr>
<td><code>-sl</code>, <code>--s-lang</code></td> <td><code>-sl</code>, <code>--s-lang</code></td>
@@ -2147,34 +2123,34 @@ keys through your CDM (and any key vaults), then decrypt, mux, and tag the resul
</table> </table>
<div class="admonition example"> <div class="admonition example">
<p class="admonition-title">A few realistic variations</p> <p class="admonition-title">A few realistic variations</p>
<div class="language-shell highlight"><pre><span></span><code><span id="__span-13-1"><a id="__codelineno-13-1" name="__codelineno-13-1" href="#__codelineno-13-1"></a><span class="c1"># A whole first season in the best available quality</span> <div class="language-shell highlight"><pre><span></span><code><span id="__span-10-1"><a id="__codelineno-10-1" name="__codelineno-10-1" href="#__codelineno-10-1"></a><span class="c1"># A whole first season in the best available quality</span>
</span><span id="__span-13-2"><a id="__codelineno-13-2" name="__codelineno-13-2" href="#__codelineno-13-2"></a>unshackle<span class="w"> </span>dl<span class="w"> </span>-w<span class="w"> </span>S01<span class="w"> </span>EXAMPLE<span class="w"> </span><span class="m">81234567</span> </span><span id="__span-10-2"><a id="__codelineno-10-2" name="__codelineno-10-2" href="#__codelineno-10-2"></a>unshackle<span class="w"> </span>dl<span class="w"> </span>-w<span class="w"> </span>S01<span class="w"> </span>EXAMPLE<span class="w"> </span><span class="m">81234567</span>
</span><span id="__span-13-3"><a id="__codelineno-13-3" name="__codelineno-13-3" href="#__codelineno-13-3"></a> </span><span id="__span-10-3"><a id="__codelineno-10-3" name="__codelineno-10-3" href="#__codelineno-10-3"></a>
</span><span id="__span-13-4"><a id="__codelineno-13-4" name="__codelineno-13-4" href="#__codelineno-13-4"></a><span class="c1"># 2160p HDR10 with the original-language audio plus English subtitles</span> </span><span id="__span-10-4"><a id="__codelineno-10-4" name="__codelineno-10-4" href="#__codelineno-10-4"></a><span class="c1"># 2160p HDR10 with the original-language audio plus English subtitles</span>
</span><span id="__span-13-5"><a id="__codelineno-13-5" name="__codelineno-13-5" href="#__codelineno-13-5"></a>unshackle<span class="w"> </span>dl<span class="w"> </span>-q<span class="w"> </span><span class="m">2160</span><span class="w"> </span>-r<span class="w"> </span>HDR10<span class="w"> </span>-l<span class="w"> </span>orig<span class="w"> </span>-sl<span class="w"> </span>en<span class="w"> </span>EXAMPLE<span class="w"> </span><span class="m">81234567</span> </span><span id="__span-10-5"><a id="__codelineno-10-5" name="__codelineno-10-5" href="#__codelineno-10-5"></a>unshackle<span class="w"> </span>dl<span class="w"> </span>-q<span class="w"> </span><span class="m">2160</span><span class="w"> </span>-r<span class="w"> </span>HDR10<span class="w"> </span>-l<span class="w"> </span>orig<span class="w"> </span>-sl<span class="w"> </span>en<span class="w"> </span>EXAMPLE<span class="w"> </span><span class="m">81234567</span>
</span><span id="__span-13-6"><a id="__codelineno-13-6" name="__codelineno-13-6" href="#__codelineno-13-6"></a> </span><span id="__span-10-6"><a id="__codelineno-10-6" name="__codelineno-10-6" href="#__codelineno-10-6"></a>
</span><span id="__span-13-7"><a id="__codelineno-13-7" name="__codelineno-13-7" href="#__codelineno-13-7"></a><span class="c1"># Just the newest episode of an ongoing show</span> </span><span id="__span-10-7"><a id="__codelineno-10-7" name="__codelineno-10-7" href="#__codelineno-10-7"></a><span class="c1"># Just the newest episode of an ongoing show</span>
</span><span id="__span-13-8"><a id="__codelineno-13-8" name="__codelineno-13-8" href="#__codelineno-13-8"></a>unshackle<span class="w"> </span>dl<span class="w"> </span>--latest-episode<span class="w"> </span>EXAMPLE<span class="w"> </span><span class="m">81234567</span> </span><span id="__span-10-8"><a id="__codelineno-10-8" name="__codelineno-10-8" href="#__codelineno-10-8"></a>unshackle<span class="w"> </span>dl<span class="w"> </span>--latest-episode<span class="w"> </span>EXAMPLE<span class="w"> </span><span class="m">81234567</span>
</span></code></pre></div> </span></code></pre></div>
</div> </div>
<p>See <a href="../../guide/downloading/">Downloading</a> for the complete flag reference, including <p>See <a href="../../guide/downloading/">Downloading</a> for the complete flag reference, including
codec, bitrate, channel-layout, and track-type selection.</p> codec, bitrate, channel-layout, and track-type selection.</p>
<h2 id="8-where-the-output-lands">8. Where the output lands<a class="headerlink" href="#8-where-the-output-lands" title="Permanent link">&para;</a></h2> <h2 id="8-where-the-output-lands">8. Where the output lands<a class="headerlink" href="#8-where-the-output-lands" title="Permanent link">&para;</a></h2>
<p>By default, finished files are written to the <code>downloads</code> directory <p>By default, unshackle writes finished files to the <code>downloads</code> directory
(<code>unshackle env info</code> shows its exact path; the built-in default is a <code>downloads</code> (<code>unshackle env info</code> shows its exact path; the built-in default is a <code>downloads</code>
folder alongside the project). Override it per run with <code>-o</code>:</p> folder one level above the installed <code>unshackle</code> package). Override it per run with <code>-o</code>:</p>
<div class="language-shell highlight"><pre><span></span><code><span id="__span-14-1"><a id="__codelineno-14-1" name="__codelineno-14-1" href="#__codelineno-14-1"></a>unshackle<span class="w"> </span>dl<span class="w"> </span>-q<span class="w"> </span><span class="m">1080</span><span class="w"> </span>-o<span class="w"> </span>/mnt/media/incoming<span class="w"> </span>EXAMPLE<span class="w"> </span><span class="m">81234567</span> <div class="language-shell highlight"><pre><span></span><code><span id="__span-11-1"><a id="__codelineno-11-1" name="__codelineno-11-1" href="#__codelineno-11-1"></a>unshackle<span class="w"> </span>dl<span class="w"> </span>-q<span class="w"> </span><span class="m">1080</span><span class="w"> </span>-o<span class="w"> </span>/mnt/media/incoming<span class="w"> </span>EXAMPLE<span class="w"> </span><span class="m">81234567</span>
</span></code></pre></div> </span></code></pre></div>
<ul> <ul>
<li><strong>Movies</strong> are written as a single <code>.mkv</code> file named from your <code>movies</code> template.</li> <li>unshackle writes <strong>movies</strong> as a single <code>.mkv</code> file named from your <code>movies</code> template.</li>
<li><strong>TV episodes</strong> are grouped into a per-show / per-season folder (from your <li><strong>TV episodes</strong> are grouped into a per-show / per-season folder (from your
<code>series</code> template) unless you pass <code>--no-folder</code>.</li> <code>series</code> template) unless you pass <code>--no-folder</code>.</li>
<li>The filename is built from your <code>output_template</code>, and IMDb/TMDB IDs are added to <li>unshackle builds the filename from your <code>output_template</code> and adds IMDb/TMDB IDs to
the file's metadata tags when available.</li> the file's metadata tags when available.</li>
</ul> </ul>
<p>To change the default output location permanently, set it in your config:</p> <p>To change the default output location permanently, set it in your config:</p>
<div class="language-yaml highlight"><span class="filename">unshackle.yaml</span><pre><span></span><code><span id="__span-15-1"><a id="__codelineno-15-1" name="__codelineno-15-1" href="#__codelineno-15-1"></a><span class="nt">directories</span><span class="p">:</span> <div class="language-yaml highlight"><span class="filename">unshackle.yaml</span><pre><span></span><code><span id="__span-12-1"><a id="__codelineno-12-1" name="__codelineno-12-1" href="#__codelineno-12-1"></a><span class="nt">directories</span><span class="p">:</span>
</span><span id="__span-15-2"><a id="__codelineno-15-2" name="__codelineno-15-2" href="#__codelineno-15-2"></a><span class="w"> </span><span class="nt">downloads</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">/mnt/media/incoming</span> </span><span id="__span-12-2"><a id="__codelineno-12-2" name="__codelineno-12-2" href="#__codelineno-12-2"></a><span class="w"> </span><span class="nt">downloads</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">/mnt/media/incoming</span>
</span></code></pre></div> </span></code></pre></div>
<h2 id="where-to-go-next">Where to go next<a class="headerlink" href="#where-to-go-next" title="Permanent link">&para;</a></h2> <h2 id="where-to-go-next">Where to go next<a class="headerlink" href="#where-to-go-next" title="Permanent link">&para;</a></h2>
<ul> <ul>
@@ -2188,7 +2164,7 @@ folder alongside the project). Override it per run with <code>-o</code>:</p>
<div class="admonition tip"> <div class="admonition tip">
<p class="admonition-title">You are never far from help</p> <p class="admonition-title">You are never far from help</p>
<p><code>unshackle --help</code>, <code>unshackle dl --help</code>, and <code>unshackle &lt;command&gt; --help</code> <p><code>unshackle --help</code>, <code>unshackle dl --help</code>, and <code>unshackle &lt;command&gt; --help</code>
list every option with its default. When in doubt, add <code>--list</code> to a <code>dl</code> list every option. When in doubt, add <code>--list</code> to a <code>dl</code>
command to preview what it would do before it downloads anything.</p> command to preview what it would do before it downloads anything.</p>
</div> </div>
+22 -18
View File
@@ -2540,7 +2540,7 @@
streaming service, selects exactly the tracks you asked for, acquires and applies streaming service, selects exactly the tracks you asked for, acquires and applies
decryption keys, and muxes everything into a finished Matroska file. The flags below decryption keys, and muxes everything into a finished Matroska file. The flags below
cover quality and codec selection, language and subtitle handling, episode ranges, and cover quality and codec selection, language and subtitle handling, episode ranges, and
the download flow itself, with examples throughout.</p> the download flow itself.</p>
<div class="admonition note"> <div class="admonition note">
<p class="admonition-title">Where the full flag list lives</p> <p class="admonition-title">Where the full flag list lives</p>
<p>This page covers the flags you will use most and explains how they interact. It is <p>This page covers the flags you will use most and explains how they interact. It is
@@ -2593,8 +2593,9 @@ helps explain why, for example, <code>--list</code> stops early and why keys are
<li><strong>Post-process</strong>: extract closed captions, convert subtitles, repack, mux with <li><strong>Post-process</strong>: extract closed captions, convert subtitles, repack, mux with
<code>mkvmerge</code>, and move the finished file to your downloads directory.</li> <code>mkvmerge</code>, and move the finished file to your downloads directory.</li>
</ol> </ol>
<p><code>--list</code> and <code>--list-titles</code> stop after selection/filtering and print what <em>would</em> be <p><code>--list</code> prints the tracks a title exposes and stops before selection. <code>--list-titles</code>
downloaded. <code>--skip-dl</code> runs the license step but skips the actual segment download.</p> prints every title the service returned and stops before <code>--wanted</code>/<code>--latest-episode</code>
filtering. <code>--skip-dl</code> runs the license step but skips the actual segment download.</p>
<h2 id="choosing-quality">Choosing quality<a class="headerlink" href="#choosing-quality" title="Permanent link">&para;</a></h2> <h2 id="choosing-quality">Choosing quality<a class="headerlink" href="#choosing-quality" title="Permanent link">&para;</a></h2>
<h3 id="resolution">Resolution<a class="headerlink" href="#resolution" title="Permanent link">&para;</a></h3> <h3 id="resolution">Resolution<a class="headerlink" href="#resolution" title="Permanent link">&para;</a></h3>
<p><code>-q</code> / <code>--quality</code> takes one or more target resolutions (heights) as a comma-separated <p><code>-q</code> / <code>--quality</code> takes one or more target resolutions (heights) as a comma-separated
@@ -2714,9 +2715,11 @@ either enum <strong>names</strong> or their <strong>values</strong>, comma-separ
<div class="admonition warning"> <div class="admonition warning">
<p class="admonition-title">HYBRID requires dovi_tool</p> <p class="admonition-title">HYBRID requires dovi_tool</p>
<p><code>-r HYBRID</code> produces a single hybrid stream by injecting the Dolby Vision RPU <p><code>-r HYBRID</code> produces a single hybrid stream by injecting the Dolby Vision RPU
metadata onto an HDR10/HDR10+ base layer using <strong>dovi_tool</strong>. It requires the metadata onto an HDR10/HDR10+ base layer using <strong>dovi_tool</strong>.
<code>dovi_tool</code> binary on your PATH and needs both an HDR10(+) <em>and</em> a DV track to be It requires the <code>dovi_tool</code> binary, resolved from unshackle's <code>binaries/</code> folder or
available, otherwise the title fails (unless <code>--best-available</code> lets it fall back). your <code>PATH</code>. The normal case is a DV track plus an HDR10 or HDR10+ base. With HDR10+
and no DV, unshackle converts the HDR10+ metadata to DV instead, which also needs
<code>hdr10plus_tool</code>. With no DV and no HDR10+, the title fails.
When HDR10+ is present it is preferred over HDR10 as the base layer.</p> When HDR10+ is present it is preferred over HDR10 as the base layer.</p>
<p>To keep an HDR10+ deliverable <em>alongside</em> the hybrid, request both ranges: <p>To keep an HDR10+ deliverable <em>alongside</em> the hybrid, request both ranges:
<code>-r HYBRID,HDR10P</code>. <code>-r HYBRID</code> on its own muxes only the merged hybrid.</p> <code>-r HYBRID,HDR10P</code>. <code>-r HYBRID</code> on its own muxes only the merged hybrid.</p>
@@ -2760,8 +2763,8 @@ pair. Pick one form.</p>
<strong>peak</strong> or <strong>nominal</strong> bandwidth that is far from the stream's real average. This matters <strong>peak</strong> or <strong>nominal</strong> bandwidth that is far from the stream's real average. This matters
because a track's bitrate drives the track listing, the sort order, <em>and</em> the because a track's bitrate drives the track listing, the sort order, <em>and</em> the
<code>--vbitrate</code>/<code>--vbitrate-range</code> selection above. A bogus declared value therefore makes <code>--vbitrate</code>/<code>--vbitrate-range</code> selection above. A bogus declared value therefore makes
unshackle pick the wrong track. These flags remove that risk by probing the actual media unshackle pick the wrong track. These flags probe the actual media size to compute a true
size to compute a true bitrate for the top renditions, overriding the manifest value:</p> bitrate for the top renditions, overriding the manifest value:</p>
<ul> <ul>
<li><code>-rvb</code> / <code>--real-video-bitrate</code>: probe real video bitrates (per codec/range).</li> <li><code>-rvb</code> / <code>--real-video-bitrate</code>: probe real video bitrates (per codec/range).</li>
<li><code>-rab</code> / <code>--real-audio-bitrate</code>: probe real audio bitrates (per codec/channels/ <li><code>-rab</code> / <code>--real-audio-bitrate</code>: probe real audio bitrates (per codec/channels/
@@ -2777,12 +2780,13 @@ That is the real <em>delivered</em> size, not an over-report or a bug.</p>
</div> </div>
<div class="admonition tip"> <div class="admonition tip">
<p class="admonition-title">Why not every rendition is probed</p> <p class="admonition-title">Why not every rendition is probed</p>
<p>Probing does not touch every rendition. Only the top rendition of each quality tier is <p>Probing does not touch every rendition. Only the five highest declared-bitrate
probed in parallel (video grouped by codec+range, audio by codec+channels+language), renditions of each quality tier are probed in parallel (video grouped by codec and
and the pass then reaches downward only as far as it must to keep the ranking correct. range, audio by codec, channels, language, and descriptive flag), and unshackle
This keeps probing fast even when a service exposes dozens of renditions. Tracks whose extends a group downward while a lower unprobed rendition could still outrank a
duration can't be determined fall back to <code>ffprobe</code>, and a probe failure is non-fatal: probed one. This keeps probing fast even when a service exposes dozens of renditions.
the manifest value is simply left in place.</p> Tracks whose duration can't be determined fall back to <code>ffprobe</code>, and a probe failure
is non-fatal: the manifest value is simply left in place.</p>
</div> </div>
<h2 id="audio-codec-channels-and-atmos">Audio codec, channels, and Atmos<a class="headerlink" href="#audio-codec-channels-and-atmos" title="Permanent link">&para;</a></h2> <h2 id="audio-codec-channels-and-atmos">Audio codec, channels, and Atmos<a class="headerlink" href="#audio-codec-channels-and-atmos" title="Permanent link">&para;</a></h2>
<h3 id="codec_1">Codec<a class="headerlink" href="#codec_1" title="Permanent link">&para;</a></h3> <h3 id="codec_1">Codec<a class="headerlink" href="#codec_1" title="Permanent link">&para;</a></h3>
@@ -2991,7 +2995,7 @@ with <code>-</code> to exclude it.</p>
</tr> </tr>
<tr> <tr>
<td><code>--list-titles</code></td> <td><code>--list-titles</code></td>
<td>List the titles that would be downloaded, then stop.</td> <td>List every title the service returned, then stop. <code>-w</code>/<code>--latest-episode</code> are not applied to this listing.</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
@@ -3043,11 +3047,11 @@ are always kept.</p>
<tbody> <tbody>
<tr> <tr>
<td><code>--list</code></td> <td><code>--list</code></td>
<td>List the available tracks and which would be selected, then stop. No download.</td> <td>List the tracks the service exposes for each title, then stop. No selection, no download.</td>
</tr> </tr>
<tr> <tr>
<td><code>--list-titles</code></td> <td><code>--list-titles</code></td>
<td>List the titles (episodes) that would be downloaded, then stop.</td> <td>List every title the service returned, then stop. <code>-w</code>/<code>--latest-episode</code> are not applied to this listing.</td>
</tr> </tr>
<tr> <tr>
<td><code>--skip-dl</code></td> <td><code>--skip-dl</code></td>
@@ -3091,7 +3095,7 @@ flags change how the output is assembled:</p>
</tr> </tr>
<tr> <tr>
<td><code>--merge-video</code></td> <td><code>--merge-video</code></td>
<td>Mux all selected video tracks into one file.</td> <td>Mux video tracks that share a height, range, and codec into one file, so only language varies inside a file.</td>
<td>config <code>muxing.merge_video</code> (off)</td> <td>config <code>muxing.merge_video</code> (off)</td>
</tr> </tr>
</tbody> </tbody>
+10 -8
View File
@@ -1777,17 +1777,19 @@
media from streaming manifests, handles the DRM, and muxes everything into clean, media from streaming manifests, handles the DRM, and muxes everything into clean,
well-tagged files, all driven from a single command-line tool, or served over a well-tagged files, all driven from a single command-line tool, or served over a
REST API for automation.</p> REST API for automation.</p>
<p>It is a fork of <a href="https://github.com/devine-dl/devine">Devine</a> with first-class <p>It is a fork of <a href="https://github.com/devine-dl/devine">Devine</a> with DASH, HLS, and
DASH, HLS, and Smooth Streaming (ISM) parsing, both <strong>Widevine</strong> and <strong>PlayReady</strong> Smooth Streaming (ISM) parsing, both <strong>Widevine</strong> and <strong>PlayReady</strong> DRM support,
DRM support, and a built-in HTTP server.</p> and a built-in HTTP server.</p>
<div class="admonition warning"> <div class="admonition warning">
<p class="admonition-title">Use responsibly</p> <p class="admonition-title">Use responsibly</p>
<p>unshackle is licensed under <a href="https://github.com/unshackle-dl/unshackle/blob/master/LICENSE">GPL-3.0</a>. <p>unshackle is licensed under <a href="https://github.com/unshackle-dl/unshackle/blob/main/LICENSE">GPL-3.0</a>.
Do not use it for content you do not have the rights to. Keep the core free and Do not use it for content you do not have the rights to. Keep the core free and
open, keep service code private, and be kind.</p> open, keep service code private, and be kind.</p>
</div> </div>
<h2 id="what-it-does">What it does<a class="headerlink" href="#what-it-does" title="Permanent link">&para;</a></h2> <h2 id="what-it-does">What it does<a class="headerlink" href="#what-it-does" title="Permanent link">&para;</a></h2>
<p>Point unshackle at a title on a streaming service and it will:</p> <p>unshackle does everything except talk to the streaming platform. You write that part
as a service module (<a href="dev/creating-a-service/">Creating a Service</a>). Point unshackle
at a title and it will:</p>
<ul> <ul>
<li>Fetch the title metadata (movies, full series, seasons, episodes, albums, tracks).</li> <li>Fetch the title metadata (movies, full series, seasons, episodes, albums, tracks).</li>
<li>Parse the streaming manifest: <strong>DASH</strong>, <strong>HLS</strong>, or <strong>Smooth Streaming (ISM)</strong>.</li> <li>Parse the streaming manifest: <strong>DASH</strong>, <strong>HLS</strong>, or <strong>Smooth Streaming (ISM)</strong>.</li>
@@ -1842,7 +1844,7 @@ open, keep service code private, and be kind.</p>
</tr> </tr>
<tr> <tr>
<td>Services</td> <td>Services</td>
<td>Pluggable service modules, loadable from local folders or git repositories</td> <td>A plugin API for the service modules you write. unshackle includes none</td>
</tr> </tr>
<tr> <tr>
<td>Automation</td> <td>Automation</td>
@@ -1875,7 +1877,7 @@ open, keep service code private, and be kind.</p>
<h2 id="a-first-download">A first download<a class="headerlink" href="#a-first-download" title="Permanent link">&para;</a></h2> <h2 id="a-first-download">A first download<a class="headerlink" href="#a-first-download" title="Permanent link">&para;</a></h2>
<p>Every download is three parts: the <code>dl</code> command, a <strong>service tag</strong>, and the <p>Every download is three parts: the <code>dl</code> command, a <strong>service tag</strong>, and the
service's title argument (a URL, ID, or slug).</p> service's title argument (a URL, ID, or slug).</p>
<div class="language-shell highlight"><span class="filename">Download a 1080p title with English audio and subtitles</span><pre><span></span><code><span id="__span-2-1"><a id="__codelineno-2-1" name="__codelineno-2-1" href="#__codelineno-2-1"></a>unshackle<span class="w"> </span>dl<span class="w"> </span>-q<span class="w"> </span><span class="m">1080</span><span class="w"> </span>-l<span class="w"> </span>en<span class="w"> </span>EXAMPLE<span class="w"> </span><span class="m">81234567</span> <div class="language-shell highlight"><span class="filename">Download a 1080p title with English audio</span><pre><span></span><code><span id="__span-2-1"><a id="__codelineno-2-1" name="__codelineno-2-1" href="#__codelineno-2-1"></a>unshackle<span class="w"> </span>dl<span class="w"> </span>-q<span class="w"> </span><span class="m">1080</span><span class="w"> </span>-l<span class="w"> </span>en<span class="w"> </span>EXAMPLE<span class="w"> </span><span class="m">81234567</span>
</span></code></pre></div> </span></code></pre></div>
<p>The <code>dl</code> command carries all the quality, language, and output flags; the service <p>The <code>dl</code> command carries all the quality, language, and output flags; the service
tag (<code>EXAMPLE</code> above) selects which streaming service to talk to, and the value after it tag (<code>EXAMPLE</code> above) selects which streaming service to talk to, and the value after it
@@ -1886,7 +1888,7 @@ install to your first file.</p>
<li><strong><a href="getting-started/installation/">Installation</a></strong>. Install unshackle and the external tools it depends on.</li> <li><strong><a href="getting-started/installation/">Installation</a></strong>. Install unshackle and the external tools it depends on.</li>
<li><strong><a href="getting-started/quickstart/">Quickstart</a></strong>. Configure <code>unshackle.yaml</code> and run your first download.</li> <li><strong><a href="getting-started/quickstart/">Quickstart</a></strong>. Configure <code>unshackle.yaml</code> and run your first download.</li>
<li><strong><a href="guide/downloading/">Downloading</a></strong>. The full <code>dl</code> command guide: quality, codecs, languages, track selection, and output.</li> <li><strong><a href="guide/downloading/">Downloading</a></strong>. The full <code>dl</code> command guide: quality, codecs, languages, track selection, and output.</li>
<li><strong><a href="getting-started/configuration-file/">Configuration</a></strong>. Every <code>unshackle.yaml</code> key, directories, vaults, proxies, and naming templates.</li> <li><strong><a href="getting-started/configuration-file/">Configuration</a></strong>. Where <code>unshackle.yaml</code> lives, the directory layout, and how to edit values. Full key list in the <a href="reference/configuration/">Configuration Reference</a>.</li>
<li><strong><a href="dev/rest-api/">REST API</a></strong>. Run the <code>serve</code> HTTP server and drive downloads programmatically.</li> <li><strong><a href="dev/rest-api/">REST API</a></strong>. Run the <code>serve</code> HTTP server and drive downloads programmatically.</li>
</ul> </ul>
<div class="admonition tip"> <div class="admonition tip">
+31 -36
View File
@@ -2580,7 +2580,7 @@
<h1 id="configuration-reference">Configuration Reference<a class="headerlink" href="#configuration-reference" title="Permanent link">&para;</a></h1> <h1 id="configuration-reference">Configuration Reference<a class="headerlink" href="#configuration-reference" title="Permanent link">&para;</a></h1>
<p>This page is the exhaustive, authoritative reference for <strong>every</strong> key you can set in <p>This page documents every key you can set in
<code>unshackle.yaml</code>. For each key you will find its name, expected type, default value, and <code>unshackle.yaml</code>. For each key you will find its name, expected type, default value, and
what it does. Keys are grouped by area so you can jump straight to the part of unshackle what it does. Keys are grouped by area so you can jump straight to the part of unshackle
you are configuring.</p> you are configuring.</p>
@@ -2589,10 +2589,12 @@ edit it), start with <a href="../../getting-started/configuration-file/">The Con
This page assumes you already know the basics and want precise details.</p> This page assumes you already know the basics and want precise details.</p>
<div class="admonition info"> <div class="admonition info">
<p class="admonition-title">How defaults work</p> <p class="admonition-title">How defaults work</p>
<p>Every key is optional. If you omit a key, unshackle uses the built-in default listed <p>Every key is optional except <a href="#output-naming"><code>output_template</code></a>, which <code>dl</code> requires.
here. There is <strong>no schema validation</strong>: unknown keys are silently ignored (they never Without it, <code>dl</code> aborts with an error. If you omit any other key, unshackle uses
become settings), and the file is parsed with <code>yaml.safe_load</code>. An empty or missing the built-in default listed here. There is <strong>no schema validation</strong>: unknown keys are
file means <em>all</em> defaults apply.</p> silently ignored (they never become settings), and the file is parsed with
<code>yaml.safe_load</code>. An empty or missing file means every other key falls back to its
default.</p>
</div> </div>
<div class="admonition warning"> <div class="admonition warning">
<p class="admonition-title">Two keys behave specially on load</p> <p class="admonition-title">Two keys behave specially on load</p>
@@ -2625,7 +2627,7 @@ file means <em>all</em> defaults apply.</p>
</tr> </tr>
<tr> <tr>
<td><a href="#download-processing">Download &amp; processing</a></td> <td><a href="#download-processing">Download &amp; processing</a></td>
<td><code>dl</code>, <code>subtitle</code>, <code>audio</code>, <code>muxing</code>, <code>language_tags</code></td> <td><code>dl</code>, <code>subtitle</code>, <code>audio</code>, <code>muxing</code>, <code>language_tags</code>, <code>dual_multi_mode</code></td>
</tr> </tr>
<tr> <tr>
<td><a href="#output-naming">Output &amp; naming</a></td> <td><a href="#output-naming">Output &amp; naming</a></td>
@@ -2822,7 +2824,7 @@ paths are used as-is. <strong>List order is priority</strong>: the first source
tag wins, so put your own local service directories <strong>last</strong> to make them fallbacks.</p> tag wins, so put your own local service directories <strong>last</strong> to make them fallbacks.</p>
<div class="language-yaml highlight"><pre><span></span><code><span id="__span-1-1"><a id="__codelineno-1-1" name="__codelineno-1-1" href="#__codelineno-1-1"></a><span class="nt">directories</span><span class="p">:</span> <div class="language-yaml highlight"><pre><span></span><code><span id="__span-1-1"><a id="__codelineno-1-1" name="__codelineno-1-1" href="#__codelineno-1-1"></a><span class="nt">directories</span><span class="p">:</span>
</span><span id="__span-1-2"><a id="__codelineno-1-2" name="__codelineno-1-2" href="#__codelineno-1-2"></a><span class="w"> </span><span class="nt">services</span><span class="p">:</span> </span><span id="__span-1-2"><a id="__codelineno-1-2" name="__codelineno-1-2" href="#__codelineno-1-2"></a><span class="w"> </span><span class="nt">services</span><span class="p">:</span>
</span><span id="__span-1-3"><a id="__codelineno-1-3" name="__codelineno-1-3" href="#__codelineno-1-3"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">unshackle-dl/community-services</span><span class="w"> </span><span class="c1"># cloned from GitHub</span> </span><span id="__span-1-3"><a id="__codelineno-1-3" name="__codelineno-1-3" href="#__codelineno-1-3"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">you/your-services</span><span class="w"> </span><span class="c1"># cloned from GitHub</span>
</span><span id="__span-1-4"><a id="__codelineno-1-4" name="__codelineno-1-4" href="#__codelineno-1-4"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">https://example.com/private.git@stable</span> </span><span id="__span-1-4"><a id="__codelineno-1-4" name="__codelineno-1-4" href="#__codelineno-1-4"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">https://example.com/private.git@stable</span>
</span><span id="__span-1-5"><a id="__codelineno-1-5" name="__codelineno-1-5" href="#__codelineno-1-5"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">~/my-services</span><span class="w"> </span><span class="c1"># local, lowest priority</span> </span><span id="__span-1-5"><a id="__codelineno-1-5" name="__codelineno-1-5" href="#__codelineno-1-5"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">~/my-services</span><span class="w"> </span><span class="c1"># local, lowest priority</span>
</span></code></pre></div> </span></code></pre></div>
@@ -3030,7 +3032,7 @@ is the <a href="../../dev/rest-api/">REST API</a> section; these are the config
<td><code>remote_only</code></td> <td><code>remote_only</code></td>
<td>bool</td> <td>bool</td>
<td><code>false</code></td> <td><code>false</code></td>
<td>Run without a local <code>output_template</code> (CORS/Cloudflare-friendly).</td> <td>Expose only the remote service session endpoints (health, services, search, session) and disable the rest of the REST API.</td>
</tr> </tr>
<tr> <tr>
<td><code>session_ttl</code></td> <td><code>session_ttl</code></td>
@@ -3080,12 +3082,6 @@ is the <a href="../../dev/rest-api/">REST API</a> section; these are the config
<td><em>(auto)</em></td> <td><em>(auto)</em></td>
<td>PlayReady devices; auto-filled from <code>directories.prds</code>.</td> <td>PlayReady devices; auto-filled from <code>directories.prds</code>.</td>
</tr> </tr>
<tr>
<td><code>country</code> / <code>locations</code></td>
<td>str / dict</td>
<td><em>(unset)</em></td>
<td>Advertised region metadata.</td>
</tr>
</tbody> </tbody>
</table> </table>
<p>Each entry under <code>users</code> is keyed by that user's API key and may set its own <code>services</code>, <p>Each entry under <code>users</code> is keyed by that user's API key and may set its own <code>services</code>,
@@ -3103,9 +3099,10 @@ is the <a href="../../dev/rest-api/">REST API</a> section; these are the config
</span></code></pre></div> </span></code></pre></div>
<div class="admonition tip"> <div class="admonition tip">
<p class="admonition-title">Declaring <code>dl</code> defaults under <code>serve</code></p> <p class="admonition-title">Declaring <code>dl</code> defaults under <code>serve</code></p>
<p>You can set any <a href="#dl"><code>dl</code></a> flag key (<code>downloads</code>, <code>workers</code>, <code>best_available</code>, and so on) <p>You can set most <a href="#dl"><code>dl</code></a> flag keys (<code>downloads</code>, <code>workers</code>, <code>best_available</code>, and so on)
directly inside <code>serve</code>. The point is to raise concurrency and behaviour defaults directly inside <code>serve</code>; the server recognises a fixed subset of download parameters, so a
<strong>server-wide</strong> (every request the server handles picks them up) without having to change few CLI-only flags are ignored here. This raises concurrency and behaviour defaults
<strong>server-wide</strong> (every request the server handles picks them up) without changing
each client call individually.</p> each client call individually.</p>
</div> </div>
<hr /> <hr />
@@ -3163,7 +3160,7 @@ after the flag's internal destination rather than its visible name; set these ex
</tr> </tr>
</tbody> </tbody>
</table> </table>
<p><strong>Precedence</strong> (highest first): an explicit CLI flag or environment variable → a per-service <p><strong>Precedence</strong> (highest first): an explicit CLI flag → a per-service
<a href="#services-auth"><code>services.&lt;TAG&gt;.dl</code></a> override → this global <code>dl:</code> block → the built-in <a href="#services-auth"><code>services.&lt;TAG&gt;.dl</code></a> override → this global <code>dl:</code> block → the built-in
default. In other words, config only fills in options you did not set on the command line.</p> default. In other words, config only fills in options you did not set on the command line.</p>
<p>Common keys (a useful subset; every <code>dl</code> flag works):</p> <p>Common keys (a useful subset; every <code>dl</code> flag works):</p>
@@ -3364,7 +3361,7 @@ written as sidecar files. See <a href="../../guide/subtitles/">Subtitles</a> for
<td><code>output_mode</code></td> <td><code>output_mode</code></td>
<td>str</td> <td>str</td>
<td><code>"mux"</code></td> <td><code>"mux"</code></td>
<td><code>mux</code> embeds subtitles in the MKV; <code>sidecar</code> writes separate files.</td> <td><code>mux</code> embeds subtitles in the MKV; <code>sidecar</code> writes separate files; <code>both</code> writes sidecars and still muxes.</td>
</tr> </tr>
<tr> <tr>
<td><code>sidecar_format</code></td> <td><code>sidecar_format</code></td>
@@ -3408,9 +3405,9 @@ audio codecs used to break ties in track selection.</p>
</span></code></pre></div> </span></code></pre></div>
<div class="admonition note"> <div class="admonition note">
<p class="admonition-title"><code>codec_priority</code> is a soft priority: nothing is dropped</p> <p class="admonition-title"><code>codec_priority</code> is a soft priority: nothing is dropped</p>
<p><code>codec_priority</code> only breaks ties <strong>among tracks that share the same bitrate and language</strong>. <p><code>codec_priority</code> outranks bitrate: any listed codec sorts above every unlisted one, and among
Codecs not in the list keep their normal bitrate-based ordering and are simply placed after listed codecs the list order decides. Bitrate order survives only within a single codec rank.
all listed codecs, and none are ever removed. Two higher-level rules still override it: <strong>Atmos Nothing is ever removed. Two higher-level rules still override it: <strong>Atmos
tracks always take precedence over <code>codec_priority</code></strong>, and <strong>audio-description tracks are tracks always take precedence over <code>codec_priority</code></strong>, and <strong>audio-description tracks are
always forced to the end</strong> regardless of it. When <code>codec_priority</code> is unset, tracks sort by always forced to the end</strong> regardless of it. When <code>codec_priority</code> is unset, tracks sort by
bitrate alone, with those same Atmos/descriptive rules still applied.</p> bitrate alone, with those same Atmos/descriptive rules still applied.</p>
@@ -3452,7 +3449,7 @@ bitrate alone, with those same Atmos/descriptive rules still applied.</p>
<td><code>merge_video</code></td> <td><code>merge_video</code></td>
<td>bool</td> <td>bool</td>
<td><code>false</code></td> <td><code>false</code></td>
<td>Merge all video tracks into one file. <code>--merge-video</code> on the CLI flips this on.</td> <td>Merge video tracks that share height, range, and codec into one file, so only language varies inside a file. <code>--merge-video</code> on the CLI flips this on.</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
@@ -3493,12 +3490,9 @@ A rule may test:</p>
</table> </table>
<div class="language-yaml highlight"><pre><span></span><code><span id="__span-11-1"><a id="__codelineno-11-1" name="__codelineno-11-1" href="#__codelineno-11-1"></a><span class="nt">language_tags</span><span class="p">:</span> <div class="language-yaml highlight"><pre><span></span><code><span id="__span-11-1"><a id="__codelineno-11-1" name="__codelineno-11-1" href="#__codelineno-11-1"></a><span class="nt">language_tags</span><span class="p">:</span>
</span><span id="__span-11-2"><a id="__codelineno-11-2" name="__codelineno-11-2" href="#__codelineno-11-2"></a><span class="w"> </span><span class="nt">rules</span><span class="p">:</span> </span><span id="__span-11-2"><a id="__codelineno-11-2" name="__codelineno-11-2" href="#__codelineno-11-2"></a><span class="w"> </span><span class="nt">rules</span><span class="p">:</span>
</span><span id="__span-11-3"><a id="__codelineno-11-3" name="__codelineno-11-3" href="#__codelineno-11-3"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">audio</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">[</span><span class="nv">en</span><span class="p p-Indicator">]</span> </span><span id="__span-11-3"><a id="__codelineno-11-3" name="__codelineno-11-3" href="#__codelineno-11-3"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">audio</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">[</span><span class="nv">ja</span><span class="p p-Indicator">]</span>
</span><span id="__span-11-4"><a id="__codelineno-11-4" name="__codelineno-11-4" href="#__codelineno-11-4"></a><span class="w"> </span><span class="nt">subs_contain_all</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">[</span><span class="nv">en</span><span class="p p-Indicator">]</span> </span><span id="__span-11-4"><a id="__codelineno-11-4" name="__codelineno-11-4" href="#__codelineno-11-4"></a><span class="w"> </span><span class="nt">subs_contain</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">[</span><span class="nv">en</span><span class="p p-Indicator">]</span>
</span><span id="__span-11-5"><a id="__codelineno-11-5" name="__codelineno-11-5" href="#__codelineno-11-5"></a><span class="w"> </span><span class="nt">tag</span><span class="p">:</span><span class="w"> </span><span class="s">&quot;&quot;</span><span class="w"> </span><span class="c1"># native English release, no tag</span> </span><span id="__span-11-5"><a id="__codelineno-11-5" name="__codelineno-11-5" href="#__codelineno-11-5"></a><span class="w"> </span><span class="nt">tag</span><span class="p">:</span><span class="w"> </span><span class="s">&quot;SUBBED&quot;</span>
</span><span id="__span-11-6"><a id="__codelineno-11-6" name="__codelineno-11-6" href="#__codelineno-11-6"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">audio</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">[</span><span class="nv">ja</span><span class="p p-Indicator">]</span>
</span><span id="__span-11-7"><a id="__codelineno-11-7" name="__codelineno-11-7" href="#__codelineno-11-7"></a><span class="w"> </span><span class="nt">subs_contain</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">[</span><span class="nv">en</span><span class="p p-Indicator">]</span>
</span><span id="__span-11-8"><a id="__codelineno-11-8" name="__codelineno-11-8" href="#__codelineno-11-8"></a><span class="w"> </span><span class="nt">tag</span><span class="p">:</span><span class="w"> </span><span class="s">&quot;SUBBED&quot;</span>
</span></code></pre></div> </span></code></pre></div>
<h3 id="dual_multi_mode"><code>dual_multi_mode</code><a class="headerlink" href="#dual_multi_mode" title="Permanent link">&para;</a></h3> <h3 id="dual_multi_mode"><code>dual_multi_mode</code><a class="headerlink" href="#dual_multi_mode" title="Permanent link">&para;</a></h3>
<ul> <ul>
@@ -3570,7 +3564,7 @@ language in both modes, so they never trigger <code>{dual}</code> on their own.<
<a href="../../guide/output-and-naming/">Output &amp; naming</a>. The keys are summarised here.</p> <a href="../../guide/output-and-naming/">Output &amp; naming</a>. The keys are summarised here.</p>
<h3 id="output_template"><code>output_template</code><a class="headerlink" href="#output_template" title="Permanent link">&para;</a></h3> <h3 id="output_template"><code>output_template</code><a class="headerlink" href="#output_template" title="Permanent link">&para;</a></h3>
<ul> <ul>
<li><strong>Type:</strong> <code>dict</code> &nbsp;·&nbsp; <strong>Default:</strong> <code>{}</code></li> <li><strong>Type:</strong> <code>dict</code> &nbsp;·&nbsp; <strong>Required</strong> (no usable default; <code>dl</code> exits with an error if this is missing)</li>
</ul> </ul>
<p>Filename templates keyed by media kind, using <code>{variable}</code> placeholders. Recognised kinds are <p>Filename templates keyed by media kind, using <code>{variable}</code> placeholders. Recognised kinds are
<code>movies</code>, <code>series</code>, and <code>songs</code> (and <code>albums</code> for folder templates). A trailing <code>?</code> on a <code>movies</code>, <code>series</code>, and <code>songs</code> (and <code>albums</code> for folder templates). A trailing <code>?</code> on a
@@ -3737,7 +3731,7 @@ case-insensitively; <code>"mp4decrypt"</code> selects Bento4's mp4decrypt, and <
<div class="tabbed-block"> <div class="tabbed-block">
<div class="language-yaml highlight"><pre><span></span><code><span id="__span-18-1"><a id="__codelineno-18-1" name="__codelineno-18-1" href="#__codelineno-18-1"></a><span class="nt">decryption</span><span class="p">:</span> <div class="language-yaml highlight"><pre><span></span><code><span id="__span-18-1"><a id="__codelineno-18-1" name="__codelineno-18-1" href="#__codelineno-18-1"></a><span class="nt">decryption</span><span class="p">:</span>
</span><span id="__span-18-2"><a id="__codelineno-18-2" name="__codelineno-18-2" href="#__codelineno-18-2"></a><span class="w"> </span><span class="nt">default</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">shaka</span> </span><span id="__span-18-2"><a id="__codelineno-18-2" name="__codelineno-18-2" href="#__codelineno-18-2"></a><span class="w"> </span><span class="nt">default</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">shaka</span>
</span><span id="__span-18-3"><a id="__codelineno-18-3" name="__codelineno-18-3" href="#__codelineno-18-3"></a><span class="w"> </span><span class="nt">SOMESERVICE</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">mp4decrypt</span> </span><span id="__span-18-3"><a id="__codelineno-18-3" name="__codelineno-18-3" href="#__codelineno-18-3"></a><span class="w"> </span><span class="nt">EXAMPLE1</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">mp4decrypt</span>
</span></code></pre></div> </span></code></pre></div>
</div> </div>
</div> </div>
@@ -3976,8 +3970,9 @@ keys instead of re-licensing. Each entry needs a <code>type</code> (the backend
<p class="admonition-title">Common per-entry options</p> <p class="admonition-title">Common per-entry options</p>
<ul> <ul>
<li><code>no_push: true</code> makes a vault read-only (keys are fetched but never written to it).</li> <li><code>no_push: true</code> makes a vault read-only (keys are fetched but never written to it).</li>
<li>A vault of <code>type: api</code> whose <code>name</code> contains <code>decrypt_labs</code> auto-fills its <code>token</code> from <li>A vault of <code>type: API</code> whose <code>name</code> contains <code>decrypt_labs</code> auto-fills its <code>token</code> from
<a href="#external-api-keys"><code>decrypt_labs_api_key</code></a> when not set inline.</li> <a href="#external-api-keys"><code>decrypt_labs_api_key</code></a> when not set inline. Vault <code>type</code> values are
case-sensitive module names.</li>
<li>An all-zero content key (32 zeros) is treated as "no key" everywhere and is never <li>An all-zero content key (32 zeros) is treated as "no key" everywhere and is never
stored.</li> stored.</li>
</ul> </ul>
@@ -4041,9 +4036,9 @@ constructor accepts a <code>timeout</code> parameter (a per-vault <code>timeout<
</table> </table>
<div class="admonition tip"> <div class="admonition tip">
<p class="admonition-title">SIMKL is a fallback for TMDB</p> <p class="admonition-title">SIMKL is a fallback for TMDB</p>
<p>SIMKL is positioned as an alternative metadata source, and it is most valuable precisely <p>SIMKL is an alternative metadata source. Use it when you have no <code>tmdb_api_key</code>
<strong>when no <code>tmdb_api_key</code> is configured</strong>. It improves title-matching and tagging configured; it improves title matching and tagging in that case rather than replacing
reliability in that case rather than replacing TMDB where TMDB is available.</p> TMDB.</p>
</div> </div>
<div class="admonition note"> <div class="admonition note">
<p class="admonition-title"><code>ipinfo_api_key</code> never touches your service sessions</p> <p class="admonition-title"><code>ipinfo_api_key</code> never touches your service sessions</p>
File diff suppressed because one or more lines are too long