mirror of
https://github.com/unshackle-dl/unshackle.git
synced 2026-11-14 13:05:09 +00:00
Deployed 8b10b79 with MkDocs version: 1.6.1
This commit is contained in:
@@ -1975,11 +1975,11 @@
|
||||
|
||||
|
||||
<h1 id="directories">Directories<a class="headerlink" href="#directories" title="Permanent link">¶</a></h1>
|
||||
<p>The <code>directories</code> key is a <strong>dict</strong> mapping directory names to filesystem paths. Only the
|
||||
names listed below are honoured; a handful are <strong>protected</strong> and cannot be moved (attempts
|
||||
to override them are silently skipped). All defaults are computed relative to the installed
|
||||
package, and every user-settable path is passed through <code>Path(...).expanduser()</code>, so <code>~</code>
|
||||
works.</p>
|
||||
<p>The <code>directories</code> config key is a <strong>dict</strong> mapping directory names to filesystem paths.
|
||||
unshackle honours only the names listed below. A handful are <strong>protected</strong> and you cannot
|
||||
move them, and unshackle silently ignores an override of one. unshackle computes all
|
||||
defaults relative to the installed package, and passes every user-settable path through
|
||||
<code>Path(...).expanduser()</code>, so <code>~</code> works.</p>
|
||||
<div class="language-yaml highlight"><span class="filename">unshackle.yaml</span><pre><span></span><code><span id="__span-0-1"><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a><span class="nt">directories</span><span class="p">:</span>
|
||||
</span><span id="__span-0-2"><a id="__codelineno-0-2" name="__codelineno-0-2" href="#__codelineno-0-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">~/Media/unshackle</span>
|
||||
</span><span id="__span-0-3"><a id="__codelineno-0-3" name="__codelineno-0-3" href="#__codelineno-0-3"></a><span class="w"> </span><span class="nt">temp</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">/mnt/fast-scratch/unshackle-temp</span>
|
||||
@@ -2129,9 +2129,9 @@ works.</p>
|
||||
<p class="admonition-title">The <code>services</code> directory is special</p>
|
||||
<p><code>services</code> may be a <strong>list</strong>, and each entry can be either a local directory or a
|
||||
<strong>repository spec</strong>: a git URL (<code>https://...</code>, <code>ssh://...</code>, <code>git@...</code>, or anything ending in
|
||||
<code>.git</code>) or <code>owner/repo</code> shorthand. Repo specs are cloned and updated automatically; plain
|
||||
paths are used as-is. <strong>List order is priority</strong>: the first source to define a service
|
||||
tag wins.</p>
|
||||
<code>.git</code>) or <code>owner/repo</code> shorthand. unshackle clones and updates repo specs automatically,
|
||||
and uses plain paths as they are. <strong>List order is priority</strong>: the first source to define a
|
||||
service tag wins.</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>
|
||||
</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">you/your-services</span><span class="w"> </span><span class="c1"># cloned from GitHub</span>
|
||||
@@ -2141,11 +2141,11 @@ tag wins.</p>
|
||||
</div>
|
||||
<div class="admonition info">
|
||||
<p class="admonition-title">How git-backed service repos are handled</p>
|
||||
<p>unshackle's use of git is <strong>read-only on the remote</strong>: it only ever performs a shallow
|
||||
<code>clone</code>, <code>fetch</code>, <code>pull</code>, and a local <code>reset</code>; <strong>nothing is ever pushed</strong>. Private repos
|
||||
are authenticated through your existing git credential helper, and unshackle stores no
|
||||
<p>unshackle's use of git is <strong>read-only on the remote</strong>: it only ever does a shallow
|
||||
<code>clone</code>, <code>fetch</code>, <code>pull</code>, and a local <code>reset</code>. <strong>unshackle never pushes anything</strong>. Your
|
||||
existing git credential helper authenticates private repos, and unshackle stores no
|
||||
tokens of its own. Clones live under <code><first-local-services-dir>/_repos/<host>__<owner>__<repo>/</code>
|
||||
(or the bundled <code>unshackle/services</code>), and <strong>nothing is written to the cache directory</strong>. After
|
||||
(or the bundled <code>unshackle/services</code>), and <strong>unshackle writes nothing to the cache directory</strong>. After
|
||||
the first clone unshackle re-pulls <strong>at most once every 24 h</strong>, so it does not touch the
|
||||
network on every run.</p>
|
||||
</div>
|
||||
@@ -2165,9 +2165,9 @@ discarding any local edits.</p>
|
||||
point <code>services</code> at a writable path, or cloning will fail.</p>
|
||||
</div>
|
||||
<h2 id="filenames">Filenames<a class="headerlink" href="#filenames" title="Permanent link">¶</a></h2>
|
||||
<p>The <code>filenames</code> key is a <strong>dict</strong> of templated file/name patterns. Each value is used
|
||||
verbatim (no path processing). Braced fields like <code>{time}</code> and <code>{service}</code> are filled in at
|
||||
runtime.</p>
|
||||
<p>The <code>filenames</code> config key is a <strong>dict</strong> of templated file/name patterns. unshackle uses
|
||||
each value verbatim (no path processing). It fills in braced fields like <code>{time}</code> and
|
||||
<code>{service}</code> at runtime.</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
@@ -2111,12 +2111,13 @@
|
||||
<ul>
|
||||
<li><strong>Type:</strong> <code>dict</code> · <strong>Default:</strong> <code>{}</code></li>
|
||||
</ul>
|
||||
<p>Persistent defaults for the <code>dl</code> command. The block is used as Click's <code>default_map</code>, so any
|
||||
<code>dl</code> flag can be given a default here. See <a href="../../../guide/downloading/">Downloading</a> and the
|
||||
<p>Persistent defaults for the <code>dl</code> command. unshackle uses the block as Click's <code>default_map</code>,
|
||||
so you can give any <code>dl</code> flag a default here. See <a href="../../../guide/downloading/">Downloading</a> and the
|
||||
<a href="../../../guide/cli-reference/">CLI Reference</a> for what each flag does.</p>
|
||||
<p><strong>Key naming.</strong> A key is the flag's long name with dashes replaced by underscores
|
||||
(<code>--best-available</code> → <code>best_available</code>, <code>--sub-format</code> → <code>sub_format</code>). A few keys are named
|
||||
after the flag's internal destination rather than its visible name; set these exact keys:</p>
|
||||
<p><strong>Config key naming.</strong> A config key is the flag's long name with dashes replaced by
|
||||
underscores (<code>--best-available</code> → <code>best_available</code>, <code>--sub-format</code> → <code>sub_format</code>). A few
|
||||
config keys use the flag's internal destination and not its visible name. Set these exact
|
||||
config keys:</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
@@ -2162,7 +2163,7 @@ after the flag's internal destination rather than its visible name; set these ex
|
||||
<p><strong>Precedence</strong> (highest first): an explicit CLI flag → a per-service
|
||||
<a href="../services/"><code>services.<TAG>.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>
|
||||
<p>Common keys (a useful subset; every <code>dl</code> flag works):</p>
|
||||
<p>Common config keys. This is a useful subset, and every <code>dl</code> flag works:</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
@@ -2323,28 +2324,28 @@ applies to that service only.</p>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title"><code>serve</code> uses these same keys</p>
|
||||
<p>The <a href="../services/#serve"><code>serve</code></a> block accepts most of the same <code>dl</code> option keys at its top level
|
||||
to set server-wide download defaults for every request it handles. Keys the API does not know
|
||||
are ignored there (<code>speed_limit</code>, for example; <code>serve</code> has its own <code>global_speed_limit</code>).</p>
|
||||
to set server-wide download defaults for every request it handles. The API ignores the
|
||||
config keys it does not know there, <code>speed_limit</code> for example. <code>serve</code> has its own
|
||||
<code>global_speed_limit</code>.</p>
|
||||
</div>
|
||||
<h2 id="continue_downloads"><code>continue_downloads</code><a class="headerlink" href="#continue_downloads" title="Permanent link">¶</a></h2>
|
||||
<ul>
|
||||
<li><strong>Type:</strong> <code>bool</code> · <strong>Default:</strong> <code>false</code></li>
|
||||
</ul>
|
||||
<p>Keep a failed download's completed segment files so the next attempt resumes from where it
|
||||
<p>Keep a failed download's completed segment files so the next download resumes from where it
|
||||
stopped instead of restarting from byte zero.</p>
|
||||
<p>Only whole, fully downloaded segments are reused; partially written segments are always
|
||||
discarded, and no partial-byte (<code>Range</code>) resume across runs takes place. Reuse also
|
||||
requires proof that the remote content is unchanged: the manifest URL, segment count, and
|
||||
byte ranges must all match the previous run, otherwise the download silently restarts
|
||||
clean.</p>
|
||||
<p>unshackle reuses only whole, fully downloaded segments. It always discards partially written
|
||||
segments, and no partial-byte (<code>Range</code>) resume across runs takes place. Reuse is possible only
|
||||
with proof that the segmentation did not change. The manifest URL, segment count, and byte
|
||||
ranges must all match the previous download, or the download silently restarts clean.</p>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">What can and cannot resume</p>
|
||||
<ul>
|
||||
<li>Segmented DASH, ISM, and HLS tracks resume.</li>
|
||||
<li>Single-file (non-segmented) downloads and DASH tracks collapsed to a single ranged
|
||||
download never produce segment files, so this option does not apply to them (the
|
||||
download never make segment files, so this option does not apply to them (the
|
||||
downloader has its own in-flight partial-file handling for those).</li>
|
||||
<li>HLS resumes Widevine/PlayReady and unencrypted content only; AES-128 content always
|
||||
<li>HLS resumes Widevine/PlayReady and unencrypted titles only. An AES-128 title always
|
||||
restarts. An HLS failure during the post-download merge step also restarts.</li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -2356,8 +2357,8 @@ command line (the flag can only enable resume, never disable it).</p>
|
||||
<ul>
|
||||
<li><strong>Type:</strong> <code>dict</code> · <strong>Default:</strong> <code>{}</code></li>
|
||||
</ul>
|
||||
<p>Subtitle handling: SDH stripping, format conversion, and whether subtitles are muxed in or
|
||||
written as sidecar files. See <a href="../../../guide/subtitles/">Subtitles</a> for the full guide.</p>
|
||||
<p>Subtitle handling: SDH stripping, format conversion, and whether unshackle muxes the subtitles
|
||||
in or writes them as sidecar files. See <a href="../../../guide/subtitles/">Subtitles</a> for the full guide.</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
@@ -2482,7 +2483,7 @@ controls the order inside each language.</p>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Nothing is removed, unlike <code>-sl</code>, which drops every subtitle language it does not name.</p>
|
||||
<p>unshackle removes nothing, unlike <code>-sl</code>, which drops every subtitle language it does not name.</p>
|
||||
<p>Use <code>orig</code> in the list for the title's original language. A base tag also covers its
|
||||
regional forms, so <code>en</code> sorts <code>en-US</code> and <code>en-GB</code>, but <code>zh</code> does <strong>not</strong> cover
|
||||
<code>zh-Hant</code>, which you must name. The sort ignores entries that match no track, and it
|
||||
@@ -2580,8 +2581,8 @@ bitrate alone, with those same Atmos/descriptive rules still applied.</p>
|
||||
<li><strong>Type:</strong> <code>dict</code> · <strong>Default:</strong> <code>{}</code></li>
|
||||
</ul>
|
||||
<p>Language-tag remapping and the rule engine behind the <code>{lang_tag}</code> filename variable. When a
|
||||
<code>rules</code> list is present, each rule is evaluated in order and the first match's <code>tag</code> is used.
|
||||
A rule may test:</p>
|
||||
<code>rules</code> list is present, unshackle evaluates each rule in order and uses the first match's
|
||||
<code>tag</code>. A rule can examine:</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
@@ -2099,19 +2099,19 @@ profile:</p>
|
||||
</span><span id="__span-1-6"><a id="__codelineno-1-6" name="__codelineno-1-6" href="#__codelineno-1-6"></a><span class="w"> </span><span class="nt">playready</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">sl3000</span>
|
||||
</span><span id="__span-1-7"><a id="__codelineno-1-7" name="__codelineno-1-7" href="#__codelineno-1-7"></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">chromecdm_l3</span>
|
||||
</span></code></pre></div>
|
||||
<p>Quality keys support <code>1080</code>, <code>>=1080</code>, <code>>720</code>, <code><=576</code>, <code><480</code> style comparisons; DRM keys
|
||||
are <code>widevine</code> / <code>playready</code>. Quality keys are matched first, but only when a video height is
|
||||
known; if the value is still a dict after that, <code>widevine</code>/<code>playready</code> are used when present,
|
||||
otherwise the credential profile name, then <code>default</code>.</p>
|
||||
<p>The resolved name is looked up in <a href="#remote_cdm"><code>remote_cdm</code></a> by <code>name</code> first. If no entry
|
||||
matches, it is loaded as a local device file, in this order: <code><name>.prd</code> in
|
||||
<p>Quality keys can hold <code>1080</code>, <code>>=1080</code>, <code>>720</code>, <code><=576</code>, <code><480</code> style comparisons. DRM keys
|
||||
are <code>widevine</code> / <code>playready</code>. unshackle matches the quality keys first, but only when a video
|
||||
height is known. If the value is still a dict after that, unshackle uses
|
||||
<code>widevine</code>/<code>playready</code> when present, or else the credential profile name, then <code>default</code>.</p>
|
||||
<p>unshackle finds the resolved name in <a href="#remote_cdm"><code>remote_cdm</code></a> by <code>name</code> first. If no entry
|
||||
matches, unshackle loads it as a local device file, in this order: <code><name>.prd</code> in
|
||||
<code>directories.prds</code>, <code><name>.prd</code> in <code>directories.wvds</code>, then <code><name>.wvd</code> in
|
||||
<code>directories.wvds</code>.</p>
|
||||
<h2 id="remote_cdm"><code>remote_cdm</code><a class="headerlink" href="#remote_cdm" title="Permanent link">¶</a></h2>
|
||||
<ul>
|
||||
<li><strong>Type:</strong> <code>list[dict]</code> · <strong>Default:</strong> <code>[]</code></li>
|
||||
</ul>
|
||||
<p>A list of remote CDM server definitions. Each entry is matched by its <code>name</code> (referenced from
|
||||
<p>A list of remote CDM definitions. unshackle matches each entry by its <code>name</code> (referenced from
|
||||
<a href="#cdm"><code>cdm</code></a>), and its <code>type</code> selects the backend:</p>
|
||||
<table>
|
||||
<thead>
|
||||
@@ -2203,7 +2203,7 @@ configuration error.</p>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>PlayReady mode is used when <code>device_type</code> is <code>PLAYREADY</code> or <code>device_name</code> starts with <code>SL</code>.</p>
|
||||
<p>unshackle uses PlayReady mode when <code>device_type</code> is <code>PLAYREADY</code> or <code>device_name</code> starts with <code>SL</code>.</p>
|
||||
<h3 id="remote-cdm-custom-api"><code>custom_api</code> fields<a class="headerlink" href="#remote-cdm-custom-api" title="Permanent link">¶</a></h3>
|
||||
<table>
|
||||
<thead>
|
||||
@@ -2261,8 +2261,8 @@ configuration error.</p>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Transforms cover base64/hex/JSON encoding and <code>kid:key</code> parsing. PlayReady mode is used when
|
||||
<code>device.type</code> is <code>PLAYREADY</code> or the device name is <code>SL2</code>/<code>SL3</code>.</p>
|
||||
<p>Transforms cover base64/hex/JSON encoding and <code>kid:key</code> parsing. unshackle uses PlayReady mode
|
||||
when <code>device.type</code> is <code>PLAYREADY</code> or the device name is <code>SL2</code>/<code>SL3</code>.</p>
|
||||
<div class="language-yaml highlight"><pre><span></span><code><span id="__span-3-1"><a id="__codelineno-3-1" name="__codelineno-3-1" href="#__codelineno-3-1"></a><span class="nt">remote_cdm</span><span class="p">:</span>
|
||||
</span><span id="__span-3-2"><a id="__codelineno-3-2" name="__codelineno-3-2" href="#__codelineno-3-2"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">my_custom</span>
|
||||
</span><span id="__span-3-3"><a id="__codelineno-3-3" name="__codelineno-3-3" href="#__codelineno-3-3"></a><span class="w"> </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">custom_api</span>
|
||||
@@ -2288,11 +2288,11 @@ configuration error.</p>
|
||||
<ul>
|
||||
<li><strong>Type:</strong> <code>str</code> or <code>dict</code> · <strong>Default:</strong> <code>"shaka"</code></li>
|
||||
</ul>
|
||||
<p>Selects the tool used to physically decrypt CENC content. The value is compared
|
||||
case-insensitively; <code>"mp4decrypt"</code> selects Bento4's mp4decrypt, and <strong>anything else</strong>
|
||||
(including <code>"shaka"</code>) selects shaka-packager. When the value is a dict, the service key is
|
||||
matched case-insensitively and the <code>default</code> entry is the fallback.</p>
|
||||
<p>HLS AES-128 ClearKey is decrypted in-process and ignores this setting.</p>
|
||||
<p>Selects the tool that physically decrypts CENC-encrypted tracks. unshackle compares the value
|
||||
case-insensitively. <code>"mp4decrypt"</code> selects Bento4's mp4decrypt, and <strong>anything else</strong>
|
||||
(including <code>"shaka"</code>) selects shaka-packager. When the value is a dict, unshackle compares the
|
||||
service tag case-insensitively and uses the <code>default</code> entry as the fallback.</p>
|
||||
<p>unshackle decrypts HLS AES-128 ClearKey in-process and ignores this setting.</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">Global</label><label for="__tabbed_1_2">Per-service</label></div>
|
||||
<div class="tabbed-content">
|
||||
<div class="tabbed-block">
|
||||
|
||||
@@ -1908,7 +1908,7 @@
|
||||
|
||||
|
||||
<h1 id="a-complete-annotated-example">A complete annotated example<a class="headerlink" href="#a-complete-annotated-example" title="Permanent link">¶</a></h1>
|
||||
<p>The following config sets a handful of common keys. Every key not shown keeps its default.</p>
|
||||
<p>The following config sets a handful of common config keys. Every config key not shown keeps its default.</p>
|
||||
<div class="language-yaml highlight"><span class="filename">unshackle.yaml</span><pre><span></span><code><span id="__span-0-1"><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a><span class="nt">directories</span><span class="p">:</span>
|
||||
</span><span id="__span-0-2"><a id="__codelineno-0-2" name="__codelineno-0-2" href="#__codelineno-0-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">~/Media/unshackle</span>
|
||||
</span><span id="__span-0-3"><a id="__codelineno-0-3" name="__codelineno-0-3" href="#__codelineno-0-3"></a><span class="w"> </span><span class="nt">temp</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">/mnt/scratch/unshackle</span>
|
||||
|
||||
@@ -1917,17 +1917,17 @@
|
||||
|
||||
|
||||
<h1 id="configuration-reference">Configuration Reference<a class="headerlink" href="#configuration-reference" title="Permanent link">¶</a></h1>
|
||||
<p>Every key you can set in <code>unshackle.yaml</code>, with its name, type, default value, and behaviour,
|
||||
<p>Every config key you can set in <code>unshackle.yaml</code>, with its name, type, default value, and behaviour,
|
||||
split into one page per area. A worked config is on the <a href="example/">annotated example</a> page.</p>
|
||||
<p>Where the file lives, how unshackle discovers it, and how to edit it:
|
||||
<a href="../../getting-started/configuration-file/">The Configuration File</a>.</p>
|
||||
<div class="admonition info">
|
||||
<p class="admonition-title">How defaults work</p>
|
||||
<p>Every key is optional except <a href="output/"><code>output_template</code></a>, which <code>dl</code> requires.
|
||||
Without it, <code>dl</code> aborts with an error. If you omit any other key, unshackle uses
|
||||
the built-in default listed here. There is <strong>no schema validation</strong>: unknown keys are
|
||||
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
|
||||
<p>Every config key is optional except <a href="output/"><code>output_template</code></a>, which <code>dl</code> requires.
|
||||
Without it, <code>dl</code> aborts with an error. If you do not write any other config key, unshackle
|
||||
uses the built-in default listed here. There is <strong>no schema validation</strong>: unshackle
|
||||
silently ignores unknown config keys (they never become settings), and reads the file with
|
||||
<code>yaml.safe_load</code>. An empty or missing file means every other config key falls back to its
|
||||
default.</p>
|
||||
</div>
|
||||
<div class="admonition warning">
|
||||
|
||||
@@ -2122,7 +2122,7 @@
|
||||
<p>Smaller configuration areas: external metadata API keys, caching and update checks, logging and debug flags, and deprecated keys.</p>
|
||||
<h2 id="external-api-keys">External API keys<a class="headerlink" href="#external-api-keys" title="Permanent link">¶</a></h2>
|
||||
<p>All are unset by default and enable optional metadata/geolocation features. For which fields
|
||||
each metadata provider can actually answer with, see
|
||||
each metadata provider can answer with, see
|
||||
<a href="../../../guide/downloading/#what-each-metadata-provider-supplies">What each metadata provider supplies</a>.</p>
|
||||
<table>
|
||||
<thead>
|
||||
@@ -2204,7 +2204,7 @@ each metadata provider can actually answer with, see
|
||||
</table>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">How <code>metadata_providers</code> is applied</p>
|
||||
<p>A lookup goes to each provider in turn and stops at the first good match, so the order
|
||||
<p>A lookup goes to each metadata provider in turn and stops at the first good match, so the order
|
||||
decides which source wins. <code>metadata_providers</code> sets that order:</p>
|
||||
<div class="language-yaml highlight"><pre><span></span><code><span id="__span-0-1"><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a><span class="nt">metadata_providers</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">[</span><span class="nv">tvdb</span><span class="p p-Indicator">,</span><span class="w"> </span><span class="nv">tmdb</span><span class="p p-Indicator">,</span><span class="w"> </span><span class="nv">simkl</span><span class="p p-Indicator">]</span>
|
||||
</span></code></pre></div>
|
||||
@@ -2212,8 +2212,8 @@ decides which source wins. <code>metadata_providers</code> sets that order:</p>
|
||||
ignored with a warning. Leave it unset for the default order:</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">metadata_providers</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">[</span><span class="nv">imdb</span><span class="p p-Indicator">,</span><span class="w"> </span><span class="nv">omdb</span><span class="p p-Indicator">,</span><span class="w"> </span><span class="nv">simkl</span><span class="p p-Indicator">,</span><span class="w"> </span><span class="nv">tmdb</span><span class="p p-Indicator">,</span><span class="w"> </span><span class="nv">tvdb</span><span class="p p-Indicator">,</span><span class="w"> </span><span class="nv">anilist</span><span class="p p-Indicator">]</span>
|
||||
</span></code></pre></div>
|
||||
<p>Whatever the order, unshackle skips a provider that has no API key. <code>imdb</code> and
|
||||
<code>anilist</code> need no key, so they are always available. Available names are <code>imdb</code>, <code>omdb</code>,
|
||||
<p>Whatever the order, unshackle skips a metadata provider that has no API key. <code>imdb</code> and
|
||||
<code>anilist</code> need no API key, so they are always available. Available names are <code>imdb</code>, <code>omdb</code>,
|
||||
<code>simkl</code>, <code>tmdb</code>, <code>tvdb</code>, and <code>anilist</code>. The old name <code>imdbapi</code> still works and is read as
|
||||
<code>imdb</code>.</p>
|
||||
<p><code>anilist</code> is last in the default order. It only answers for anime and returns nothing for
|
||||
@@ -2235,18 +2235,18 @@ that is set, so you always get a title.</p>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">What <code>disable_metadata</code> turns off</p>
|
||||
<p>With <code>disable_metadata: true</code>, unshackle never contacts a metadata provider on its own.
|
||||
The title search is dead, and that includes the keyless <code>imdb</code> provider. Titles, years and
|
||||
The title search is dead, and that includes the keyless <code>imdb</code> metadata provider. Titles, years and
|
||||
languages then come only from the service.</p>
|
||||
<div class="language-yaml highlight"><pre><span></span><code><span id="__span-3-1"><a id="__codelineno-3-1" name="__codelineno-3-1" href="#__codelineno-3-1"></a><span class="nt">disable_metadata</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">true</span>
|
||||
</span></code></pre></div>
|
||||
<p>An ID you give with <code>--tmdb</code>, <code>--imdb</code>, <code>--tvdb</code>, or <code>--anilist</code> is your permission to use
|
||||
that ID. That lookup still works. unshackle looks the ID up directly, cross references the other
|
||||
IDs from it, and <code>--enrich</code> still reads that source. Only the lookups you did not ask for
|
||||
are stopped.</p>
|
||||
IDs from it, and <code>--enrich</code> still reads that source. unshackle stops only the lookups you
|
||||
did not ask for.</p>
|
||||
</div>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">The <code>imdb</code> provider needs no key</p>
|
||||
<p>It replaces the earlier <code>imdbapi</code> provider, which read a third-party mirror
|
||||
<p>It replaces the earlier <code>imdbapi</code> metadata provider, which read a third-party mirror
|
||||
(api.tiffara.com) and needed the <code>imdb_api_enabled</code> switch. That option is gone: delete it
|
||||
from your config, where it is now ignored.</p>
|
||||
</div>
|
||||
@@ -2254,26 +2254,26 @@ from your config, where it is now ignored.</p>
|
||||
<p class="admonition-title">A different order per title kind</p>
|
||||
<p>Give a map instead of one list when the best source differs by kind. TVDB is strongest on
|
||||
series, TMDB on films. There are two kinds, <code>tv</code> and <code>movie</code>, and this example sets both
|
||||
of them and names every provider, so nothing is left to the default:</p>
|
||||
of them and names every metadata provider, so nothing is left to the default:</p>
|
||||
<div class="language-yaml highlight"><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">metadata_providers</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">tv</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">[</span><span class="nv">tvdb</span><span class="p p-Indicator">,</span><span class="w"> </span><span class="nv">tmdb</span><span class="p p-Indicator">,</span><span class="w"> </span><span class="nv">simkl</span><span class="p p-Indicator">,</span><span class="w"> </span><span class="nv">imdb</span><span class="p p-Indicator">,</span><span class="w"> </span><span class="nv">omdb</span><span class="p p-Indicator">]</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">movie</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">[</span><span class="nv">tmdb</span><span class="p p-Indicator">,</span><span class="w"> </span><span class="nv">imdb</span><span class="p p-Indicator">,</span><span class="w"> </span><span class="nv">omdb</span><span class="p p-Indicator">,</span><span class="w"> </span><span class="nv">simkl</span><span class="p p-Indicator">,</span><span class="w"> </span><span class="nv">tvdb</span><span class="p p-Indicator">]</span>
|
||||
</span></code></pre></div>
|
||||
<p>Each list is independent: it both orders and filters that kind on its own, so a provider
|
||||
you leave out of <code>tv</code> is still used for <code>movie</code>. Here TVDB is tried first for a series and
|
||||
last for a film.</p>
|
||||
<p>Each list is independent: it both orders and filters that kind on its own, so unshackle
|
||||
still uses for <code>movie</code> a metadata provider you leave out of <code>tv</code>. Here unshackle tries TVDB
|
||||
first for a series and last for a film.</p>
|
||||
<p>You do not need to give both keys, or a full list in each. A kind you leave out uses the
|
||||
default order:</p>
|
||||
<div class="language-yaml highlight"><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">metadata_providers</span><span class="p">:</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">tv</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">[</span><span class="nv">tvdb</span><span class="p p-Indicator">,</span><span class="w"> </span><span class="nv">tmdb</span><span class="p p-Indicator">]</span><span class="w"> </span><span class="c1"># movies keep the default order</span>
|
||||
</span></code></pre></div>
|
||||
<p><code>tv</code> covers every episode and <code>movie</code> covers every film. unshackle only looks up
|
||||
metadata for those two kinds, so any other key, such as <code>anime</code> or <code>music</code>, is ignored.</p>
|
||||
metadata for those two kinds, so unshackle ignores any other config key, such as <code>anime</code> or <code>music</code>.</p>
|
||||
</div>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title"><code>ipinfo_api_key</code> never touches your service sessions</p>
|
||||
<p>The token is only ever sent to <code>api.ipinfo.io</code> as a per-request <code>Authorization</code> header; it
|
||||
is <strong>never</strong> attached to your service session, so it cannot leak to a streaming provider.
|
||||
<p>unshackle sends the token only to <code>api.ipinfo.io</code>, as a per-request <code>Authorization</code> header.
|
||||
It <strong>never</strong> goes on your service HTTP session, so it cannot leak to a streaming service.
|
||||
Lookups degrade gracefully through a fallback chain: the authenticated Lite endpoint (higher
|
||||
rate limits, and ASN/continent data, but no city or region) → anonymous ipinfo →
|
||||
<code>ip-api.in</code> as a last resort.</p>
|
||||
@@ -2409,19 +2409,19 @@ result in <code>directories.cache/update_check.json</code>.</p>
|
||||
</table>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Effect of <code>set_terminal_bg</code></p>
|
||||
<p>When on, the theme's background colour is appended to the foreground styles, which makes
|
||||
<p>When on, unshackle appends the theme's background colour to the foreground styles, which makes
|
||||
the full colour palette render correctly on terminals whose <em>default</em> background differs
|
||||
from unshackle's theme. When off, such terminals can render the ASCII-art banner and
|
||||
coloured output incorrectly.</p>
|
||||
</div>
|
||||
<div class="admonition danger">
|
||||
<p class="admonition-title">Key exposure</p>
|
||||
<p>With <code>debug_keys</code> on, decryption content keys are written to the structured debug log at
|
||||
<p>With <code>debug_keys</code> on, unshackle writes the content keys to the structured debug log at
|
||||
INFO level during the DRM handshake. Treat <code>debug</code>, <code>debug_keys</code>, and the <code>unshackle_debug_*.jsonl</code> files as
|
||||
sensitive, and keep <code>redact_paths</code> enabled when sharing logs.</p>
|
||||
<p><code>debug_keys</code> affects <strong>only</strong> content-encryption keys (the <code>content_key</code>/<code>key</code> fields).
|
||||
Passwords, tokens, cookies, and session tokens are <strong>always</strong> redacted regardless of this
|
||||
setting, and KIDs, key counts, and other metadata are always logged either way.</p>
|
||||
setting, and KIDs, content key counts, and other metadata are always logged either way.</p>
|
||||
</div>
|
||||
<hr />
|
||||
<h2 id="deprecated-removed-keys">Deprecated & removed keys<a class="headerlink" href="#deprecated-removed-keys" title="Permanent link">¶</a></h2>
|
||||
|
||||
@@ -2023,7 +2023,7 @@
|
||||
<ul>
|
||||
<li><strong>Type:</strong> <code>dict</code> · <strong>Default:</strong> <code>{}</code></li>
|
||||
</ul>
|
||||
<p>TLS-fingerprinting and HTTP client settings for the rnet-based session.</p>
|
||||
<p>TLS-fingerprinting and HTTP client settings for the rnet-based HTTP session.</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
@@ -2140,24 +2140,24 @@ honours it (only when <code>network</code> is absent) but emits a <code>Deprecat
|
||||
<ul>
|
||||
<li><strong>Type:</strong> <code>dict</code> · <strong>Default:</strong> <code>{}</code></li>
|
||||
</ul>
|
||||
<p>Default HTTP headers merged into every session unshackle creates.</p>
|
||||
<p>Default HTTP headers merged into every HTTP session unshackle makes.</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">headers</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">Accept-Language</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">en-US,en;q=0.9</span>
|
||||
</span></code></pre></div>
|
||||
<div class="admonition warning">
|
||||
<p class="admonition-title">Don't set <code>Accept-Encoding</code> (and similar) here</p>
|
||||
<p>Compatibility headers such as <code>Accept-Encoding</code> are set by the rnet HTTP backend as part of
|
||||
its browser-impersonation profile; overriding them breaks the impersonation fingerprint.
|
||||
This block is for cross-service defaults only (for example <code>Accept-Language</code>,
|
||||
<code>User-Agent</code>); per-service headers belong in that service's own config.</p>
|
||||
its browser-impersonation profile. If you override them, you break the impersonation
|
||||
fingerprint. This block is for cross-service defaults only (for example <code>Accept-Language</code>,
|
||||
<code>User-Agent</code>). Per-service headers belong in that service's own config.</p>
|
||||
</div>
|
||||
<h2 id="proxy_providers"><code>proxy_providers</code><a class="headerlink" href="#proxy_providers" title="Permanent link">¶</a></h2>
|
||||
<ul>
|
||||
<li><strong>Type:</strong> <code>dict</code> · <strong>Default:</strong> <code>{}</code></li>
|
||||
</ul>
|
||||
<p>Proxy/VPN provider configuration. Each sub-key names a provider, and its block is passed
|
||||
straight to that provider's constructor. See <a href="../../../guide/proxies-and-vpn/">Proxies & VPN</a> for
|
||||
the full provider guide. Recognised providers and their exit ports:</p>
|
||||
<p>Proxy/VPN provider configuration. Each sub-key names a proxy provider, and unshackle passes its
|
||||
block straight to that provider's constructor. See <a href="../../../guide/proxies-and-vpn/">Proxies & VPN</a>
|
||||
for the full proxy provider guide. Recognised proxy providers and their exit ports:</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
@@ -2072,7 +2072,7 @@ dropped.</p>
|
||||
</span><span id="__span-0-6"><a id="__codelineno-0-6" name="__codelineno-0-6" href="#__codelineno-0-6"></a><span class="w"> </span><span class="nt">movies</span><span class="p">:</span><span class="w"> </span><span class="s">"{title}</span><span class="nv"> </span><span class="s">({year})"</span>
|
||||
</span><span id="__span-0-7"><a id="__codelineno-0-7" name="__codelineno-0-7" href="#__codelineno-0-7"></a><span class="w"> </span><span class="nt">series</span><span class="p">:</span><span class="w"> </span><span class="s">"{title}</span><span class="nv"> </span><span class="s">({year})"</span>
|
||||
</span></code></pre></div>
|
||||
<p><strong>The nested <code>folder</code> sub-key</strong> controls output subfolders and is popped out of
|
||||
<p><strong>The nested <code>folder</code> sub-key</strong> controls output subfolders, and unshackle pops it out of
|
||||
<code>output_template</code>:</p>
|
||||
<ul>
|
||||
<li>A <strong>dict</strong> sets per-kind folder templates (kinds: <code>movies</code>, <code>series</code>, <code>songs</code>, <code>albums</code>).</li>
|
||||
@@ -2104,7 +2104,7 @@ folders do not carry the part.</p>
|
||||
<div class="admonition tip">
|
||||
<p class="admonition-title"><code>{absolute}</code> counts episodes across seasons</p>
|
||||
<p><code>absolute</code> holds the absolute episode number, zero-padded to 3 digits (<code>007</code>), and is
|
||||
empty on titles that have none. It is added to the name and never replaces <code>{season}</code>
|
||||
empty on titles that have none. You add it to the name yourself, and it never replaces <code>{season}</code>
|
||||
or <code>{episode}</code>. Any series with a TVDB absolute order can use it, anime most often.
|
||||
Services can supply it, and
|
||||
<a href="../../../guide/downloading/#metadata-and-tagging"><code>--enrich</code></a> fills it in from TVDB.
|
||||
@@ -2143,7 +2143,7 @@ Use <code>{absolute?}</code> so the name stays clean when it is unknown.</p>
|
||||
<td><code>chapter_fallback_name</code></td>
|
||||
<td>str</td>
|
||||
<td><code>""</code></td>
|
||||
<td>Fallback chapter-name template, e.g. <code>"Chapter {i:02}"</code>.</td>
|
||||
<td>Fallback template for chapter names, e.g. <code>"Chapter {i:02}"</code>.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>unicode_filenames</code></td>
|
||||
@@ -2158,8 +2158,8 @@ Use <code>{absolute?}</code> so the name stays clean when it is unknown.</p>
|
||||
<li><strong>Type:</strong> <code>list</code> · <strong>Default:</strong> <code>[]</code></li>
|
||||
</ul>
|
||||
<p>Conditionally replaces <a href="#tagging-naming-keys"><code>tag</code></a> for a given download. Each rule pairs a <code>when</code>
|
||||
dict of conditions with the <code>tag</code> to use when they hold. Rules are evaluated in order and the
|
||||
first match wins; if no rule matches, the global <code>tag</code> is kept.</p>
|
||||
dict of conditions with the <code>tag</code> to use when they hold. unshackle evaluates the rules in
|
||||
order and the first match wins. If no rule matches, the global <code>tag</code> stays.</p>
|
||||
<div class="language-yaml highlight"><span class="filename">unshackle.yaml</span><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">tag_rules</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="p p-Indicator">-</span><span class="w"> </span><span class="nt">when</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">{</span><span class="nt"> title_type</span><span class="p">:</span><span class="w"> </span><span class="nv">movie</span><span class="p p-Indicator">,</span><span class="nt"> lang_tag</span><span class="p">:</span><span class="w"> </span><span class="nv">SUBBED</span><span class="w"> </span><span class="p p-Indicator">}</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="nt">tag</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">SUBMOVIES</span>
|
||||
@@ -2169,29 +2169,30 @@ first match wins; if no rule matches, the global <code>tag</code> is kept.</p>
|
||||
<p>Rule semantics:</p>
|
||||
<ul>
|
||||
<li>Every condition in <code>when</code> must hold (they are AND-ed).</li>
|
||||
<li>A value may be a scalar or a list; a list matches if <strong>any</strong> entry matches.</li>
|
||||
<li>A value can be a scalar or a list. A list matches if <strong>any</strong> entry matches.</li>
|
||||
<li>Comparison is case-insensitive string equality.</li>
|
||||
<li>The keys of <code>when</code> are the filename template variables that describe the release itself:
|
||||
<li>The keys of <code>when</code> are the filename template variables for the release itself:
|
||||
<code>title_type</code>, <code>quality</code>, <code>resolution</code>, <code>source</code>, <code>video</code>, <code>hdr</code>, <code>hfr</code>, <code>audio</code>,
|
||||
<code>audio_channels</code>, <code>audio_full</code>, <code>atmos</code>, <code>dual</code>, <code>multi</code>, <code>dubbed</code>, <code>edition</code>, <code>repack</code>,
|
||||
and <code>lang_tag</code>. Only these are available. The title's own fields (<code>title</code>, <code>year</code>, <code>season</code>,
|
||||
<code>episode</code>, and so on) are added after the rules run and cannot be matched.</li>
|
||||
<li>An unknown key in <code>when</code> is a mistake: unshackle logs a warning that names the key and skips
|
||||
that rule. A rule without conditions or without a <code>tag</code> is also warned about and skipped.</li>
|
||||
and <code>lang_tag</code>. Only these are available. unshackle adds the title's own fields (<code>title</code>,
|
||||
<code>year</code>, <code>season</code>, <code>episode</code>, and so on) after it evaluates the rules, so a condition cannot
|
||||
use them.</li>
|
||||
<li>An unknown key in <code>when</code> is a mistake: unshackle logs a warning that names the key
|
||||
and skips that rule. unshackle also warns about a rule without conditions or without a <code>tag</code>, and skips it.</li>
|
||||
</ul>
|
||||
<p>Put the more specific rules first, because the first match ends the search.</p>
|
||||
<p>Put the more specific rules first, because unshackle stops at the first match.</p>
|
||||
<div class="admonition warning">
|
||||
<p class="admonition-title">Match <code>hdr</code> on the exact value</p>
|
||||
<p>Matching is exact, and <code>hdr</code> is a composite label for Dolby Vision titles: a DV title with
|
||||
an HDR10 base layer gives <code>DV.HDR</code>, and with an HDR10+ base layer <code>DV.HDR10P</code>. Plain <code>DV</code>
|
||||
does <strong>not</strong> match those. List every variant you want, as the example above does. Note
|
||||
does <strong>not</strong> match those. Name every variant you want, as the example above does. Note
|
||||
also that HDR10 gives <code>HDR</code>, not <code>HDR10</code>. The full set of values is <code>HDR</code>, <code>HDR10P</code>, <code>DV</code>,
|
||||
<code>DV.HDR</code>, <code>DV.HDR10P</code>, and <code>HLG</code>, as listed in the
|
||||
<a href="../../../guide/output-and-naming/#template-variables">variable table</a>.</p>
|
||||
</div>
|
||||
<h3 id="operators">Operators<a class="headerlink" href="#operators" title="Permanent link">¶</a></h3>
|
||||
<p>A condition value may start with a comparison operator, which is applied to the rest of the
|
||||
value:</p>
|
||||
<p>A condition value can start with a comparison operator, which unshackle applies to the rest of
|
||||
the value:</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">tag_rules</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="p p-Indicator">-</span><span class="w"> </span><span class="nt">when</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">{</span><span class="nt"> resolution</span><span class="p">:</span><span class="w"> </span><span class="s">"<1080"</span><span class="w"> </span><span class="p p-Indicator">}</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">tag</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">SDGROUP</span>
|
||||
|
||||
@@ -2263,12 +2263,12 @@
|
||||
|
||||
|
||||
<h1 id="post-scripts">Post-download scripts<a class="headerlink" href="#post-scripts" title="Permanent link">¶</a></h1>
|
||||
<p>Run your own script when a download finishes, with unshackle's metadata passed in as
|
||||
<p>Operate your own script when a download finishes, with unshackle's metadata passed in as
|
||||
<code>{variable}</code> placeholders. Use it to hand a finished file to an uploader, send a
|
||||
notification, or start a library scan.</p>
|
||||
<h2 id="post_scripts"><code>post_scripts</code><a class="headerlink" href="#post_scripts" title="Permanent link">¶</a></h2>
|
||||
<ul>
|
||||
<li><strong>Type:</strong> <code>list[dict]</code> · <strong>Default:</strong> <code>[]</code> (no scripts run)</li>
|
||||
<li><strong>Type:</strong> <code>list[dict]</code> · <strong>Default:</strong> <code>[]</code> (unshackle operates no scripts)</li>
|
||||
</ul>
|
||||
<div class="language-yaml highlight"><span class="filename">unshackle.yaml</span><pre><span></span><code><span id="__span-0-1"><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a><span class="nt">post_scripts</span><span class="p">:</span>
|
||||
</span><span id="__span-0-2"><a id="__codelineno-0-2" name="__codelineno-0-2" href="#__codelineno-0-2"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">command</span><span class="p">:</span><span class="w"> </span><span class="s">"python</span><span class="nv"> </span><span class="s">/opt/upload.py</span><span class="nv"> </span><span class="s">{filepath}</span><span class="nv"> </span><span class="s">--service={service}</span><span class="nv"> </span><span class="s">--season={season}</span><span class="nv"> </span><span class="s">--episode={episode}</span><span class="nv"> </span><span class="s">--tmdb={tmdb}</span><span class="nv"> </span><span class="s">--subs={sidecars}"</span>
|
||||
@@ -2277,7 +2277,7 @@ notification, or start a library scan.</p>
|
||||
</span><span id="__span-0-5"><a id="__codelineno-0-5" name="__codelineno-0-5" href="#__codelineno-0-5"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">command</span><span class="p">:</span><span class="w"> </span><span class="s">"python</span><span class="nv"> </span><span class="s">/opt/notify.py</span><span class="nv"> </span><span class="s">--title={title}</span><span class="nv"> </span><span class="s">--episode={episode}"</span>
|
||||
</span></code></pre></div>
|
||||
<p>Every entry that matches the event and mode runs, so one download can feed an uploader and
|
||||
a notifier without a wrapper script. An entry may also be written as a plain string, which
|
||||
a notifier without a wrapper script. You can also write an entry as a plain string, which
|
||||
is the same as <code>{command: "...", event: success, mode: file}</code>.</p>
|
||||
<table>
|
||||
<thead>
|
||||
@@ -2305,13 +2305,13 @@ is the same as <code>{command: "...", event: success, mode: file}</code>.</p>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>An entry whose <code>event</code> or <code>mode</code> is not one of the listed values is skipped and logs a
|
||||
warning naming the bad value, once per command. An entry whose <code>command</code> cannot be split
|
||||
into arguments, such as one with an unbalanced quote, is skipped with a warning too. Neither
|
||||
stops the download or the other entries.</p>
|
||||
<p>unshackle skips an entry whose <code>event</code> or <code>mode</code> is not one of the listed values, and logs a
|
||||
warning that names the bad value, once per command. unshackle also skips an entry whose
|
||||
<code>command</code> it cannot split into arguments, such as one with an unbalanced quote, and logs a
|
||||
warning. Neither stops the download or the other entries.</p>
|
||||
<h2 id="how-the-command-runs">How the command runs<a class="headerlink" href="#how-the-command-runs" title="Permanent link">¶</a></h2>
|
||||
<p>The command is split into arguments <strong>first</strong>, and variables are substituted into those
|
||||
arguments afterwards. The process runs without a shell.</p>
|
||||
<p>unshackle splits the command into arguments <strong>first</strong>, and then substitutes the variables
|
||||
into those arguments. The process runs without a shell.</p>
|
||||
<p>This is what keeps a title like <code>Bob"; rm -rf ~</code> harmless: a value can never turn into an
|
||||
extra argument or a shell operator, and you never have to think about quoting. It also
|
||||
means a path containing spaces always arrives as a single argument on every OS.</p>
|
||||
@@ -2321,19 +2321,19 @@ means a path containing spaces always arrives as a single argument on every OS.<
|
||||
first stops a value becoming a <em>new</em> argument, but a value on its own can still be a
|
||||
whole argument. A bare <code>{title}</code> whose value is <code>--upload-file=/etc/passwd</code> would arrive
|
||||
as an option to your script, not as text. Write <code>--title={title}</code>, not a bare <code>{title}</code>,
|
||||
so a service can never forge a flag. unshackle refuses to run a command when a
|
||||
so a service can never forge a flag. unshackle refuses to operate a command when a
|
||||
substituted value would become an option-like token (one that starts with <code>-</code>), and logs
|
||||
a warning instead.</p>
|
||||
</div>
|
||||
<div class="admonition warning">
|
||||
<p class="admonition-title">No shell features, and name your interpreter</p>
|
||||
<p>Pipes, <code>&&</code>, <code>></code> redirection, <code>~</code> and globs do not work, because no shell is involved.
|
||||
<p>Pipes, <code>&&</code>, <code>></code> redirection, <code>~</code> and globs do not work, because unshackle uses no shell.
|
||||
If you want them, make the shell explicit: <code>bash -c "..."</code>.</p>
|
||||
<p>For the same reason there is no interpreter lookup. Write <code>python /opt/upload.py</code>
|
||||
rather than <code>/opt/upload.py</code>. unshackle will not guess whether you meant the system
|
||||
Python or the one in its own virtual environment.</p>
|
||||
<p>On Windows, when a <strong>fixed</strong> part of an argument contains a space, quote the whole
|
||||
argument (<code>"--out=C:\My Dir\{filename}"</code>), not just the value. Substituted values
|
||||
argument (<code>"--out=C:\My Dir\{filename}"</code>), not only the value. Substituted values
|
||||
never need quoting on any OS.</p>
|
||||
<p>On Windows, do not target a <code>.bat</code> or <code>.cmd</code> file directly. Windows runs batch files
|
||||
through <code>cmd.exe</code>, whose argument quoting differs from every other program and has a
|
||||
@@ -2352,7 +2352,7 @@ throttling them. If your script is heavy, queue the work inside it or use <code>
|
||||
</div>
|
||||
<h2 id="variables">Variables<a class="headerlink" href="#variables" title="Permanent link">¶</a></h2>
|
||||
<p>Metadata comes from the same naming context that produced the file's name, built per output
|
||||
file. So <code>{quality}</code> and <code>{hdr}</code> always describe the file being passed. Downloading
|
||||
file. So <code>{quality}</code> and <code>{hdr}</code> always give the values for the file unshackle passes in. Downloading
|
||||
<code>-q 1080,2160 -r HDR10,SDR</code> produces four files, each with its own invocation and its own
|
||||
values.</p>
|
||||
<table>
|
||||
@@ -2422,10 +2422,10 @@ values.</p>
|
||||
<div class="admonition warning">
|
||||
<p class="admonition-title">Empty variables become an empty string</p>
|
||||
<p><code>--tmdb={tmdb}</code> with no ID resolved hands your script <code>--tmdb=</code>, so treat an empty
|
||||
string as absent. Write your script to handle every variable being empty.</p>
|
||||
string as absent. Write your script to accept an empty value for every variable.</p>
|
||||
<p>Empty is common, and not only when data is missing:</p>
|
||||
<ul>
|
||||
<li>Nothing was resolved. <code>{tmdb}</code> is empty when no metadata provider found the title,
|
||||
<li>No metadata provider found an ID. <code>{tmdb}</code> is empty when no metadata provider found the title,
|
||||
the matching API key is missing, or the title is a movie you gave no ID for.</li>
|
||||
<li>The title has no such field. Movies have no <code>{season}</code> or <code>{episode}</code>, and music has
|
||||
neither.</li>
|
||||
@@ -2495,22 +2495,21 @@ puts in <code>{title}</code>.</p>
|
||||
<p><code>{year}</code> is empty when the service gives the release no year. <code>{ext}</code> is the container the
|
||||
track arrived in, such as <code>.flac</code>, because a music download is not muxed.</p>
|
||||
<h3 id="tagging-ids">Tagging IDs<a class="headerlink" href="#tagging-ids" title="Permanent link">¶</a></h3>
|
||||
<p><code>{tmdb}</code>, <code>{imdb}</code> and <code>{tvdb}</code> carry the IDs unshackle is tagging the file with, read at
|
||||
the moment the hook is dispatched rather than snapshotted at the start of the run. An
|
||||
episode's TMDB ID is resolved by the title search inside the download loop, so a hook fires
|
||||
with it already filled in.</p>
|
||||
<p><code>{tmdb}</code>, <code>{imdb}</code> and <code>{tvdb}</code> carry the IDs unshackle tags the file with. unshackle reads
|
||||
them at the moment it sends the hook, and not at the start of the run. The title search inside
|
||||
the download loop finds an episode's TMDB ID, so a hook fires with it already filled in.</p>
|
||||
<p>They hold an ID you passed with <code>--tmdb</code>, <code>--imdb</code> or <code>--tvdb</code>, plus a TMDB ID the episode
|
||||
search resolved. No such search runs for a movie, so a movie hook gets them empty unless you
|
||||
passed one.</p>
|
||||
<h3 id="sidecar-files">Sidecar files<a class="headerlink" href="#sidecar-files" title="Permanent link">¶</a></h3>
|
||||
<p><code>{sidecars}</code> holds the sidecar subtitle files written beside the output, which are the only
|
||||
extra files a download leaves next to it. Attachments such as fonts are muxed into the
|
||||
container and temporary artwork is deleted, so neither appears. Expect <code>{sidecars}</code> to be
|
||||
extra files a download leaves next to it. unshackle muxes attachments such as fonts into the
|
||||
container and deletes temporary artwork, so neither appears. Expect <code>{sidecars}</code> to be
|
||||
empty unless <a href="../download/#subtitle"><code>subtitle.output_mode</code></a> is <code>sidecar</code> or <code>both</code>, which is
|
||||
not the default. A music download writes no sidecars at all.</p>
|
||||
<p>Paths are absolute and separated by a newline, because a newline is the only character that
|
||||
cannot appear in a filename on any supported OS. The whole list arrives as a single
|
||||
argument, so no quoting is needed in your template.</p>
|
||||
argument, so your template needs no quoting.</p>
|
||||
<p>When one download writes several outputs (<code>-q 1080,720</code>), each output's folder gets its own
|
||||
copy of the sidecar files, and each invocation lists the copies sitting beside its own
|
||||
<code>{filepath}</code>.</p>
|
||||
@@ -2558,7 +2557,7 @@ that title and then returns. It downloads no further title, and no <code>season<
|
||||
hook fires after that point. This applies to every title type. If one episode of S01
|
||||
fails, the S01 hook does not fire at all.</p>
|
||||
</div>
|
||||
<p>The hook is keyed to the folder, not to the season, so one season landing in several
|
||||
<p>unshackle attaches the hook to the folder, not to the season, so one season landing in several
|
||||
folders (<code>-q 1080,720</code> with a quality-dependent folder template) fires it once per folder,
|
||||
each with its own <code>{folder}</code>. A movie is a group of its own: a <code>season</code> hook fires for a
|
||||
movie's folder as soon as the movie finishes.</p>
|
||||
@@ -2611,9 +2610,9 @@ title object already knew: <code>{title}</code>, <code>{title_raw}</code>, <code
|
||||
<code>{episode}</code>, <code>{episode_name}</code>, <code>{service}</code>, the tagging IDs and <code>{error}</code>. Everything that
|
||||
comes from the naming context, such as <code>{quality}</code>, <code>{hdr}</code>, <code>{artist}</code> and <code>{album}</code>, is
|
||||
empty.</p>
|
||||
<p>A resumed <code>--continue</code> download that finishes runs <code>success</code> as usual. Because unshackle
|
||||
does not wait for your script, it never sees its exit code, so a failing script is not
|
||||
reported anywhere. Your script owns its own error handling and logging.</p>
|
||||
<p>A resumed <code>--continue-downloads</code> download that finishes runs <code>success</code> as usual. Because
|
||||
unshackle does not wait for your script, it never sees its exit code, so a failing script
|
||||
is not reported anywhere. Your script owns its own error handling and logging.</p>
|
||||
<p>A <code>success</code> hook always names a file this run wrote. There is no skip-if-exists path in
|
||||
<code>dl</code> today, so nothing fires for a title that was not downloaded.</p>
|
||||
<h2 id="-postscript"><code>--postscript</code><a class="headerlink" href="#-postscript" title="Permanent link">¶</a></h2>
|
||||
@@ -2626,29 +2625,30 @@ configured entry runs while it is in use. That includes your <code>season</code>
|
||||
entries, which have no <code>--postscript</code> equivalent.</p>
|
||||
<h2 id="the-rest-api">The REST API<a class="headerlink" href="#the-rest-api" title="Permanent link">¶</a></h2>
|
||||
<p>The API never accepts a post-script command. <code>postscript</code>, <code>post_script</code> and <code>post_scripts</code>
|
||||
in a <code>POST /api/download</code> body are rejected with <code>400 INVALID_PARAMETERS</code>, because a command
|
||||
arriving from an HTTP caller would be remote code execution.</p>
|
||||
<p>Scripts defined in <code>unshackle.yaml</code> do run for API jobs, music jobs included. Only the
|
||||
in a <code>POST /api/download</code> body get <code>400 INVALID_PARAMETERS</code>. A command that arrives from an
|
||||
HTTP caller would be remote code execution.</p>
|
||||
<p>unshackle does operate the scripts defined in <code>unshackle.yaml</code> for API jobs, music jobs
|
||||
included. Only the
|
||||
command itself may not cross the network.</p>
|
||||
<h2 id="logging">Logging<a class="headerlink" href="#logging" title="Permanent link">¶</a></h2>
|
||||
<p>The command that was run is logged twice: at <code>DEBUG</code> level on the console, and as a
|
||||
<p>unshackle logs the command it operated twice: at <code>DEBUG</code> level on the console, and as a
|
||||
<code>post_script_dispatch</code> entry in the
|
||||
<a href="../../../guide/troubleshooting/#the-structured-json-debug-log">structured JSON debug log</a>
|
||||
when that log is enabled.</p>
|
||||
<p>Both are masked the same way, honouring <a href="../misc/"><code>redact_paths</code></a>, which is on by default.
|
||||
when that log is on.</p>
|
||||
<p>unshackle masks both the same way, and honours <a href="../misc/"><code>redact_paths</code></a>, which is on by default.
|
||||
Debug logs get shared in issue reports, and a hook command line is mostly paths. URL
|
||||
credentials and <code>token=</code> / <code>api_key=</code> query parameters are also masked.</p>
|
||||
<div class="admonition warning">
|
||||
<p class="admonition-title">Do not hardcode secrets in the command</p>
|
||||
<p>An arbitrary secret in the command line, such as <code>-H "Authorization: Bearer <key>"</code>,
|
||||
cannot be recognised and is logged verbatim. Read the secret from a file or an
|
||||
<p>unshackle cannot recognise an arbitrary secret in the command line, such as
|
||||
<code>-H "Authorization: Bearer <key>"</code>, and logs it verbatim. Read the secret from a file or an
|
||||
environment variable inside your script rather than putting it in the <code>command</code>.</p>
|
||||
</div>
|
||||
<h2 id="limitations">Limitations<a class="headerlink" href="#limitations" title="Permanent link">¶</a></h2>
|
||||
<ul>
|
||||
<li>No <code>success</code> hooks run under <code>--no-mux</code> or <code>--skip-dl</code>, because neither writes a muxed
|
||||
<li>No <code>success</code> hook operates under <code>--no-mux</code> or <code>--skip-dl</code>, because neither writes a muxed
|
||||
output. A <code>failure</code> hook still runs under <code>--no-mux</code> if the download itself fails.</li>
|
||||
<li><code>failure</code> hooks only run in <code>file</code> mode.</li>
|
||||
<li><code>failure</code> hooks only operate in <code>file</code> mode.</li>
|
||||
<li>There is no webhook sender. Call <code>curl</code> from a script instead.</li>
|
||||
<li>Script output is not captured. Redirect it inside your own script if you want a log.</li>
|
||||
</ul>
|
||||
|
||||
@@ -2070,18 +2070,18 @@
|
||||
<p>Per-service configuration, keyed by the canonical service tag (for example <code>EXAMPLE1</code>, <code>EXAMPLE2</code>,
|
||||
<code>EXAMPLE3</code>). unshackle reads several well-known sub-keys out of each service's block:</p>
|
||||
<ul>
|
||||
<li><strong><code>proxy_map</code></strong>: remaps the region query you passed to <code>-p/--proxy</code> for this service. A key is
|
||||
that query, or <code>"provider:query"</code> when the flag also named a provider; the value is the query
|
||||
asked of the proxy provider instead. It has no effect when <code>-p</code> was given a full proxy URL.</li>
|
||||
<li><strong><code>proxy_map</code></strong>: remaps the region query you passed to <code>-p/--proxy</code> for this service.
|
||||
A config key is that query, or <code>"provider:query"</code> when the flag also named a proxy provider. The value is
|
||||
the query asked of the proxy provider instead. It has no effect when you give <code>-p</code> a full proxy URL.</li>
|
||||
<li><strong><code>title_map</code></strong>: an exact-match rename map applied to fetched titles (source name →
|
||||
desired name), so a service that names a title differently from your library still matches.</li>
|
||||
<li><strong><code>dl</code></strong>: per-service download defaults, using the same keys as the global
|
||||
<a href="../download/#dl"><code>dl</code></a> block.</li>
|
||||
</ul>
|
||||
<p>Individual services may read any additional keys they define. The merged result (the service's
|
||||
own <code>config.yaml</code> with this block layered on top) is handed to the service as <code>self.config</code>.</p>
|
||||
<p>Individual services may read any additional keys they define. unshackle hands the merged result
|
||||
(the service's own <code>config.yaml</code> with this block layered on top) to the service as <code>self.config</code>.</p>
|
||||
<p>User- or device-specific values (API keys, account IDs, device attributes) belong in this block
|
||||
rather than in the service's own <code>config.yaml</code>, which holds shared defaults; see
|
||||
rather than in the service's own <code>config.yaml</code>, which holds shared defaults. See
|
||||
<a href="../../../dev/creating-a-service/">creating a service</a>.</p>
|
||||
<div class="language-yaml highlight"><pre><span></span><code><span id="__span-0-1"><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a><span class="nt">services</span><span class="p">:</span>
|
||||
</span><span id="__span-0-2"><a id="__codelineno-0-2" name="__codelineno-0-2" href="#__codelineno-0-2"></a><span class="w"> </span><span class="nt">EXAMPLE1</span><span class="p">:</span>
|
||||
@@ -2097,10 +2097,10 @@ rather than in the service's own <code>config.yaml</code>, which holds shared de
|
||||
</ul>
|
||||
<p>Per-service login credentials. Each value is a <code>username:password[:extra]</code> string, the same
|
||||
data as a <code>[username, password]</code> (or <code>[username, password, extra]</code>) list, or a dict of profile
|
||||
name to either of those. With the dict form, <code>-p/--profile</code> selects the entry, and the
|
||||
<code>default</code> key is used when no profile was given or the named profile is missing. These are
|
||||
parsed into <code>Credential</code> objects; the credential's SHA-1 is also used as an account hash for
|
||||
cache keys.</p>
|
||||
name to either of those. With the dict form, <code>-p/--profile</code> selects the entry, and unshackle
|
||||
uses the <code>default</code> config key when you give no profile, or when the named profile is missing.
|
||||
unshackle parses these into <code>Credential</code> objects. It also uses the credential's SHA-1 as an
|
||||
account hash for cache keys.</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">credentials</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">EXAMPLE2</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">user@example.com:hunter2</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="nt">EXAMPLE1</span><span class="p">:</span>
|
||||
@@ -2109,22 +2109,22 @@ cache keys.</p>
|
||||
</span></code></pre></div>
|
||||
<div class="admonition tip">
|
||||
<p class="admonition-title">Cookies vs credentials</p>
|
||||
<p>Cookies are stored as files under <a href="../directories/"><code>directories.cookies</code></a>, not in this key.
|
||||
<p>unshackle stores cookies as files under <a href="../directories/"><code>directories.cookies</code></a>, not in this config key.
|
||||
A service's <code>authenticate()</code> accepts cookies, credentials, or both.</p>
|
||||
</div>
|
||||
<h2 id="firefox_cookies"><code>firefox_cookies</code><a class="headerlink" href="#firefox_cookies" title="Permanent link">¶</a></h2>
|
||||
<ul>
|
||||
<li><strong>Type:</strong> <code>dict</code> keyed by service tag · <strong>Default:</strong> <code>{}</code></li>
|
||||
</ul>
|
||||
<p>Settings for extracting cookies directly from a local Firefox profile. A service block is
|
||||
expected to provide <code>hosts</code> (a list of cookie hostnames; entries shorter than 3 characters
|
||||
are ignored to prevent dumping the whole cookie store) and an optional <code>local_storage</code>
|
||||
boolean to also pull matching entries from <code>webappsstore.sqlite</code>, which only services that
|
||||
keep auth tokens in localStorage rather than in HTTP cookies need. Extraction is read-only.</p>
|
||||
<p>Settings for extracting cookies directly from a local Firefox profile. A service block must give
|
||||
<code>hosts</code>, a list of cookie hostnames. unshackle ignores an entry shorter than 3 characters, to
|
||||
prevent a broad match dumping most of the profile. With an optional <code>local_storage</code> boolean,
|
||||
unshackle also pulls matching entries from <code>webappsstore.sqlite</code>, which only services that keep
|
||||
auth tokens in localStorage rather than in HTTP cookies need. Extraction is read-only.</p>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Firefox does not need to be closed</p>
|
||||
<p>The extractor copies <strong>both</strong> <code>cookies.sqlite</code> <strong>and</strong> its WAL file into a <code>0700</code> temp
|
||||
directory, so writes Firefox has not yet flushed to the main DB are included. Extraction
|
||||
directory, so the copy holds the writes Firefox has not yet flushed to the main DB. Extraction
|
||||
fails only if Firefox holds an exclusive write lock at the instant of the copy. The live
|
||||
profile is not modified.</p>
|
||||
</div>
|
||||
@@ -2139,19 +2139,19 @@ to the normal file-based cookie path (<code>cookies/<SERVICE>.txt</code> o
|
||||
<li><strong>Type:</strong> <code>dict</code> · <strong>Default:</strong> <code>{}</code></li>
|
||||
</ul>
|
||||
<p>Definitions of remote unshackle service servers, used by the <code>--remote</code> mode. Each entry is
|
||||
named by you (pick it with <code>--server</code>, or omit that flag when only one is configured) and gives
|
||||
named by you (pick it with <code>--server</code>, or do not write that flag when you configure only one) and gives
|
||||
the server's <code>url</code> (required), an optional <code>api_key</code>, an optional <code>auth_headers</code> list, an
|
||||
optional <code>server_cdm</code> boolean, and an optional <code>services</code> sub-dict of per-service local
|
||||
overrides such as <code>title_map</code>.</p>
|
||||
<p><code>auth_headers</code> lists extra header names to send the API key in, tried before the defaults
|
||||
<code>X-Secret-Key</code> and <code>X-Api-Key</code>, which are always appended as fallbacks. unshackle sends the
|
||||
first name; if the server answers <code>401</code>, it retries the same request with the next name, and
|
||||
keeps the one that works for the rest of the session. Names you list keep your spelling and are
|
||||
not repeated in the fallbacks, so <code>auth_headers: ["Authorization", "x-secret-key"]</code> is tried as
|
||||
<code>Authorization</code>, <code>x-secret-key</code>, <code>X-Api-Key</code>.</p>
|
||||
first name. If the server answers <code>401</code>, it retries the same request with the next name, and
|
||||
keeps the one that works for the rest of the HTTP session. Names you give keep your spelling and
|
||||
are not repeated in the fallbacks, so unshackle tries
|
||||
<code>auth_headers: ["Authorization", "x-secret-key"]</code> as <code>Authorization</code>, <code>x-secret-key</code>, <code>X-Api-Key</code>.</p>
|
||||
<p>In <code>--remote</code> mode unshackle turns the server's service list into synthetic CLI
|
||||
commands that run against it, falling back to the tags in that <code>services</code> sub-dict when the
|
||||
list cannot be fetched. Each synthetic command carries the server-side service's options and
|
||||
commands that operate against it, falling back to the tags in that <code>services</code> sub-dict when
|
||||
unshackle cannot fetch the list. Each synthetic command carries the server-side service's options and
|
||||
documentation, so <code>unshackle dl --remote <TAG> -h</code> shows the same help text as it does on the
|
||||
server. See <a href="../../../dev/rest-api/remote-sessions/">remote sessions</a> for the
|
||||
full setup.</p>
|
||||
@@ -2160,7 +2160,7 @@ full setup.</p>
|
||||
<li><strong>Type:</strong> <code>dict</code> · <strong>Default:</strong> <code>{}</code></li>
|
||||
</ul>
|
||||
<p>Configuration for the <code>serve</code> command (the built-in REST API server). The full server guide
|
||||
is the <a href="../../../dev/rest-api/">REST API</a> section; these are the config keys.</p>
|
||||
is the <a href="../../../dev/rest-api/">REST API</a> section. These are the config keys.</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
@@ -2251,14 +2251,15 @@ is the <a href="../../../dev/rest-api/">REST API</a> section; these are the conf
|
||||
</tr>
|
||||
</tbody>
|
||||
</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> uses that user's API key as its name, and can set its own <code>services</code>,
|
||||
<code>devices</code>, and <code>playready_devices</code> allowlists, narrowing the global ones, plus an optional
|
||||
<code>username</code> used as the log label for that key (defaults to a truncated form of the key). A
|
||||
user with no <code>playready_devices</code> key gets no PlayReady access at all, not the global list.</p>
|
||||
<p><code>server_cdm</code> decides whether the server runs the CDM licensing for that key. It is <code>false</code>
|
||||
<code>username</code> used as the log label for that API key (defaults to a truncated form of the API key).
|
||||
A user with no <code>playready_devices</code> config key gets no PlayReady access at all, not the global
|
||||
list.</p>
|
||||
<p><code>server_cdm</code> decides whether the server runs the CDM licensing for that API key. It is <code>false</code>
|
||||
unless the entry sets it, so a remote client configured with <code>server_cdm: true</code> is told to
|
||||
license with its own local CDM instead, and a client that asks anyway gets a <code>FORBIDDEN</code>
|
||||
error. Because a download job always licenses with the server's CDM, a key without
|
||||
error. Because a download job always licenses with the server's CDM, an API key without
|
||||
<code>server_cdm</code> also cannot submit or retry <code>/api/download</code> jobs. Keys that have no <code>users</code>
|
||||
entry, such as <code>api_secret</code>, keep server CDM access.</p>
|
||||
<div class="language-yaml highlight"><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">serve</span><span class="p">:</span>
|
||||
|
||||
@@ -2002,9 +2002,9 @@
|
||||
<ul>
|
||||
<li><strong>Type:</strong> <code>list[dict]</code> · <strong>Default:</strong> <code>[]</code></li>
|
||||
</ul>
|
||||
<p>An ordered list of key-vault backends. unshackle queries them in order and reuses content
|
||||
keys instead of re-licensing. Each entry needs a <code>type</code> (the backend module name) and a
|
||||
<code>name</code>, plus backend-specific keys.</p>
|
||||
<p>An ordered list of key-vault backends. unshackle queries them in order and reuses the
|
||||
content keys instead of licensing them again. Each entry needs a <code>type</code> (the backend module
|
||||
name) and a <code>name</code>, plus backend-specific keys.</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
@@ -2056,12 +2056,12 @@ keys instead of re-licensing. Each entry needs a <code>type</code> (the backend
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Per-entry options</p>
|
||||
<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 (unshackle fetches content keys from it but never writes 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
|
||||
<a href="../misc/#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
|
||||
stored.</li>
|
||||
<li>unshackle treats an all-zero content key (32 zeros) as "no key" everywhere and never
|
||||
stores it.</li>
|
||||
</ul>
|
||||
</div>
|
||||
<h2 id="vault_timeout"><code>vault_timeout</code><a class="headerlink" href="#vault_timeout" title="Permanent link">¶</a></h2>
|
||||
|
||||
Reference in New Issue
Block a user