Deployed 8b10b79 with MkDocs version: 1.6.1

This commit is contained in:
2026-08-20 03:01:15 +00:00
parent 01248725da
commit 94f2b09ef6
40 changed files with 1967 additions and 1920 deletions
+24 -24
View File
@@ -2067,14 +2067,14 @@
<h1 id="rest-api-overview">REST API Overview<a class="headerlink" href="#rest-api-overview" title="Permanent link">&para;</a></h1>
<p>unshackle ships with a built-in HTTP server. Alongside the command-line tool, you
can run <code>unshackle serve</code> and drive the same download engine over a REST API:
can operate <code>unshackle serve</code> and drive the same download engine over a REST API:
searching services, listing titles and tracks, queueing downloads, watching live
progress, and browsing history, all as JSON over HTTP.</p>
<p>This page explains what the API is for, how to start the server, where it listens,
and how the endpoints are organised. Later pages cover each area in depth.</p>
<div class="admonition info">
<p class="admonition-title">Who this section is for</p>
<p>The REST API is aimed at people building automation, dashboards, or remote
<p>The REST API is for people who make automation, dashboards, or remote
clients on top of unshackle. If you only download the occasional title, the
<a href="../../guide/cli-reference/">command-line tool</a> does everything the API does
and is simpler to use. Reach for the API when you want a long-running service, a
@@ -2084,20 +2084,20 @@ job queue, or a web front-end.</p>
<p>The server exposes the same capabilities as the <code>dl</code> command, but as discrete HTTP
calls you can script against:</p>
<ul>
<li><strong>Discovery</strong>: list the services available on the server, run a service's search,
<li><strong>Discovery</strong>: show the services available on the server, use a service's search,
and enumerate the titles and tracks behind a title ID.</li>
<li><strong>Downloading</strong>: submit a download as a background <em>job</em>, then follow its status and
live progress (by polling, or by subscribing to its Server-Sent Events stream),
cancel it, retry it, or bump it to the front of the queue.</li>
<li><strong>History and housekeeping</strong>: read the log of finished jobs, inspect the server's
effective (redacted) configuration, check external tool versions, and clear caches
effective (redacted) configuration, examine external tool versions, and clear caches
or temp files.</li>
<li><strong>Remote-download sessions</strong>: a thin local client can authenticate against a
service <em>on the server</em>, then pull titles, tracks, and segment info back, and proxy
DRM licensing. This is how one machine with the credentials and CDMs can serve
downloads to another. See <a href="remote-sessions/">Remote Sessions</a>.</li>
</ul>
<p>Because every download runs as a queued job in a separate worker process, the API is
<p>Because every download runs as a queued job in a separate job worker process, the API is
well suited to running unattended: submit work, come back later, and read the result.</p>
<h2 id="running-the-server">Running the server<a class="headerlink" href="#running-the-server" title="Permanent link">&para;</a></h2>
<p>Start the server with the <code>serve</code> command:</p>
@@ -2181,24 +2181,24 @@ how the <code>X-Secret-Key</code> header works.</p>
<div class="admonition danger">
<p class="admonition-title">Binding to a public interface</p>
<p><code>--no-key</code> disables authentication completely. Anyone who can reach the port can
search, download, and read your configuration. Only combine it with a host like
find titles, download them, and read your configuration. Only combine it with a host like
<code>127.0.0.1</code>, or keep the default key-based auth when binding to <code>0.0.0.0</code>. Put a
TLS-terminating reverse proxy (Caddy, nginx) in front for anything internet-facing.</p>
</div>
<h3 id="server-modes">Server modes<a class="headerlink" href="#server-modes" title="Permanent link">&para;</a></h3>
<p>The set of routes that is actually mounted depends on how you start the server:</p>
<p>The routes the server mounts depend on how you start the server:</p>
<div class="tabbed-set tabbed-alternate" data-tabs="1:3"><input checked="checked" id="__tabbed_1_1" name="__tabbed_1" type="radio" /><input id="__tabbed_1_2" name="__tabbed_1" type="radio" /><input id="__tabbed_1_3" name="__tabbed_1" type="radio" /><div class="tabbed-labels"><label for="__tabbed_1_1">Default (CDM + REST)</label><label for="__tabbed_1_2"><code>--api-only</code></label><label for="__tabbed_1_3"><code>--remote-only</code></label></div>
<div class="tabbed-content">
<div class="tabbed-block">
<p>Both the pywidevine/pyplayready CDM endpoints and the full REST API are mounted.
This is the mode used when you run <code>unshackle serve</code> with no mode flags.</p>
<p>The server mounts both the pywidevine/pyplayready CDM endpoints and the full REST API.
This is the mode you get when you operate <code>unshackle serve</code> with no mode flags.</p>
</div>
<div class="tabbed-block">
<p>Only the REST API is mounted; the CDM HTTP endpoints are omitted. Authentication
uses the single configured API key (or none, with <code>--no-key</code>).</p>
<p>The server mounts only the REST API. It does not mount the CDM HTTP endpoints.
Authentication uses the single configured API key (or none, with <code>--no-key</code>).</p>
</div>
<div class="tabbed-block">
<p>Only the remote-session subset of routes is exposed (health, services, search,
<p>The server mounts only the remote-session subset of routes (health, services, search,
and everything under <code>/api/session/*</code>). This mode implies <code>--api-only</code>, and the
interactive Swagger UI is <strong>not</strong> mounted.</p>
</div>
@@ -2214,12 +2214,12 @@ health check is <code>GET http://127.0.0.1:8786/api/health</code>.</p>
<div class="admonition tip">
<p class="admonition-title">Interactive API docs</p>
<p>Unless you started the server with <code>--remote-only</code>, an interactive Swagger UI is
available at <a href="http://127.0.0.1:8786/api/docs/"><code>/api/docs/</code></a>. It is generated from
the same route table the server actually serves, so it stays in sync with the
running build. Note that in <code>--api-only</code> mode the docs page is itself behind the
API key; only <code>/api/health</code> is exempt from authentication.</p>
available at <a href="http://127.0.0.1:8786/api/docs/"><code>/api/docs/</code></a>. The server generates
it from the same route table it serves, so it always matches the version you
operate. Note that in <code>--api-only</code> mode the docs page is itself behind the
API key. Only <code>/api/health</code> is exempt from authentication.</p>
</div>
<p>A quick smoke test that needs no key:</p>
<p>A quick smoke test that needs no API key:</p>
<div class="language-shell highlight"><span class="filename">Confirm the server is up</span><pre><span></span><code><span id="__span-3-1"><a id="__codelineno-3-1" name="__codelineno-3-1" href="#__codelineno-3-1"></a>curl<span class="w"> </span>http://127.0.0.1:8786/api/health
</span></code></pre></div>
<div class="language-json highlight"><span class="filename">Response</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="p">{</span>
@@ -2234,7 +2234,7 @@ API key; only <code>/api/health</code> is exempt from authentication.</p>
</span></code></pre></div>
<h2 id="endpoint-map">Endpoint map<a class="headerlink" href="#endpoint-map" title="Permanent link">&para;</a></h2>
<p>Every REST path uses JSON request and response bodies and lives under <code>/api</code>. The
table below is a map of the surface; the <a href="endpoints/">Endpoints</a> page documents each
table below is a map of the surface. The <a href="endpoints/">Endpoints</a> page gives each
request and response in full.</p>
<h3 id="discovery">Discovery<a class="headerlink" href="#discovery" title="Permanent link">&para;</a></h3>
<table>
@@ -2249,7 +2249,7 @@ request and response in full.</p>
<tr>
<td><code>GET</code></td>
<td><code>/api/health</code></td>
<td>Liveness and version check. Never requires a key.</td>
<td>Liveness and version check. Never requires an API key.</td>
</tr>
<tr>
<td><code>GET</code></td>
@@ -2407,7 +2407,7 @@ request and response in full.</p>
<tr>
<td><code>GET</code></td>
<td><code>/api/session/{session_id}</code></td>
<td>Session info and time-to-live.</td>
<td>Remote session info and time-to-live.</td>
</tr>
<tr>
<td><code>DELETE</code></td>
@@ -2460,13 +2460,13 @@ every request except <code>/api/health</code>:</p>
</span><span id="__span-5-3"><a id="__codelineno-5-3" name="__codelineno-5-3" href="#__codelineno-5-3"></a><span class="w"> </span>-H<span class="w"> </span><span class="s2">"Content-Type: application/json"</span><span class="w"> </span><span class="se">\</span>
</span><span id="__span-5-4"><a id="__codelineno-5-4" name="__codelineno-5-4" href="#__codelineno-5-4"></a><span class="w"> </span>-d<span class="w"> </span><span class="s1">'{"service": "EXAMPLE", "query": "example"}'</span>
</span></code></pre></div>
<p>A missing or unknown key returns <code>401</code>. The full model, including per-key service
allowlists, is covered in <a href="authentication/">Authentication</a>.</p>
<p>A missing or unknown API key returns <code>401</code>. <a href="authentication/">Authentication</a> gives
the full model, including per-key service allowlists.</p>
<h2 id="where-to-go-next">Where to go next<a class="headerlink" href="#where-to-go-next" title="Permanent link">&para;</a></h2>
<div class="grid cards">
<ul>
<li><strong><a href="quickstart/">Quick Start</a></strong>: start the server, set a key, and run your first
end-to-end download over the API.</li>
<li><strong><a href="quickstart/">Quick Start</a></strong>: start the server, set an API key, and operate your
first end-to-end download over the API.</li>
<li><strong><a href="authentication/">Authentication</a></strong>: the <code>X-Secret-Key</code> header, <code>--no-key</code>,
per-key service allowlists, and CORS.</li>
<li><strong><a href="endpoints/">Endpoints</a></strong>: every request body, query parameter, and response