Deployed 40cad41 with MkDocs version: 1.6.1

This commit is contained in:
2026-08-26 01:20:34 +00:00
parent c889ec725a
commit f12f423434
4 changed files with 100 additions and 49 deletions
+62 -11
View File
@@ -1265,6 +1265,23 @@
</span>
</a>
<nav class="md-nav" aria-label="How the command runs">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#wait" class="md-nav__link">
<span class="md-ellipsis">
Waiting for a script
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
@@ -2107,6 +2124,23 @@
</span>
</a>
<nav class="md-nav" aria-label="How the command runs">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#wait" class="md-nav__link">
<span class="md-ellipsis">
Waiting for a script
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
@@ -2303,6 +2337,11 @@ is the same as <code>{command: "...", event: success, mode: file}</code>.</p>
<td><code>file</code></td>
<td><code>file</code>, <code>season</code>, or <code>run</code>. See <a href="#modes">Modes</a></td>
</tr>
<tr>
<td><code>wait</code></td>
<td><code>false</code></td>
<td><code>true</code> makes unshackle wait for the script to exit before carrying on. See <a href="#wait">Waiting for a script</a></td>
</tr>
</tbody>
</table>
<p>unshackle skips an entry whose <code>event</code> or <code>mode</code> is not one of the listed values, and logs a
@@ -2340,16 +2379,27 @@ through <code>cmd.exe</code>, whose argument quoting differs from every other pr
history of letting a crafted value break out (CVE-2024-3566). Call the interpreter and
pass the script as an argument (<code>python upload.py</code>, <code>pwsh -File upload.ps1</code>) instead.</p>
</div>
<p>Scripts are fire and forget. unshackle starts the process, writes the command to the debug
log, and carries on. It does not wait for the script, capture its output, time it out, or
change its own exit code when a script fails. A script keeps running if unshackle exits
first, and <kbd>Ctrl</kbd>+<kbd>C</kbd> during a season pack does not kill the scripts
already started.</p>
<p>By default, scripts are fire and forget. unshackle starts the process, writes the command to
the debug log, and carries on. It does not wait for the script, capture its output, time it
out, or change its own exit code when a script fails. A script keeps running if unshackle
exits first, and <kbd>Ctrl</kbd>+<kbd>C</kbd> during a season pack does not kill the
scripts already started.</p>
<div class="admonition note">
<p class="admonition-title">One process per file</p>
<p>In <code>file</code> mode a large season pack starts one process per episode with nothing
throttling them. If your script is heavy, queue the work inside it or use <code>mode: season</code>.</p>
throttling them. If your script is heavy, set <code>wait: true</code>, queue the work inside the
script, or use <code>mode: season</code>.</p>
</div>
<h3 id="wait">Waiting for a script<a class="headerlink" href="#wait" title="Permanent link">&para;</a></h3>
<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">post_scripts</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">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">--file={filepath}"</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">wait</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">true</span>
</span></code></pre></div>
<p>With <code>wait: true</code>, unshackle waits until the script exits, then writes the exit code to the
debug log and carries on. Because the <code>file</code> hook runs between titles, unshackle runs one
script at a time over a season pack instead of starting them all at once. unshackle only
logs the exit code: a failing script does not fail the download or change unshackle's own
exit code. <code>--postscript</code> entries never wait.</p>
<h2 id="variables">Variables<a class="headerlink" href="#variables" title="Permanent link">&para;</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 give the values for the file unshackle passes in. Downloading
@@ -2513,7 +2563,7 @@ 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>
<div class="language-python highlight"><span class="filename">Reading {sidecars} in Python</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="n">subs</span> <span class="o">=</span> <span class="p">[</span><span class="n">p</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">.</span><span class="n">removeprefix</span><span class="p">(</span><span class="s2">"--subs="</span><span class="p">)</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">)</span> <span class="k">if</span> <span class="n">p</span><span class="p">]</span>
<div class="language-python highlight"><span class="filename">Reading {sidecars} in Python</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="n">subs</span> <span class="o">=</span> <span class="p">[</span><span class="n">p</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">.</span><span class="n">removeprefix</span><span class="p">(</span><span class="s2">"--subs="</span><span class="p">)</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">)</span> <span class="k">if</span> <span class="n">p</span><span class="p">]</span>
</span></code></pre></div>
<h2 id="modes">Modes<a class="headerlink" href="#modes" title="Permanent link">&para;</a></h2>
<table>
@@ -2610,15 +2660,16 @@ 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-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 resumed <code>--continue-downloads</code> download that finishes runs <code>success</code> as usual. unshackle
sees your script's exit code only when that entry sets <code>wait: true</code>, and even then it only
writes the code to the debug log. Nothing else reports a failing script. 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">&para;</a></h2>
<p><code>dl</code> accepts <code>--postscript "&lt;command&gt;"</code>, repeatable. Every command given this way runs with
<code>event: success</code> and <code>mode: file</code>.</p>
<div class="language-console 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="gp">$ </span>unshackle<span class="w"> </span>dl<span class="w"> </span>--postscript<span class="w"> </span><span class="s2">"python /opt/upload.py {filepath}"</span><span class="w"> </span>SERVICE<span class="w"> </span>TITLE_ID
<div class="language-console 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="gp">$ </span>unshackle<span class="w"> </span>dl<span class="w"> </span>--postscript<span class="w"> </span><span class="s2">"python /opt/upload.py {filepath}"</span><span class="w"> </span>SERVICE<span class="w"> </span>TITLE_ID
</span></code></pre></div>
<p>It replaces the <code>post_scripts</code> config for that run rather than adding to it, so no
configured entry runs while it is in use. That includes your <code>season</code>, <code>run</code> and <code>failure</code>