Deployed 09cae2e with MkDocs version: 1.6.1

This commit is contained in:
2026-10-07 17:16:14 +00:00
parent 53e2d835d3
commit fbb818e18b
7 changed files with 414 additions and 358 deletions
+4 -1
View File
@@ -2662,7 +2662,10 @@ returns a value. <code>check</code> returns <code>None</code> while the approval
<p>It raises <code>TimeoutError</code> after <code>timeout</code> seconds. Under <code>serve</code> mode it also stops
when the client deletes the remote session, so the loop does not continue on the
server with no client. The message goes out as a log line, so a remote
session shows it, but a REST download job does not relay it as <code>input_prompt</code>.</p>
session shows it. A REST download job shows it in its <code>notice</code> field until the wait ends.</p>
<p>The wait sees a cancel only between two <code>check</code> calls, so <code>check</code> must return within a few
seconds. A <code>check</code> that reads a socket keeps the socket open across calls and returns <code>None</code>
after each short idle wait.</p>
<div class="admonition warning">
<p class="admonition-title">Make each token cache entry unique</p>
<p>The cache above uses <code>tokens_{device}_{profile}</code> on purpose. A token cache
+35 -4
View File
@@ -1664,6 +1664,17 @@
<nav class="md-nav" aria-label="POST /api/list-titles">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#logins-that-need-the-user" class="md-nav__link">
<span class="md-ellipsis">
Logins that need the user
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#client-cache-on-a-remote-only-server" class="md-nav__link">
<span class="md-ellipsis">
@@ -2557,6 +2568,17 @@
<nav class="md-nav" aria-label="POST /api/list-titles">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#logins-that-need-the-user" class="md-nav__link">
<span class="md-ellipsis">
Logins that need the user
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#client-cache-on-a-remote-only-server" class="md-nav__link">
<span class="md-ellipsis">
@@ -3401,6 +3423,11 @@
</tbody>
</table>
<p>You can also pass service-specific CLI options as additional keys.</p>
<h4 id="logins-that-need-the-user">Logins that need the user<a class="headerlink" href="#logins-that-need-the-user" title="Permanent link">&para;</a></h4>
<p><code>search</code>, <code>list-titles</code> and <code>list-tracks</code> have no channel to the user. A login that asks for
input or waits for an approval on another device fails at once with <code>AUTH_FAILED</code> on these
endpoints. Complete that login in a download job or a remote session, then send the saved
login with the request.</p>
<h4 id="client-cache-on-a-remote-only-server">Client cache on a remote-only server<a class="headerlink" href="#client-cache-on-a-remote-only-server" title="Permanent link">&para;</a></h4>
<p>A <code>--remote-only</code> server keeps nothing that a client sends. When the request
does not use a server account, the server runs <code>search</code>, <code>list-titles</code> and
@@ -4200,10 +4227,11 @@ an HTTP caller would be remote code execution. You configure post-scripts only i
</span><span id="__span-14-18"><a id="__codelineno-14-18" name="__codelineno-14-18" href="#__codelineno-14-18"></a><span class="w"> </span><span class="nt">"segments_total"</span><span class="p">:</span><span class="w"> </span><span class="mi">300</span><span class="p">,</span>
</span><span id="__span-14-19"><a id="__codelineno-14-19" name="__codelineno-14-19" href="#__codelineno-14-19"></a><span class="w"> </span><span class="nt">"speed"</span><span class="p">:</span><span class="w"> </span><span class="s2">"5.2 MB/s"</span><span class="p">,</span>
</span><span id="__span-14-20"><a id="__codelineno-14-20" name="__codelineno-14-20" href="#__codelineno-14-20"></a><span class="w"> </span><span class="nt">"skipped_subtitles"</span><span class="p">:</span><span class="w"> </span><span class="p">[],</span>
</span><span id="__span-14-21"><a id="__codelineno-14-21" name="__codelineno-14-21" href="#__codelineno-14-21"></a><span class="w"> </span><span class="nt">"input_prompt"</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span>
</span><span id="__span-14-22"><a id="__codelineno-14-22" name="__codelineno-14-22" href="#__codelineno-14-22"></a><span class="w"> </span><span class="p">}</span>
</span><span id="__span-14-23"><a id="__codelineno-14-23" name="__codelineno-14-23" href="#__codelineno-14-23"></a><span class="w"> </span><span class="p">]</span>
</span><span id="__span-14-24"><a id="__codelineno-14-24" name="__codelineno-14-24" href="#__codelineno-14-24"></a><span class="p">}</span>
</span><span id="__span-14-21"><a id="__codelineno-14-21" name="__codelineno-14-21" href="#__codelineno-14-21"></a><span class="w"> </span><span class="nt">"input_prompt"</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span>
</span><span id="__span-14-22"><a id="__codelineno-14-22" name="__codelineno-14-22" href="#__codelineno-14-22"></a><span class="w"> </span><span class="nt">"notice"</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span>
</span><span id="__span-14-23"><a id="__codelineno-14-23" name="__codelineno-14-23" href="#__codelineno-14-23"></a><span class="w"> </span><span class="p">}</span>
</span><span id="__span-14-24"><a id="__codelineno-14-24" name="__codelineno-14-24" href="#__codelineno-14-24"></a><span class="w"> </span><span class="p">]</span>
</span><span id="__span-14-25"><a id="__codelineno-14-25" name="__codelineno-14-25" href="#__codelineno-14-25"></a><span class="p">}</span>
</span></code></pre></div>
</div>
</div>
@@ -4501,6 +4529,9 @@ an HTTP caller would be remote code execution. You configure post-scripts only i
example an OTP code, a PIN, or a device-code confirmation. The job then shows the prompt in its
<code>input_prompt</code> field and in its <code>progress</code> events. Show the prompt to the user and send the
answer here.</p>
<p>A job that waits for an approval on another device, such as a pair code login, shows the
message in its <code>notice</code> field instead. A notice needs no answer: show it to the user and keep
polling.</p>
<div class="tabbed-set tabbed-alternate" data-tabs="13:2"><input checked="checked" id="__tabbed_13_1" name="__tabbed_13" type="radio" /><input id="__tabbed_13_2" name="__tabbed_13" type="radio" /><div class="tabbed-labels"><label for="__tabbed_13_1">Request</label><label for="__tabbed_13_2">Response <code>200</code></label></div>
<div class="tabbed-content">
<div class="tabbed-block">
+8 -1
View File
@@ -2689,6 +2689,11 @@ full detail:</p>
<td>string or <code>null</code></td>
<td>The prompt the service waits on. Answer it with <code>POST /api/download/jobs/{job_id}/input</code>.</td>
</tr>
<tr>
<td><code>notice</code></td>
<td>string or <code>null</code></td>
<td>A message the service shows while it waits for an approval on another device, such as a pair code. It needs no answer.</td>
</tr>
</tbody>
</table>
<p>The full detail adds <code>started_time</code>, <code>completed_time</code>, <code>output_files</code>, the redacted
@@ -2893,7 +2898,9 @@ server process. For each job it spawns a separate Python subprocess:</p>
</ul>
<p>The job worker has no terminal. When a service asks the user for input, the job worker writes
the prompt to <code>progress.json</code> as <code>input_prompt</code> and waits. The answer from
<code>POST /api/download/jobs/{job_id}/input</code> goes to the job worker on its stdin.</p>
<code>POST /api/download/jobs/{job_id}/input</code> goes to the job worker on its stdin.
When a service waits for an approval on another device, the job worker writes the message as
<code>notice</code> and sets it back to <code>null</code> when the wait ends.</p>
<p>Running each download out-of-process isolates the server from crashes, memory growth,
and blocking work inside the download engine, and makes hard cancellation (killing the
process) reliable.</p>
+4 -1
View File
@@ -2532,7 +2532,10 @@ server does not have to prompt:</p>
<code>controld://&lt;resolver&gt;@dns.controld.com</code>. The server counts it as a full proxy
URI and runs its own forwarder for it. A bare region skips Control D, because its
proxy is a forwarder on the client. See
<a href="../../../guide/proxies-and-vpn/#control-d">Control D</a></li>
<a href="../../../guide/proxies-and-vpn/#control-d">Control D</a>
The client also downloads playlists and segments through the same proxy,
as a local run does. <code>--no-proxy-download</code> and <code>--proxy-download</code> change
that for downloads only.</li>
<li>Track-selection hints (<code>range_</code>, <code>vcodec</code>, <code>quality</code>, <code>best_available</code>) so
the server fetches the right manifests</li>
<li>Your language and audio codec selection (<code>-l</code>, <code>-vl</code>, <code>-al</code>, <code>-a</code>, <code>-fs</code>)
+2 -1
View File
@@ -2738,7 +2738,8 @@ Two kinds of members matter: <strong>class variables</strong> that give the deta
bridge, the REST download job relay, or the rich console.</li>
<li><strong><code>wait_for_approval(message, check, timeout, interval=3.0)</code></strong>: shows a message, then
calls <code>check</code> until it returns a value. Use it for a login that the user approves on
another device, such as a pair code.</li>
another device, such as a pair code. A remote-dl session shows the message as a log
line, and a REST download job shows it as the job's <code>notice</code>.</li>
<li><strong>Event callbacks</strong>: <code>on_segment_downloaded</code>, <code>on_track_downloaded</code>,
<code>on_track_decrypted</code>, <code>on_track_repacked</code>, <code>on_track_multiplex</code> let a service react to
pipeline events (for example, MonaLisa decrypts each segment in <code>on_segment_downloaded</code>).</li>
+360 -349
View File
@@ -3761,8 +3761,9 @@ REST download job relays it through <code>prompt_user</code> to the job's <code>
<p>Show <code>message</code>, then call <code>check</code> until it returns a value.</p>
<p>Use it for a login that the user approves on another device, such as a pair code.
<code>check</code> returns None while the approval is pending. Raises TimeoutError after
<code>timeout</code> seconds, and RuntimeError when the remote session no longer exists.</p>
<code>check</code> returns None while the approval is pending, and must return within a few
seconds. Raises TimeoutError after <code>timeout</code> seconds, and RuntimeError when the
remote session no longer exists. A REST download job shows <code>message</code> as its <code>notice</code>.</p>
<details class="mkdocstrings-source">
@@ -3786,26 +3787,36 @@ REST download job relays it through <code>prompt_user</code> to the job's <code>
<span class="normal"><a href="#__codelineno-0-502">502</a></span>
<span class="normal"><a href="#__codelineno-0-503">503</a></span>
<span class="normal"><a href="#__codelineno-0-504">504</a></span>
<span class="normal"><a href="#__codelineno-0-505">505</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-486"><a id="__codelineno-0-486" name="__codelineno-0-486"></a><span class="k">def</span><span class="w"> </span><span class="nf">wait_for_approval</span><span class="p">(</span>
<span class="normal"><a href="#__codelineno-0-505">505</a></span>
<span class="normal"><a href="#__codelineno-0-506">506</a></span>
<span class="normal"><a href="#__codelineno-0-507">507</a></span>
<span class="normal"><a href="#__codelineno-0-508">508</a></span>
<span class="normal"><a href="#__codelineno-0-509">509</a></span>
<span class="normal"><a href="#__codelineno-0-510">510</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-486"><a id="__codelineno-0-486" name="__codelineno-0-486"></a><span class="k">def</span><span class="w"> </span><span class="nf">wait_for_approval</span><span class="p">(</span>
</span><span id="__span-0-487"><a id="__codelineno-0-487" name="__codelineno-0-487"></a> <span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">check</span><span class="p">:</span> <span class="n">Callable</span><span class="p">[[],</span> <span class="n">Optional</span><span class="p">[</span><span class="n">T</span><span class="p">]],</span> <span class="n">timeout</span><span class="p">:</span> <span class="nb">float</span><span class="p">,</span> <span class="n">interval</span><span class="p">:</span> <span class="nb">float</span> <span class="o">=</span> <span class="mf">3.0</span>
</span><span id="__span-0-488"><a id="__codelineno-0-488" name="__codelineno-0-488"></a><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">T</span><span class="p">:</span>
</span><span id="__span-0-489"><a id="__codelineno-0-489" name="__codelineno-0-489"></a><span class="w"> </span><span class="sd">"""Show ``message``, then call ``check`` until it returns a value.</span>
</span><span id="__span-0-490"><a id="__codelineno-0-490" name="__codelineno-0-490"></a>
</span><span id="__span-0-491"><a id="__codelineno-0-491" name="__codelineno-0-491"></a><span class="sd"> Use it for a login that the user approves on another device, such as a pair code.</span>
</span><span id="__span-0-492"><a id="__codelineno-0-492" name="__codelineno-0-492"></a><span class="sd"> ``check`` returns None while the approval is pending. Raises TimeoutError after</span>
</span><span id="__span-0-493"><a id="__codelineno-0-493" name="__codelineno-0-493"></a><span class="sd"> ``timeout`` seconds, and RuntimeError when the remote session no longer exists.</span>
</span><span id="__span-0-494"><a id="__codelineno-0-494" name="__codelineno-0-494"></a><span class="sd"> """</span>
</span><span id="__span-0-495"><a id="__codelineno-0-495" name="__codelineno-0-495"></a> <span class="bp">self</span><span class="o">.</span><span class="n">log</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="n">message</span><span class="p">)</span>
</span><span id="__span-0-496"><a id="__codelineno-0-496" name="__codelineno-0-496"></a> <span class="n">deadline</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">monotonic</span><span class="p">()</span> <span class="o">+</span> <span class="n">timeout</span>
</span><span id="__span-0-497"><a id="__codelineno-0-497" name="__codelineno-0-497"></a> <span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
</span><span id="__span-0-498"><a id="__codelineno-0-498" name="__codelineno-0-498"></a> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_input_bridge</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">_input_bridge</span><span class="o">.</span><span class="n">cancelled</span><span class="p">:</span>
</span><span id="__span-0-499"><a id="__codelineno-0-499" name="__codelineno-0-499"></a> <span class="k">raise</span> <span class="ne">RuntimeError</span><span class="p">(</span><span class="s2">"Session was cancelled"</span><span class="p">)</span>
</span><span id="__span-0-500"><a id="__codelineno-0-500" name="__codelineno-0-500"></a> <span class="n">result</span> <span class="o">=</span> <span class="n">check</span><span class="p">()</span>
</span><span id="__span-0-501"><a id="__codelineno-0-501" name="__codelineno-0-501"></a> <span class="k">if</span> <span class="n">result</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
</span><span id="__span-0-502"><a id="__codelineno-0-502" name="__codelineno-0-502"></a> <span class="k">return</span> <span class="n">result</span>
</span><span id="__span-0-503"><a id="__codelineno-0-503" name="__codelineno-0-503"></a> <span class="k">if</span> <span class="n">time</span><span class="o">.</span><span class="n">monotonic</span><span class="p">()</span> <span class="o">+</span> <span class="n">interval</span> <span class="o">&gt;=</span> <span class="n">deadline</span><span class="p">:</span>
</span><span id="__span-0-504"><a id="__codelineno-0-504" name="__codelineno-0-504"></a> <span class="k">raise</span> <span class="ne">TimeoutError</span><span class="p">(</span><span class="sa">f</span><span class="s2">"No approval within </span><span class="si">{</span><span class="n">timeout</span><span class="si">:</span><span class="s2">.0f</span><span class="si">}</span><span class="s2">s"</span><span class="p">)</span>
</span><span id="__span-0-505"><a id="__codelineno-0-505" name="__codelineno-0-505"></a> <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="n">interval</span><span class="p">)</span>
</span><span id="__span-0-492"><a id="__codelineno-0-492" name="__codelineno-0-492"></a><span class="sd"> ``check`` returns None while the approval is pending, and must return within a few</span>
</span><span id="__span-0-493"><a id="__codelineno-0-493" name="__codelineno-0-493"></a><span class="sd"> seconds. Raises TimeoutError after ``timeout`` seconds, and RuntimeError when the</span>
</span><span id="__span-0-494"><a id="__codelineno-0-494" name="__codelineno-0-494"></a><span class="sd"> remote session no longer exists. A REST download job shows ``message`` as its ``notice``.</span>
</span><span id="__span-0-495"><a id="__codelineno-0-495" name="__codelineno-0-495"></a><span class="sd"> """</span>
</span><span id="__span-0-496"><a id="__codelineno-0-496" name="__codelineno-0-496"></a> <span class="bp">self</span><span class="o">.</span><span class="n">log</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="n">message</span><span class="p">)</span>
</span><span id="__span-0-497"><a id="__codelineno-0-497" name="__codelineno-0-497"></a> <span class="n">show_notice</span><span class="p">(</span><span class="n">message</span><span class="p">)</span>
</span><span id="__span-0-498"><a id="__codelineno-0-498" name="__codelineno-0-498"></a> <span class="n">deadline</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">monotonic</span><span class="p">()</span> <span class="o">+</span> <span class="n">timeout</span>
</span><span id="__span-0-499"><a id="__codelineno-0-499" name="__codelineno-0-499"></a> <span class="k">try</span><span class="p">:</span>
</span><span id="__span-0-500"><a id="__codelineno-0-500" name="__codelineno-0-500"></a> <span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
</span><span id="__span-0-501"><a id="__codelineno-0-501" name="__codelineno-0-501"></a> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_input_bridge</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
</span><span id="__span-0-502"><a id="__codelineno-0-502" name="__codelineno-0-502"></a> <span class="bp">self</span><span class="o">.</span><span class="n">_input_bridge</span><span class="o">.</span><span class="n">ensure_active</span><span class="p">()</span>
</span><span id="__span-0-503"><a id="__codelineno-0-503" name="__codelineno-0-503"></a> <span class="n">result</span> <span class="o">=</span> <span class="n">check</span><span class="p">()</span>
</span><span id="__span-0-504"><a id="__codelineno-0-504" name="__codelineno-0-504"></a> <span class="k">if</span> <span class="n">result</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
</span><span id="__span-0-505"><a id="__codelineno-0-505" name="__codelineno-0-505"></a> <span class="k">return</span> <span class="n">result</span>
</span><span id="__span-0-506"><a id="__codelineno-0-506" name="__codelineno-0-506"></a> <span class="k">if</span> <span class="n">time</span><span class="o">.</span><span class="n">monotonic</span><span class="p">()</span> <span class="o">+</span> <span class="n">interval</span> <span class="o">&gt;=</span> <span class="n">deadline</span><span class="p">:</span>
</span><span id="__span-0-507"><a id="__codelineno-0-507" name="__codelineno-0-507"></a> <span class="k">raise</span> <span class="ne">TimeoutError</span><span class="p">(</span><span class="sa">f</span><span class="s2">"No approval within </span><span class="si">{</span><span class="n">timeout</span><span class="si">:</span><span class="s2">.0f</span><span class="si">}</span><span class="s2">s"</span><span class="p">)</span>
</span><span id="__span-0-508"><a id="__codelineno-0-508" name="__codelineno-0-508"></a> <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="n">interval</span><span class="p">)</span>
</span><span id="__span-0-509"><a id="__codelineno-0-509" name="__codelineno-0-509"></a> <span class="k">finally</span><span class="p">:</span>
</span><span id="__span-0-510"><a id="__codelineno-0-510" name="__codelineno-0-510"></a> <span class="n">show_notice</span><span class="p">(</span><span class="kc">None</span><span class="p">)</span>
</span></code></pre></div></td></tr></table></div>
</details>
</div>
@@ -3833,25 +3844,25 @@ Ideally re-use the title ID argument (that is, self.title).</p>
<details class="mkdocstrings-source">
<summary>Source code in <code>unshackle/core/service.py</code></summary>
<div class="language-python highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-507">507</a></span>
<span class="normal"><a href="#__codelineno-0-508">508</a></span>
<span class="normal"><a href="#__codelineno-0-509">509</a></span>
<span class="normal"><a href="#__codelineno-0-510">510</a></span>
<span class="normal"><a href="#__codelineno-0-511">511</a></span>
<span class="normal"><a href="#__codelineno-0-512">512</a></span>
<div class="language-python highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-512">512</a></span>
<span class="normal"><a href="#__codelineno-0-513">513</a></span>
<span class="normal"><a href="#__codelineno-0-514">514</a></span>
<span class="normal"><a href="#__codelineno-0-515">515</a></span>
<span class="normal"><a href="#__codelineno-0-516">516</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-507"><a id="__codelineno-0-507" name="__codelineno-0-507"></a><span class="k">def</span><span class="w"> </span><span class="nf">search</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Generator</span><span class="p">[</span><span class="n">SearchResult</span><span class="p">,</span> <span class="kc">None</span><span class="p">,</span> <span class="kc">None</span><span class="p">]:</span>
</span><span id="__span-0-508"><a id="__codelineno-0-508" name="__codelineno-0-508"></a><span class="w"> </span><span class="sd">"""</span>
</span><span id="__span-0-509"><a id="__codelineno-0-509" name="__codelineno-0-509"></a><span class="sd"> Find titles from the Service by query.</span>
</span><span id="__span-0-510"><a id="__codelineno-0-510" name="__codelineno-0-510"></a>
</span><span id="__span-0-511"><a id="__codelineno-0-511" name="__codelineno-0-511"></a><span class="sd"> The Service class must take the query as a CLI argument.</span>
</span><span id="__span-0-512"><a id="__codelineno-0-512" name="__codelineno-0-512"></a><span class="sd"> Ideally re-use the title ID argument (that is, self.title).</span>
</span><span id="__span-0-513"><a id="__codelineno-0-513" name="__codelineno-0-513"></a>
</span><span id="__span-0-514"><a id="__codelineno-0-514" name="__codelineno-0-514"></a><span class="sd"> unshackle displays the search results in the order yielded.</span>
</span><span id="__span-0-515"><a id="__codelineno-0-515" name="__codelineno-0-515"></a><span class="sd"> """</span>
</span><span id="__span-0-516"><a id="__codelineno-0-516" name="__codelineno-0-516"></a> <span class="k">raise</span> <span class="ne">NotImplementedError</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Search functionality has not been implemented by </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="vm">__class__</span><span class="o">.</span><span class="vm">__name__</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
<span class="normal"><a href="#__codelineno-0-516">516</a></span>
<span class="normal"><a href="#__codelineno-0-517">517</a></span>
<span class="normal"><a href="#__codelineno-0-518">518</a></span>
<span class="normal"><a href="#__codelineno-0-519">519</a></span>
<span class="normal"><a href="#__codelineno-0-520">520</a></span>
<span class="normal"><a href="#__codelineno-0-521">521</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-512"><a id="__codelineno-0-512" name="__codelineno-0-512"></a><span class="k">def</span><span class="w"> </span><span class="nf">search</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Generator</span><span class="p">[</span><span class="n">SearchResult</span><span class="p">,</span> <span class="kc">None</span><span class="p">,</span> <span class="kc">None</span><span class="p">]:</span>
</span><span id="__span-0-513"><a id="__codelineno-0-513" name="__codelineno-0-513"></a><span class="w"> </span><span class="sd">"""</span>
</span><span id="__span-0-514"><a id="__codelineno-0-514" name="__codelineno-0-514"></a><span class="sd"> Find titles from the Service by query.</span>
</span><span id="__span-0-515"><a id="__codelineno-0-515" name="__codelineno-0-515"></a>
</span><span id="__span-0-516"><a id="__codelineno-0-516" name="__codelineno-0-516"></a><span class="sd"> The Service class must take the query as a CLI argument.</span>
</span><span id="__span-0-517"><a id="__codelineno-0-517" name="__codelineno-0-517"></a><span class="sd"> Ideally re-use the title ID argument (that is, self.title).</span>
</span><span id="__span-0-518"><a id="__codelineno-0-518" name="__codelineno-0-518"></a>
</span><span id="__span-0-519"><a id="__codelineno-0-519" name="__codelineno-0-519"></a><span class="sd"> unshackle displays the search results in the order yielded.</span>
</span><span id="__span-0-520"><a id="__codelineno-0-520" name="__codelineno-0-520"></a><span class="sd"> """</span>
</span><span id="__span-0-521"><a id="__codelineno-0-521" name="__codelineno-0-521"></a> <span class="k">raise</span> <span class="ne">NotImplementedError</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Search functionality has not been implemented by </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="vm">__class__</span><span class="o">.</span><span class="vm">__name__</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span></code></pre></div></td></tr></table></div>
</details>
</div>
@@ -3885,12 +3896,7 @@ Ideally re-use the title ID argument (that is, self.title).</p>
<details class="mkdocstrings-source">
<summary>Source code in <code>unshackle/core/service.py</code></summary>
<div class="language-python highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-518">518</a></span>
<span class="normal"><a href="#__codelineno-0-519">519</a></span>
<span class="normal"><a href="#__codelineno-0-520">520</a></span>
<span class="normal"><a href="#__codelineno-0-521">521</a></span>
<span class="normal"><a href="#__codelineno-0-522">522</a></span>
<span class="normal"><a href="#__codelineno-0-523">523</a></span>
<div class="language-python highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-523">523</a></span>
<span class="normal"><a href="#__codelineno-0-524">524</a></span>
<span class="normal"><a href="#__codelineno-0-525">525</a></span>
<span class="normal"><a href="#__codelineno-0-526">526</a></span>
@@ -3898,20 +3904,25 @@ Ideally re-use the title ID argument (that is, self.title).</p>
<span class="normal"><a href="#__codelineno-0-528">528</a></span>
<span class="normal"><a href="#__codelineno-0-529">529</a></span>
<span class="normal"><a href="#__codelineno-0-530">530</a></span>
<span class="normal"><a href="#__codelineno-0-531">531</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-518"><a id="__codelineno-0-518" name="__codelineno-0-518"></a><span class="k">def</span><span class="w"> </span><span class="nf">get_widevine_service_certificate</span><span class="p">(</span>
</span><span id="__span-0-519"><a id="__codelineno-0-519" name="__codelineno-0-519"></a> <span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">challenge</span><span class="p">:</span> <span class="nb">bytes</span><span class="p">,</span> <span class="n">title</span><span class="p">:</span> <span class="n">Title_T</span><span class="p">,</span> <span class="n">track</span><span class="p">:</span> <span class="n">AnyTrack</span>
</span><span id="__span-0-520"><a id="__codelineno-0-520" name="__codelineno-0-520"></a><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Union</span><span class="p">[</span><span class="nb">bytes</span><span class="p">,</span> <span class="nb">str</span><span class="p">]:</span>
</span><span id="__span-0-521"><a id="__codelineno-0-521" name="__codelineno-0-521"></a><span class="w"> </span><span class="sd">"""</span>
</span><span id="__span-0-522"><a id="__codelineno-0-522" name="__codelineno-0-522"></a><span class="sd"> Get the Widevine Service Certificate used for Privacy Mode.</span>
</span><span id="__span-0-523"><a id="__codelineno-0-523" name="__codelineno-0-523"></a>
</span><span id="__span-0-524"><a id="__codelineno-0-524" name="__codelineno-0-524"></a><span class="sd"> :param challenge: The service challenge, providing this to a License endpoint should return the</span>
</span><span id="__span-0-525"><a id="__codelineno-0-525" name="__codelineno-0-525"></a><span class="sd"> privacy certificate that the service uses.</span>
</span><span id="__span-0-526"><a id="__codelineno-0-526" name="__codelineno-0-526"></a><span class="sd"> :param title: The current `Title` from get_titles that unshackle processes now. unshackle</span>
</span><span id="__span-0-527"><a id="__codelineno-0-527" name="__codelineno-0-527"></a><span class="sd"> gives this in case it holds data you need, for example for an HTTP request.</span>
</span><span id="__span-0-528"><a id="__codelineno-0-528" name="__codelineno-0-528"></a><span class="sd"> :param track: The current `Track` needing decryption. Provided for same reason as `title`.</span>
</span><span id="__span-0-529"><a id="__codelineno-0-529" name="__codelineno-0-529"></a><span class="sd"> :return: The Service Privacy Certificate as Bytes or a Base64 string. Do not Base64 Encode or</span>
</span><span id="__span-0-530"><a id="__codelineno-0-530" name="__codelineno-0-530"></a><span class="sd"> Decode the data, return as is to reduce unnecessary computations.</span>
</span><span id="__span-0-531"><a id="__codelineno-0-531" name="__codelineno-0-531"></a><span class="sd"> """</span>
<span class="normal"><a href="#__codelineno-0-531">531</a></span>
<span class="normal"><a href="#__codelineno-0-532">532</a></span>
<span class="normal"><a href="#__codelineno-0-533">533</a></span>
<span class="normal"><a href="#__codelineno-0-534">534</a></span>
<span class="normal"><a href="#__codelineno-0-535">535</a></span>
<span class="normal"><a href="#__codelineno-0-536">536</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-523"><a id="__codelineno-0-523" name="__codelineno-0-523"></a><span class="k">def</span><span class="w"> </span><span class="nf">get_widevine_service_certificate</span><span class="p">(</span>
</span><span id="__span-0-524"><a id="__codelineno-0-524" name="__codelineno-0-524"></a> <span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">challenge</span><span class="p">:</span> <span class="nb">bytes</span><span class="p">,</span> <span class="n">title</span><span class="p">:</span> <span class="n">Title_T</span><span class="p">,</span> <span class="n">track</span><span class="p">:</span> <span class="n">AnyTrack</span>
</span><span id="__span-0-525"><a id="__codelineno-0-525" name="__codelineno-0-525"></a><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Union</span><span class="p">[</span><span class="nb">bytes</span><span class="p">,</span> <span class="nb">str</span><span class="p">]:</span>
</span><span id="__span-0-526"><a id="__codelineno-0-526" name="__codelineno-0-526"></a><span class="w"> </span><span class="sd">"""</span>
</span><span id="__span-0-527"><a id="__codelineno-0-527" name="__codelineno-0-527"></a><span class="sd"> Get the Widevine Service Certificate used for Privacy Mode.</span>
</span><span id="__span-0-528"><a id="__codelineno-0-528" name="__codelineno-0-528"></a>
</span><span id="__span-0-529"><a id="__codelineno-0-529" name="__codelineno-0-529"></a><span class="sd"> :param challenge: The service challenge, providing this to a License endpoint should return the</span>
</span><span id="__span-0-530"><a id="__codelineno-0-530" name="__codelineno-0-530"></a><span class="sd"> privacy certificate that the service uses.</span>
</span><span id="__span-0-531"><a id="__codelineno-0-531" name="__codelineno-0-531"></a><span class="sd"> :param title: The current `Title` from get_titles that unshackle processes now. unshackle</span>
</span><span id="__span-0-532"><a id="__codelineno-0-532" name="__codelineno-0-532"></a><span class="sd"> gives this in case it holds data you need, for example for an HTTP request.</span>
</span><span id="__span-0-533"><a id="__codelineno-0-533" name="__codelineno-0-533"></a><span class="sd"> :param track: The current `Track` needing decryption. Provided for same reason as `title`.</span>
</span><span id="__span-0-534"><a id="__codelineno-0-534" name="__codelineno-0-534"></a><span class="sd"> :return: The Service Privacy Certificate as Bytes or a Base64 string. Do not Base64 Encode or</span>
</span><span id="__span-0-535"><a id="__codelineno-0-535" name="__codelineno-0-535"></a><span class="sd"> Decode the data, return as is to reduce unnecessary computations.</span>
</span><span id="__span-0-536"><a id="__codelineno-0-536" name="__codelineno-0-536"></a><span class="sd"> """</span>
</span></code></pre></div></td></tr></table></div>
</details>
</div>
@@ -3947,12 +3958,7 @@ The service can then ban, revoke, disable, or downgrade that device.</p>
<details class="mkdocstrings-source">
<summary>Source code in <code>unshackle/core/service.py</code></summary>
<div class="language-python highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-533">533</a></span>
<span class="normal"><a href="#__codelineno-0-534">534</a></span>
<span class="normal"><a href="#__codelineno-0-535">535</a></span>
<span class="normal"><a href="#__codelineno-0-536">536</a></span>
<span class="normal"><a href="#__codelineno-0-537">537</a></span>
<span class="normal"><a href="#__codelineno-0-538">538</a></span>
<div class="language-python highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-538">538</a></span>
<span class="normal"><a href="#__codelineno-0-539">539</a></span>
<span class="normal"><a href="#__codelineno-0-540">540</a></span>
<span class="normal"><a href="#__codelineno-0-541">541</a></span>
@@ -3964,24 +3970,29 @@ The service can then ban, revoke, disable, or downgrade that device.</p>
<span class="normal"><a href="#__codelineno-0-547">547</a></span>
<span class="normal"><a href="#__codelineno-0-548">548</a></span>
<span class="normal"><a href="#__codelineno-0-549">549</a></span>
<span class="normal"><a href="#__codelineno-0-550">550</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-533"><a id="__codelineno-0-533" name="__codelineno-0-533"></a><span class="k">def</span><span class="w"> </span><span class="nf">get_widevine_license</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">challenge</span><span class="p">:</span> <span class="nb">bytes</span><span class="p">,</span> <span class="n">title</span><span class="p">:</span> <span class="n">Title_T</span><span class="p">,</span> <span class="n">track</span><span class="p">:</span> <span class="n">AnyTrack</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Optional</span><span class="p">[</span><span class="n">Union</span><span class="p">[</span><span class="nb">bytes</span><span class="p">,</span> <span class="nb">str</span><span class="p">]]:</span>
</span><span id="__span-0-534"><a id="__codelineno-0-534" name="__codelineno-0-534"></a><span class="w"> </span><span class="sd">"""</span>
</span><span id="__span-0-535"><a id="__codelineno-0-535" name="__codelineno-0-535"></a><span class="sd"> Get a Widevine License message by sending a License Request (challenge).</span>
</span><span id="__span-0-536"><a id="__codelineno-0-536" name="__codelineno-0-536"></a>
</span><span id="__span-0-537"><a id="__codelineno-0-537" name="__codelineno-0-537"></a><span class="sd"> This License message contains the encrypted content keys and will be</span>
</span><span id="__span-0-538"><a id="__codelineno-0-538" name="__codelineno-0-538"></a><span class="sd"> read by the Cdm and decrypted.</span>
</span><span id="__span-0-539"><a id="__codelineno-0-539" name="__codelineno-0-539"></a>
</span><span id="__span-0-540"><a id="__codelineno-0-540" name="__codelineno-0-540"></a><span class="sd"> This is a very important request to get correct. A bad, unexpected, or missing</span>
</span><span id="__span-0-541"><a id="__codelineno-0-541" name="__codelineno-0-541"></a><span class="sd"> value in the request can cause the service to detect your CDM device.</span>
</span><span id="__span-0-542"><a id="__codelineno-0-542" name="__codelineno-0-542"></a><span class="sd"> The service can then ban, revoke, disable, or downgrade that device.</span>
</span><span id="__span-0-543"><a id="__codelineno-0-543" name="__codelineno-0-543"></a>
</span><span id="__span-0-544"><a id="__codelineno-0-544" name="__codelineno-0-544"></a><span class="sd"> :param challenge: The license challenge from the Widevine CDM.</span>
</span><span id="__span-0-545"><a id="__codelineno-0-545" name="__codelineno-0-545"></a><span class="sd"> :param title: The current `Title` from get_titles that unshackle processes now. unshackle</span>
</span><span id="__span-0-546"><a id="__codelineno-0-546" name="__codelineno-0-546"></a><span class="sd"> gives this in case it holds data you need, for example for an HTTP request.</span>
</span><span id="__span-0-547"><a id="__codelineno-0-547" name="__codelineno-0-547"></a><span class="sd"> :param track: The current `Track` needing decryption. Provided for same reason as `title`.</span>
</span><span id="__span-0-548"><a id="__codelineno-0-548" name="__codelineno-0-548"></a><span class="sd"> :return: The License response as Bytes or a Base64 string. Do not Base64 Encode or</span>
</span><span id="__span-0-549"><a id="__codelineno-0-549" name="__codelineno-0-549"></a><span class="sd"> Decode the data, return as is to reduce unnecessary computations.</span>
</span><span id="__span-0-550"><a id="__codelineno-0-550" name="__codelineno-0-550"></a><span class="sd"> """</span>
<span class="normal"><a href="#__codelineno-0-550">550</a></span>
<span class="normal"><a href="#__codelineno-0-551">551</a></span>
<span class="normal"><a href="#__codelineno-0-552">552</a></span>
<span class="normal"><a href="#__codelineno-0-553">553</a></span>
<span class="normal"><a href="#__codelineno-0-554">554</a></span>
<span class="normal"><a href="#__codelineno-0-555">555</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-538"><a id="__codelineno-0-538" name="__codelineno-0-538"></a><span class="k">def</span><span class="w"> </span><span class="nf">get_widevine_license</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">challenge</span><span class="p">:</span> <span class="nb">bytes</span><span class="p">,</span> <span class="n">title</span><span class="p">:</span> <span class="n">Title_T</span><span class="p">,</span> <span class="n">track</span><span class="p">:</span> <span class="n">AnyTrack</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Optional</span><span class="p">[</span><span class="n">Union</span><span class="p">[</span><span class="nb">bytes</span><span class="p">,</span> <span class="nb">str</span><span class="p">]]:</span>
</span><span id="__span-0-539"><a id="__codelineno-0-539" name="__codelineno-0-539"></a><span class="w"> </span><span class="sd">"""</span>
</span><span id="__span-0-540"><a id="__codelineno-0-540" name="__codelineno-0-540"></a><span class="sd"> Get a Widevine License message by sending a License Request (challenge).</span>
</span><span id="__span-0-541"><a id="__codelineno-0-541" name="__codelineno-0-541"></a>
</span><span id="__span-0-542"><a id="__codelineno-0-542" name="__codelineno-0-542"></a><span class="sd"> This License message contains the encrypted content keys and will be</span>
</span><span id="__span-0-543"><a id="__codelineno-0-543" name="__codelineno-0-543"></a><span class="sd"> read by the Cdm and decrypted.</span>
</span><span id="__span-0-544"><a id="__codelineno-0-544" name="__codelineno-0-544"></a>
</span><span id="__span-0-545"><a id="__codelineno-0-545" name="__codelineno-0-545"></a><span class="sd"> This is a very important request to get correct. A bad, unexpected, or missing</span>
</span><span id="__span-0-546"><a id="__codelineno-0-546" name="__codelineno-0-546"></a><span class="sd"> value in the request can cause the service to detect your CDM device.</span>
</span><span id="__span-0-547"><a id="__codelineno-0-547" name="__codelineno-0-547"></a><span class="sd"> The service can then ban, revoke, disable, or downgrade that device.</span>
</span><span id="__span-0-548"><a id="__codelineno-0-548" name="__codelineno-0-548"></a>
</span><span id="__span-0-549"><a id="__codelineno-0-549" name="__codelineno-0-549"></a><span class="sd"> :param challenge: The license challenge from the Widevine CDM.</span>
</span><span id="__span-0-550"><a id="__codelineno-0-550" name="__codelineno-0-550"></a><span class="sd"> :param title: The current `Title` from get_titles that unshackle processes now. unshackle</span>
</span><span id="__span-0-551"><a id="__codelineno-0-551" name="__codelineno-0-551"></a><span class="sd"> gives this in case it holds data you need, for example for an HTTP request.</span>
</span><span id="__span-0-552"><a id="__codelineno-0-552" name="__codelineno-0-552"></a><span class="sd"> :param track: The current `Track` needing decryption. Provided for same reason as `title`.</span>
</span><span id="__span-0-553"><a id="__codelineno-0-553" name="__codelineno-0-553"></a><span class="sd"> :return: The License response as Bytes or a Base64 string. Do not Base64 Encode or</span>
</span><span id="__span-0-554"><a id="__codelineno-0-554" name="__codelineno-0-554"></a><span class="sd"> Decode the data, return as is to reduce unnecessary computations.</span>
</span><span id="__span-0-555"><a id="__codelineno-0-555" name="__codelineno-0-555"></a><span class="sd"> """</span>
</span></code></pre></div></td></tr></table></div>
</details>
</div>
@@ -4017,12 +4028,7 @@ The service can then ban, revoke, disable, or downgrade that device.</p>
<details class="mkdocstrings-source">
<summary>Source code in <code>unshackle/core/service.py</code></summary>
<div class="language-python highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-552">552</a></span>
<span class="normal"><a href="#__codelineno-0-553">553</a></span>
<span class="normal"><a href="#__codelineno-0-554">554</a></span>
<span class="normal"><a href="#__codelineno-0-555">555</a></span>
<span class="normal"><a href="#__codelineno-0-556">556</a></span>
<span class="normal"><a href="#__codelineno-0-557">557</a></span>
<div class="language-python highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-557">557</a></span>
<span class="normal"><a href="#__codelineno-0-558">558</a></span>
<span class="normal"><a href="#__codelineno-0-559">559</a></span>
<span class="normal"><a href="#__codelineno-0-560">560</a></span>
@@ -4041,31 +4047,36 @@ The service can then ban, revoke, disable, or downgrade that device.</p>
<span class="normal"><a href="#__codelineno-0-573">573</a></span>
<span class="normal"><a href="#__codelineno-0-574">574</a></span>
<span class="normal"><a href="#__codelineno-0-575">575</a></span>
<span class="normal"><a href="#__codelineno-0-576">576</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-552"><a id="__codelineno-0-552" name="__codelineno-0-552"></a><span class="k">def</span><span class="w"> </span><span class="nf">get_playready_license</span><span class="p">(</span>
</span><span id="__span-0-553"><a id="__codelineno-0-553" name="__codelineno-0-553"></a> <span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">challenge</span><span class="p">:</span> <span class="nb">bytes</span><span class="p">,</span> <span class="n">title</span><span class="p">:</span> <span class="n">Title_T</span><span class="p">,</span> <span class="n">track</span><span class="p">:</span> <span class="n">AnyTrack</span>
</span><span id="__span-0-554"><a id="__codelineno-0-554" name="__codelineno-0-554"></a><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Optional</span><span class="p">[</span><span class="n">Union</span><span class="p">[</span><span class="nb">bytes</span><span class="p">,</span> <span class="nb">str</span><span class="p">]]:</span>
</span><span id="__span-0-555"><a id="__codelineno-0-555" name="__codelineno-0-555"></a><span class="w"> </span><span class="sd">"""</span>
</span><span id="__span-0-556"><a id="__codelineno-0-556" name="__codelineno-0-556"></a><span class="sd"> Get a PlayReady License message by sending a License Request (challenge).</span>
</span><span id="__span-0-557"><a id="__codelineno-0-557" name="__codelineno-0-557"></a>
</span><span id="__span-0-558"><a id="__codelineno-0-558" name="__codelineno-0-558"></a><span class="sd"> This License message contains the encrypted content keys and will be</span>
</span><span id="__span-0-559"><a id="__codelineno-0-559" name="__codelineno-0-559"></a><span class="sd"> read by the CDM and decrypted.</span>
</span><span id="__span-0-560"><a id="__codelineno-0-560" name="__codelineno-0-560"></a>
</span><span id="__span-0-561"><a id="__codelineno-0-561" name="__codelineno-0-561"></a><span class="sd"> This is a very important request to get correct. A bad, unexpected, or missing</span>
</span><span id="__span-0-562"><a id="__codelineno-0-562" name="__codelineno-0-562"></a><span class="sd"> value in the request can cause the service to detect your CDM device.</span>
</span><span id="__span-0-563"><a id="__codelineno-0-563" name="__codelineno-0-563"></a><span class="sd"> The service can then ban, revoke, disable, or downgrade that device.</span>
</span><span id="__span-0-564"><a id="__codelineno-0-564" name="__codelineno-0-564"></a>
</span><span id="__span-0-565"><a id="__codelineno-0-565" name="__codelineno-0-565"></a><span class="sd"> :param challenge: The license challenge from the PlayReady CDM.</span>
</span><span id="__span-0-566"><a id="__codelineno-0-566" name="__codelineno-0-566"></a><span class="sd"> :param title: The current `Title` from get_titles that unshackle processes now. unshackle</span>
</span><span id="__span-0-567"><a id="__codelineno-0-567" name="__codelineno-0-567"></a><span class="sd"> gives this in case it holds data you need, for example for an HTTP request.</span>
</span><span id="__span-0-568"><a id="__codelineno-0-568" name="__codelineno-0-568"></a><span class="sd"> :param track: The current `Track` needing decryption. Provided for same reason as `title`.</span>
</span><span id="__span-0-569"><a id="__codelineno-0-569" name="__codelineno-0-569"></a><span class="sd"> :return: The License response as Bytes or a Base64 string. Do not Base64 Encode or</span>
</span><span id="__span-0-570"><a id="__codelineno-0-570" name="__codelineno-0-570"></a><span class="sd"> Decode the data, return as is to reduce unnecessary computations.</span>
</span><span id="__span-0-571"><a id="__codelineno-0-571" name="__codelineno-0-571"></a><span class="sd"> """</span>
</span><span id="__span-0-572"><a id="__codelineno-0-572" name="__codelineno-0-572"></a> <span class="c1"># A service that implements Widevine licensing only still gets PlayReady, with the</span>
</span><span id="__span-0-573"><a id="__codelineno-0-573" name="__codelineno-0-573"></a> <span class="c1"># arguments its own signature declares.</span>
</span><span id="__span-0-574"><a id="__codelineno-0-574" name="__codelineno-0-574"></a> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_widevine_license</span><span class="p">(</span>
</span><span id="__span-0-575"><a id="__codelineno-0-575" name="__codelineno-0-575"></a> <span class="o">**</span><span class="n">declared_kwargs</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">get_widevine_license</span><span class="p">,</span> <span class="p">{</span><span class="s2">"challenge"</span><span class="p">:</span> <span class="n">challenge</span><span class="p">,</span> <span class="s2">"title"</span><span class="p">:</span> <span class="n">title</span><span class="p">,</span> <span class="s2">"track"</span><span class="p">:</span> <span class="n">track</span><span class="p">})</span>
</span><span id="__span-0-576"><a id="__codelineno-0-576" name="__codelineno-0-576"></a> <span class="p">)</span>
<span class="normal"><a href="#__codelineno-0-576">576</a></span>
<span class="normal"><a href="#__codelineno-0-577">577</a></span>
<span class="normal"><a href="#__codelineno-0-578">578</a></span>
<span class="normal"><a href="#__codelineno-0-579">579</a></span>
<span class="normal"><a href="#__codelineno-0-580">580</a></span>
<span class="normal"><a href="#__codelineno-0-581">581</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-557"><a id="__codelineno-0-557" name="__codelineno-0-557"></a><span class="k">def</span><span class="w"> </span><span class="nf">get_playready_license</span><span class="p">(</span>
</span><span id="__span-0-558"><a id="__codelineno-0-558" name="__codelineno-0-558"></a> <span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">challenge</span><span class="p">:</span> <span class="nb">bytes</span><span class="p">,</span> <span class="n">title</span><span class="p">:</span> <span class="n">Title_T</span><span class="p">,</span> <span class="n">track</span><span class="p">:</span> <span class="n">AnyTrack</span>
</span><span id="__span-0-559"><a id="__codelineno-0-559" name="__codelineno-0-559"></a><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Optional</span><span class="p">[</span><span class="n">Union</span><span class="p">[</span><span class="nb">bytes</span><span class="p">,</span> <span class="nb">str</span><span class="p">]]:</span>
</span><span id="__span-0-560"><a id="__codelineno-0-560" name="__codelineno-0-560"></a><span class="w"> </span><span class="sd">"""</span>
</span><span id="__span-0-561"><a id="__codelineno-0-561" name="__codelineno-0-561"></a><span class="sd"> Get a PlayReady License message by sending a License Request (challenge).</span>
</span><span id="__span-0-562"><a id="__codelineno-0-562" name="__codelineno-0-562"></a>
</span><span id="__span-0-563"><a id="__codelineno-0-563" name="__codelineno-0-563"></a><span class="sd"> This License message contains the encrypted content keys and will be</span>
</span><span id="__span-0-564"><a id="__codelineno-0-564" name="__codelineno-0-564"></a><span class="sd"> read by the CDM and decrypted.</span>
</span><span id="__span-0-565"><a id="__codelineno-0-565" name="__codelineno-0-565"></a>
</span><span id="__span-0-566"><a id="__codelineno-0-566" name="__codelineno-0-566"></a><span class="sd"> This is a very important request to get correct. A bad, unexpected, or missing</span>
</span><span id="__span-0-567"><a id="__codelineno-0-567" name="__codelineno-0-567"></a><span class="sd"> value in the request can cause the service to detect your CDM device.</span>
</span><span id="__span-0-568"><a id="__codelineno-0-568" name="__codelineno-0-568"></a><span class="sd"> The service can then ban, revoke, disable, or downgrade that device.</span>
</span><span id="__span-0-569"><a id="__codelineno-0-569" name="__codelineno-0-569"></a>
</span><span id="__span-0-570"><a id="__codelineno-0-570" name="__codelineno-0-570"></a><span class="sd"> :param challenge: The license challenge from the PlayReady CDM.</span>
</span><span id="__span-0-571"><a id="__codelineno-0-571" name="__codelineno-0-571"></a><span class="sd"> :param title: The current `Title` from get_titles that unshackle processes now. unshackle</span>
</span><span id="__span-0-572"><a id="__codelineno-0-572" name="__codelineno-0-572"></a><span class="sd"> gives this in case it holds data you need, for example for an HTTP request.</span>
</span><span id="__span-0-573"><a id="__codelineno-0-573" name="__codelineno-0-573"></a><span class="sd"> :param track: The current `Track` needing decryption. Provided for same reason as `title`.</span>
</span><span id="__span-0-574"><a id="__codelineno-0-574" name="__codelineno-0-574"></a><span class="sd"> :return: The License response as Bytes or a Base64 string. Do not Base64 Encode or</span>
</span><span id="__span-0-575"><a id="__codelineno-0-575" name="__codelineno-0-575"></a><span class="sd"> Decode the data, return as is to reduce unnecessary computations.</span>
</span><span id="__span-0-576"><a id="__codelineno-0-576" name="__codelineno-0-576"></a><span class="sd"> """</span>
</span><span id="__span-0-577"><a id="__codelineno-0-577" name="__codelineno-0-577"></a> <span class="c1"># A service that implements Widevine licensing only still gets PlayReady, with the</span>
</span><span id="__span-0-578"><a id="__codelineno-0-578" name="__codelineno-0-578"></a> <span class="c1"># arguments its own signature declares.</span>
</span><span id="__span-0-579"><a id="__codelineno-0-579" name="__codelineno-0-579"></a> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_widevine_license</span><span class="p">(</span>
</span><span id="__span-0-580"><a id="__codelineno-0-580" name="__codelineno-0-580"></a> <span class="o">**</span><span class="n">declared_kwargs</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">get_widevine_license</span><span class="p">,</span> <span class="p">{</span><span class="s2">"challenge"</span><span class="p">:</span> <span class="n">challenge</span><span class="p">,</span> <span class="s2">"title"</span><span class="p">:</span> <span class="n">title</span><span class="p">,</span> <span class="s2">"track"</span><span class="p">:</span> <span class="n">track</span><span class="p">})</span>
</span><span id="__span-0-581"><a id="__codelineno-0-581" name="__codelineno-0-581"></a> <span class="p">)</span>
</span></code></pre></div></td></tr></table></div>
</details>
</div>
@@ -4101,12 +4112,7 @@ and the license is a JWK Set, e.g. <code>{"keys": [{"kty": "oct", "k": "...", "k
<details class="mkdocstrings-source">
<summary>Source code in <code>unshackle/core/service.py</code></summary>
<div class="language-python highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-578">578</a></span>
<span class="normal"><a href="#__codelineno-0-579">579</a></span>
<span class="normal"><a href="#__codelineno-0-580">580</a></span>
<span class="normal"><a href="#__codelineno-0-581">581</a></span>
<span class="normal"><a href="#__codelineno-0-582">582</a></span>
<span class="normal"><a href="#__codelineno-0-583">583</a></span>
<div class="language-python highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-583">583</a></span>
<span class="normal"><a href="#__codelineno-0-584">584</a></span>
<span class="normal"><a href="#__codelineno-0-585">585</a></span>
<span class="normal"><a href="#__codelineno-0-586">586</a></span>
@@ -4120,26 +4126,31 @@ and the license is a JWK Set, e.g. <code>{"keys": [{"kty": "oct", "k": "...", "k
<span class="normal"><a href="#__codelineno-0-594">594</a></span>
<span class="normal"><a href="#__codelineno-0-595">595</a></span>
<span class="normal"><a href="#__codelineno-0-596">596</a></span>
<span class="normal"><a href="#__codelineno-0-597">597</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-578"><a id="__codelineno-0-578" name="__codelineno-0-578"></a><span class="k">def</span><span class="w"> </span><span class="nf">get_clearkey_license</span><span class="p">(</span>
</span><span id="__span-0-579"><a id="__codelineno-0-579" name="__codelineno-0-579"></a> <span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">challenge</span><span class="p">:</span> <span class="nb">bytes</span><span class="p">,</span> <span class="n">title</span><span class="p">:</span> <span class="n">Title_T</span><span class="p">,</span> <span class="n">track</span><span class="p">:</span> <span class="n">AnyTrack</span>
</span><span id="__span-0-580"><a id="__codelineno-0-580" name="__codelineno-0-580"></a><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Optional</span><span class="p">[</span><span class="n">Union</span><span class="p">[</span><span class="nb">bytes</span><span class="p">,</span> <span class="nb">str</span><span class="p">,</span> <span class="nb">dict</span><span class="p">]]:</span>
</span><span id="__span-0-581"><a id="__codelineno-0-581" name="__codelineno-0-581"></a><span class="w"> </span><span class="sd">"""</span>
</span><span id="__span-0-582"><a id="__codelineno-0-582" name="__codelineno-0-582"></a><span class="sd"> Get a W3C ClearKey License (JWK Set) by sending a License Request (challenge).</span>
</span><span id="__span-0-583"><a id="__codelineno-0-583" name="__codelineno-0-583"></a>
</span><span id="__span-0-584"><a id="__codelineno-0-584" name="__codelineno-0-584"></a><span class="sd"> Used for DASH `org.w3.clearkey` tracks. unshackle uses no CDM here: the challenge is</span>
</span><span id="__span-0-585"><a id="__codelineno-0-585" name="__codelineno-0-585"></a><span class="sd"> the W3C EME JSON license request, e.g. ``{"kids": ["&lt;base64url&gt;"], "type": "temporary"}``,</span>
</span><span id="__span-0-586"><a id="__codelineno-0-586" name="__codelineno-0-586"></a><span class="sd"> and the license is a JWK Set, e.g. ``{"keys": [{"kty": "oct", "k": "...", "kid": "..."}]}``.</span>
</span><span id="__span-0-587"><a id="__codelineno-0-587" name="__codelineno-0-587"></a>
</span><span id="__span-0-588"><a id="__codelineno-0-588" name="__codelineno-0-588"></a><span class="sd"> :param challenge: The JSON license request bytes to POST to the license server.</span>
</span><span id="__span-0-589"><a id="__codelineno-0-589" name="__codelineno-0-589"></a><span class="sd"> :param title: The current `Title` from get_titles that unshackle processes now. unshackle</span>
</span><span id="__span-0-590"><a id="__codelineno-0-590" name="__codelineno-0-590"></a><span class="sd"> gives this in case it holds data you need, for example for an HTTP request.</span>
</span><span id="__span-0-591"><a id="__codelineno-0-591" name="__codelineno-0-591"></a><span class="sd"> :param track: The current `Track` needing decryption. Provided for same reason as `title`.</span>
</span><span id="__span-0-592"><a id="__codelineno-0-592" name="__codelineno-0-592"></a><span class="sd"> :return: The JWK Set license as a dict, JSON str, or raw bytes. Return None (the default)</span>
</span><span id="__span-0-593"><a id="__codelineno-0-593" name="__codelineno-0-593"></a><span class="sd"> to let the framework POST the challenge to the manifest-provided Laurl, if any.</span>
</span><span id="__span-0-594"><a id="__codelineno-0-594" name="__codelineno-0-594"></a><span class="sd"> Services with no license server can instead pre-populate the DRM object's</span>
</span><span id="__span-0-595"><a id="__codelineno-0-595" name="__codelineno-0-595"></a><span class="sd"> `content_keys` in get_tracks.</span>
</span><span id="__span-0-596"><a id="__codelineno-0-596" name="__codelineno-0-596"></a><span class="sd"> """</span>
</span><span id="__span-0-597"><a id="__codelineno-0-597" name="__codelineno-0-597"></a> <span class="k">return</span> <span class="kc">None</span>
<span class="normal"><a href="#__codelineno-0-597">597</a></span>
<span class="normal"><a href="#__codelineno-0-598">598</a></span>
<span class="normal"><a href="#__codelineno-0-599">599</a></span>
<span class="normal"><a href="#__codelineno-0-600">600</a></span>
<span class="normal"><a href="#__codelineno-0-601">601</a></span>
<span class="normal"><a href="#__codelineno-0-602">602</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-583"><a id="__codelineno-0-583" name="__codelineno-0-583"></a><span class="k">def</span><span class="w"> </span><span class="nf">get_clearkey_license</span><span class="p">(</span>
</span><span id="__span-0-584"><a id="__codelineno-0-584" name="__codelineno-0-584"></a> <span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">challenge</span><span class="p">:</span> <span class="nb">bytes</span><span class="p">,</span> <span class="n">title</span><span class="p">:</span> <span class="n">Title_T</span><span class="p">,</span> <span class="n">track</span><span class="p">:</span> <span class="n">AnyTrack</span>
</span><span id="__span-0-585"><a id="__codelineno-0-585" name="__codelineno-0-585"></a><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Optional</span><span class="p">[</span><span class="n">Union</span><span class="p">[</span><span class="nb">bytes</span><span class="p">,</span> <span class="nb">str</span><span class="p">,</span> <span class="nb">dict</span><span class="p">]]:</span>
</span><span id="__span-0-586"><a id="__codelineno-0-586" name="__codelineno-0-586"></a><span class="w"> </span><span class="sd">"""</span>
</span><span id="__span-0-587"><a id="__codelineno-0-587" name="__codelineno-0-587"></a><span class="sd"> Get a W3C ClearKey License (JWK Set) by sending a License Request (challenge).</span>
</span><span id="__span-0-588"><a id="__codelineno-0-588" name="__codelineno-0-588"></a>
</span><span id="__span-0-589"><a id="__codelineno-0-589" name="__codelineno-0-589"></a><span class="sd"> Used for DASH `org.w3.clearkey` tracks. unshackle uses no CDM here: the challenge is</span>
</span><span id="__span-0-590"><a id="__codelineno-0-590" name="__codelineno-0-590"></a><span class="sd"> the W3C EME JSON license request, e.g. ``{"kids": ["&lt;base64url&gt;"], "type": "temporary"}``,</span>
</span><span id="__span-0-591"><a id="__codelineno-0-591" name="__codelineno-0-591"></a><span class="sd"> and the license is a JWK Set, e.g. ``{"keys": [{"kty": "oct", "k": "...", "kid": "..."}]}``.</span>
</span><span id="__span-0-592"><a id="__codelineno-0-592" name="__codelineno-0-592"></a>
</span><span id="__span-0-593"><a id="__codelineno-0-593" name="__codelineno-0-593"></a><span class="sd"> :param challenge: The JSON license request bytes to POST to the license server.</span>
</span><span id="__span-0-594"><a id="__codelineno-0-594" name="__codelineno-0-594"></a><span class="sd"> :param title: The current `Title` from get_titles that unshackle processes now. unshackle</span>
</span><span id="__span-0-595"><a id="__codelineno-0-595" name="__codelineno-0-595"></a><span class="sd"> gives this in case it holds data you need, for example for an HTTP request.</span>
</span><span id="__span-0-596"><a id="__codelineno-0-596" name="__codelineno-0-596"></a><span class="sd"> :param track: The current `Track` needing decryption. Provided for same reason as `title`.</span>
</span><span id="__span-0-597"><a id="__codelineno-0-597" name="__codelineno-0-597"></a><span class="sd"> :return: The JWK Set license as a dict, JSON str, or raw bytes. Return None (the default)</span>
</span><span id="__span-0-598"><a id="__codelineno-0-598" name="__codelineno-0-598"></a><span class="sd"> to let the framework POST the challenge to the manifest-provided Laurl, if any.</span>
</span><span id="__span-0-599"><a id="__codelineno-0-599" name="__codelineno-0-599"></a><span class="sd"> Services with no license server can instead pre-populate the DRM object's</span>
</span><span id="__span-0-600"><a id="__codelineno-0-600" name="__codelineno-0-600"></a><span class="sd"> `content_keys` in get_tracks.</span>
</span><span id="__span-0-601"><a id="__codelineno-0-601" name="__codelineno-0-601"></a><span class="sd"> """</span>
</span><span id="__span-0-602"><a id="__codelineno-0-602" name="__codelineno-0-602"></a> <span class="k">return</span> <span class="kc">None</span>
</span></code></pre></div></td></tr></table></div>
</details>
</div>
@@ -4174,12 +4185,7 @@ This can be useful to store information on each title that you need later, like
<details class="mkdocstrings-source">
<summary>Source code in <code>unshackle/core/service.py</code></summary>
<div class="language-python highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-599">599</a></span>
<span class="normal"><a href="#__codelineno-0-600">600</a></span>
<span class="normal"><a href="#__codelineno-0-601">601</a></span>
<span class="normal"><a href="#__codelineno-0-602">602</a></span>
<span class="normal"><a href="#__codelineno-0-603">603</a></span>
<span class="normal"><a href="#__codelineno-0-604">604</a></span>
<div class="language-python highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-604">604</a></span>
<span class="normal"><a href="#__codelineno-0-605">605</a></span>
<span class="normal"><a href="#__codelineno-0-606">606</a></span>
<span class="normal"><a href="#__codelineno-0-607">607</a></span>
@@ -4187,20 +4193,25 @@ This can be useful to store information on each title that you need later, like
<span class="normal"><a href="#__codelineno-0-609">609</a></span>
<span class="normal"><a href="#__codelineno-0-610">610</a></span>
<span class="normal"><a href="#__codelineno-0-611">611</a></span>
<span class="normal"><a href="#__codelineno-0-612">612</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-599"><a id="__codelineno-0-599" name="__codelineno-0-599"></a><span class="nd">@abstractmethod</span>
</span><span id="__span-0-600"><a id="__codelineno-0-600" name="__codelineno-0-600"></a><span class="k">def</span><span class="w"> </span><span class="nf">get_titles</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Titles_T</span><span class="p">:</span>
</span><span id="__span-0-601"><a id="__codelineno-0-601" name="__codelineno-0-601"></a><span class="w"> </span><span class="sd">"""</span>
</span><span id="__span-0-602"><a id="__codelineno-0-602" name="__codelineno-0-602"></a><span class="sd"> Get Titles for the provided title ID.</span>
</span><span id="__span-0-603"><a id="__codelineno-0-603" name="__codelineno-0-603"></a>
</span><span id="__span-0-604"><a id="__codelineno-0-604" name="__codelineno-0-604"></a><span class="sd"> Return a Movies, Series, or Album objects containing Movie, Episode, or Song title objects respectively.</span>
</span><span id="__span-0-605"><a id="__codelineno-0-605" name="__codelineno-0-605"></a><span class="sd"> The returned data must be for the given title ID, or a spawn of the title ID.</span>
</span><span id="__span-0-606"><a id="__codelineno-0-606" name="__codelineno-0-606"></a>
</span><span id="__span-0-607"><a id="__codelineno-0-607" name="__codelineno-0-607"></a><span class="sd"> You must return at least one object. If you do not, unshackle presumes an invalid</span>
</span><span id="__span-0-608"><a id="__codelineno-0-608" name="__codelineno-0-608"></a><span class="sd"> Title ID.</span>
</span><span id="__span-0-609"><a id="__codelineno-0-609" name="__codelineno-0-609"></a>
</span><span id="__span-0-610"><a id="__codelineno-0-610" name="__codelineno-0-610"></a><span class="sd"> You can use the `data` dictionary class instance attribute of each Title to store data you may need later on.</span>
</span><span id="__span-0-611"><a id="__codelineno-0-611" name="__codelineno-0-611"></a><span class="sd"> This can be useful to store information on each title that you need later, like any sub-asset IDs, or such.</span>
</span><span id="__span-0-612"><a id="__codelineno-0-612" name="__codelineno-0-612"></a><span class="sd"> """</span>
<span class="normal"><a href="#__codelineno-0-612">612</a></span>
<span class="normal"><a href="#__codelineno-0-613">613</a></span>
<span class="normal"><a href="#__codelineno-0-614">614</a></span>
<span class="normal"><a href="#__codelineno-0-615">615</a></span>
<span class="normal"><a href="#__codelineno-0-616">616</a></span>
<span class="normal"><a href="#__codelineno-0-617">617</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-604"><a id="__codelineno-0-604" name="__codelineno-0-604"></a><span class="nd">@abstractmethod</span>
</span><span id="__span-0-605"><a id="__codelineno-0-605" name="__codelineno-0-605"></a><span class="k">def</span><span class="w"> </span><span class="nf">get_titles</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Titles_T</span><span class="p">:</span>
</span><span id="__span-0-606"><a id="__codelineno-0-606" name="__codelineno-0-606"></a><span class="w"> </span><span class="sd">"""</span>
</span><span id="__span-0-607"><a id="__codelineno-0-607" name="__codelineno-0-607"></a><span class="sd"> Get Titles for the provided title ID.</span>
</span><span id="__span-0-608"><a id="__codelineno-0-608" name="__codelineno-0-608"></a>
</span><span id="__span-0-609"><a id="__codelineno-0-609" name="__codelineno-0-609"></a><span class="sd"> Return a Movies, Series, or Album objects containing Movie, Episode, or Song title objects respectively.</span>
</span><span id="__span-0-610"><a id="__codelineno-0-610" name="__codelineno-0-610"></a><span class="sd"> The returned data must be for the given title ID, or a spawn of the title ID.</span>
</span><span id="__span-0-611"><a id="__codelineno-0-611" name="__codelineno-0-611"></a>
</span><span id="__span-0-612"><a id="__codelineno-0-612" name="__codelineno-0-612"></a><span class="sd"> You must return at least one object. If you do not, unshackle presumes an invalid</span>
</span><span id="__span-0-613"><a id="__codelineno-0-613" name="__codelineno-0-613"></a><span class="sd"> Title ID.</span>
</span><span id="__span-0-614"><a id="__codelineno-0-614" name="__codelineno-0-614"></a>
</span><span id="__span-0-615"><a id="__codelineno-0-615" name="__codelineno-0-615"></a><span class="sd"> You can use the `data` dictionary class instance attribute of each Title to store data you may need later on.</span>
</span><span id="__span-0-616"><a id="__codelineno-0-616" name="__codelineno-0-616"></a><span class="sd"> This can be useful to store information on each title that you need later, like any sub-asset IDs, or such.</span>
</span><span id="__span-0-617"><a id="__codelineno-0-617" name="__codelineno-0-617"></a><span class="sd"> """</span>
</span></code></pre></div></td></tr></table></div>
</details>
</div>
@@ -4282,12 +4293,7 @@ fallback to cached data when API calls fail.</p>
<details class="mkdocstrings-source">
<summary>Source code in <code>unshackle/core/service.py</code></summary>
<div class="language-python highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-614">614</a></span>
<span class="normal"><a href="#__codelineno-0-615">615</a></span>
<span class="normal"><a href="#__codelineno-0-616">616</a></span>
<span class="normal"><a href="#__codelineno-0-617">617</a></span>
<span class="normal"><a href="#__codelineno-0-618">618</a></span>
<span class="normal"><a href="#__codelineno-0-619">619</a></span>
<div class="language-python highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-619">619</a></span>
<span class="normal"><a href="#__codelineno-0-620">620</a></span>
<span class="normal"><a href="#__codelineno-0-621">621</a></span>
<span class="normal"><a href="#__codelineno-0-622">622</a></span>
@@ -4324,49 +4330,54 @@ fallback to cached data when API calls fail.</p>
<span class="normal"><a href="#__codelineno-0-653">653</a></span>
<span class="normal"><a href="#__codelineno-0-654">654</a></span>
<span class="normal"><a href="#__codelineno-0-655">655</a></span>
<span class="normal"><a href="#__codelineno-0-656">656</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-614"><a id="__codelineno-0-614" name="__codelineno-0-614"></a><span class="k">def</span><span class="w"> </span><span class="nf">get_titles_cached</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">title_id</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="kc">None</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Titles_T</span><span class="p">:</span>
</span><span id="__span-0-615"><a id="__codelineno-0-615" name="__codelineno-0-615"></a><span class="w"> </span><span class="sd">"""</span>
</span><span id="__span-0-616"><a id="__codelineno-0-616" name="__codelineno-0-616"></a><span class="sd"> Cached wrapper around get_titles() to reduce redundant API calls.</span>
</span><span id="__span-0-617"><a id="__codelineno-0-617" name="__codelineno-0-617"></a>
</span><span id="__span-0-618"><a id="__codelineno-0-618" name="__codelineno-0-618"></a><span class="sd"> This method checks the cache before calling get_titles() and handles</span>
</span><span id="__span-0-619"><a id="__codelineno-0-619" name="__codelineno-0-619"></a><span class="sd"> fallback to cached data when API calls fail.</span>
</span><span id="__span-0-620"><a id="__codelineno-0-620" name="__codelineno-0-620"></a>
</span><span id="__span-0-621"><a id="__codelineno-0-621" name="__codelineno-0-621"></a><span class="sd"> Args:</span>
</span><span id="__span-0-622"><a id="__codelineno-0-622" name="__codelineno-0-622"></a><span class="sd"> title_id: Optional title ID for cache key generation.</span>
</span><span id="__span-0-623"><a id="__codelineno-0-623" name="__codelineno-0-623"></a><span class="sd"> If not provided, will try to extract from service instance.</span>
</span><span id="__span-0-624"><a id="__codelineno-0-624" name="__codelineno-0-624"></a>
</span><span id="__span-0-625"><a id="__codelineno-0-625" name="__codelineno-0-625"></a><span class="sd"> Returns:</span>
</span><span id="__span-0-626"><a id="__codelineno-0-626" name="__codelineno-0-626"></a><span class="sd"> Titles object (Movies, Series, or Album)</span>
</span><span id="__span-0-627"><a id="__codelineno-0-627" name="__codelineno-0-627"></a><span class="sd"> """</span>
</span><span id="__span-0-628"><a id="__codelineno-0-628" name="__codelineno-0-628"></a> <span class="k">if</span> <span class="n">title_id</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
</span><span id="__span-0-629"><a id="__codelineno-0-629" name="__codelineno-0-629"></a> <span class="c1"># Different services store the title ID in different attributes</span>
</span><span id="__span-0-630"><a id="__codelineno-0-630" name="__codelineno-0-630"></a> <span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="s2">"title"</span><span class="p">):</span>
</span><span id="__span-0-631"><a id="__codelineno-0-631" name="__codelineno-0-631"></a> <span class="n">title_id</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">title</span>
</span><span id="__span-0-632"><a id="__codelineno-0-632" name="__codelineno-0-632"></a> <span class="k">elif</span> <span class="nb">hasattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="s2">"title_id"</span><span class="p">):</span>
</span><span id="__span-0-633"><a id="__codelineno-0-633" name="__codelineno-0-633"></a> <span class="n">title_id</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">title_id</span>
</span><span id="__span-0-634"><a id="__codelineno-0-634" name="__codelineno-0-634"></a> <span class="k">else</span><span class="p">:</span>
</span><span id="__span-0-635"><a id="__codelineno-0-635" name="__codelineno-0-635"></a> <span class="c1"># If we can't determine title_id, just call get_titles directly</span>
</span><span id="__span-0-636"><a id="__codelineno-0-636" name="__codelineno-0-636"></a> <span class="bp">self</span><span class="o">.</span><span class="n">log</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">"Cannot determine title_id for caching, bypassing cache"</span><span class="p">)</span>
</span><span id="__span-0-637"><a id="__codelineno-0-637" name="__codelineno-0-637"></a> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">apply_title_map</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">get_titles</span><span class="p">())</span>
</span><span id="__span-0-638"><a id="__codelineno-0-638" name="__codelineno-0-638"></a>
</span><span id="__span-0-639"><a id="__codelineno-0-639" name="__codelineno-0-639"></a> <span class="n">no_cache</span> <span class="o">=</span> <span class="kc">False</span>
</span><span id="__span-0-640"><a id="__codelineno-0-640" name="__codelineno-0-640"></a> <span class="n">reset_cache</span> <span class="o">=</span> <span class="kc">False</span>
</span><span id="__span-0-641"><a id="__codelineno-0-641" name="__codelineno-0-641"></a> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">ctx</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">ctx</span><span class="o">.</span><span class="n">parent</span><span class="p">:</span>
</span><span id="__span-0-642"><a id="__codelineno-0-642" name="__codelineno-0-642"></a> <span class="n">no_cache</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">ctx</span><span class="o">.</span><span class="n">parent</span><span class="o">.</span><span class="n">params</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"no_cache"</span><span class="p">,</span> <span class="kc">False</span><span class="p">)</span>
</span><span id="__span-0-643"><a id="__codelineno-0-643" name="__codelineno-0-643"></a> <span class="n">reset_cache</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">ctx</span><span class="o">.</span><span class="n">parent</span><span class="o">.</span><span class="n">params</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"reset_cache"</span><span class="p">,</span> <span class="kc">False</span><span class="p">)</span>
</span><span id="__span-0-644"><a id="__codelineno-0-644" name="__codelineno-0-644"></a>
</span><span id="__span-0-645"><a id="__codelineno-0-645" name="__codelineno-0-645"></a> <span class="c1"># Get account hash for cache key</span>
</span><span id="__span-0-646"><a id="__codelineno-0-646" name="__codelineno-0-646"></a> <span class="n">account_hash</span> <span class="o">=</span> <span class="n">get_account_hash</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">credential</span><span class="p">)</span>
</span><span id="__span-0-647"><a id="__codelineno-0-647" name="__codelineno-0-647"></a>
</span><span id="__span-0-648"><a id="__codelineno-0-648" name="__codelineno-0-648"></a> <span class="n">titles</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">title_cache</span><span class="o">.</span><span class="n">get_cached_titles</span><span class="p">(</span>
</span><span id="__span-0-649"><a id="__codelineno-0-649" name="__codelineno-0-649"></a> <span class="n">title_id</span><span class="o">=</span><span class="nb">str</span><span class="p">(</span><span class="n">title_id</span><span class="p">),</span>
</span><span id="__span-0-650"><a id="__codelineno-0-650" name="__codelineno-0-650"></a> <span class="n">fetch_function</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">get_titles</span><span class="p">,</span>
</span><span id="__span-0-651"><a id="__codelineno-0-651" name="__codelineno-0-651"></a> <span class="n">region</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">current_region</span><span class="p">,</span>
</span><span id="__span-0-652"><a id="__codelineno-0-652" name="__codelineno-0-652"></a> <span class="n">account_hash</span><span class="o">=</span><span class="n">account_hash</span><span class="p">,</span>
</span><span id="__span-0-653"><a id="__codelineno-0-653" name="__codelineno-0-653"></a> <span class="n">no_cache</span><span class="o">=</span><span class="n">no_cache</span><span class="p">,</span>
</span><span id="__span-0-654"><a id="__codelineno-0-654" name="__codelineno-0-654"></a> <span class="n">reset_cache</span><span class="o">=</span><span class="n">reset_cache</span><span class="p">,</span>
</span><span id="__span-0-655"><a id="__codelineno-0-655" name="__codelineno-0-655"></a> <span class="p">)</span>
</span><span id="__span-0-656"><a id="__codelineno-0-656" name="__codelineno-0-656"></a> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">apply_title_map</span><span class="p">(</span><span class="n">titles</span><span class="p">)</span>
<span class="normal"><a href="#__codelineno-0-656">656</a></span>
<span class="normal"><a href="#__codelineno-0-657">657</a></span>
<span class="normal"><a href="#__codelineno-0-658">658</a></span>
<span class="normal"><a href="#__codelineno-0-659">659</a></span>
<span class="normal"><a href="#__codelineno-0-660">660</a></span>
<span class="normal"><a href="#__codelineno-0-661">661</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-619"><a id="__codelineno-0-619" name="__codelineno-0-619"></a><span class="k">def</span><span class="w"> </span><span class="nf">get_titles_cached</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">title_id</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="kc">None</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Titles_T</span><span class="p">:</span>
</span><span id="__span-0-620"><a id="__codelineno-0-620" name="__codelineno-0-620"></a><span class="w"> </span><span class="sd">"""</span>
</span><span id="__span-0-621"><a id="__codelineno-0-621" name="__codelineno-0-621"></a><span class="sd"> Cached wrapper around get_titles() to reduce redundant API calls.</span>
</span><span id="__span-0-622"><a id="__codelineno-0-622" name="__codelineno-0-622"></a>
</span><span id="__span-0-623"><a id="__codelineno-0-623" name="__codelineno-0-623"></a><span class="sd"> This method checks the cache before calling get_titles() and handles</span>
</span><span id="__span-0-624"><a id="__codelineno-0-624" name="__codelineno-0-624"></a><span class="sd"> fallback to cached data when API calls fail.</span>
</span><span id="__span-0-625"><a id="__codelineno-0-625" name="__codelineno-0-625"></a>
</span><span id="__span-0-626"><a id="__codelineno-0-626" name="__codelineno-0-626"></a><span class="sd"> Args:</span>
</span><span id="__span-0-627"><a id="__codelineno-0-627" name="__codelineno-0-627"></a><span class="sd"> title_id: Optional title ID for cache key generation.</span>
</span><span id="__span-0-628"><a id="__codelineno-0-628" name="__codelineno-0-628"></a><span class="sd"> If not provided, will try to extract from service instance.</span>
</span><span id="__span-0-629"><a id="__codelineno-0-629" name="__codelineno-0-629"></a>
</span><span id="__span-0-630"><a id="__codelineno-0-630" name="__codelineno-0-630"></a><span class="sd"> Returns:</span>
</span><span id="__span-0-631"><a id="__codelineno-0-631" name="__codelineno-0-631"></a><span class="sd"> Titles object (Movies, Series, or Album)</span>
</span><span id="__span-0-632"><a id="__codelineno-0-632" name="__codelineno-0-632"></a><span class="sd"> """</span>
</span><span id="__span-0-633"><a id="__codelineno-0-633" name="__codelineno-0-633"></a> <span class="k">if</span> <span class="n">title_id</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
</span><span id="__span-0-634"><a id="__codelineno-0-634" name="__codelineno-0-634"></a> <span class="c1"># Different services store the title ID in different attributes</span>
</span><span id="__span-0-635"><a id="__codelineno-0-635" name="__codelineno-0-635"></a> <span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="s2">"title"</span><span class="p">):</span>
</span><span id="__span-0-636"><a id="__codelineno-0-636" name="__codelineno-0-636"></a> <span class="n">title_id</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">title</span>
</span><span id="__span-0-637"><a id="__codelineno-0-637" name="__codelineno-0-637"></a> <span class="k">elif</span> <span class="nb">hasattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="s2">"title_id"</span><span class="p">):</span>
</span><span id="__span-0-638"><a id="__codelineno-0-638" name="__codelineno-0-638"></a> <span class="n">title_id</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">title_id</span>
</span><span id="__span-0-639"><a id="__codelineno-0-639" name="__codelineno-0-639"></a> <span class="k">else</span><span class="p">:</span>
</span><span id="__span-0-640"><a id="__codelineno-0-640" name="__codelineno-0-640"></a> <span class="c1"># If we can't determine title_id, just call get_titles directly</span>
</span><span id="__span-0-641"><a id="__codelineno-0-641" name="__codelineno-0-641"></a> <span class="bp">self</span><span class="o">.</span><span class="n">log</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">"Cannot determine title_id for caching, bypassing cache"</span><span class="p">)</span>
</span><span id="__span-0-642"><a id="__codelineno-0-642" name="__codelineno-0-642"></a> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">apply_title_map</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">get_titles</span><span class="p">())</span>
</span><span id="__span-0-643"><a id="__codelineno-0-643" name="__codelineno-0-643"></a>
</span><span id="__span-0-644"><a id="__codelineno-0-644" name="__codelineno-0-644"></a> <span class="n">no_cache</span> <span class="o">=</span> <span class="kc">False</span>
</span><span id="__span-0-645"><a id="__codelineno-0-645" name="__codelineno-0-645"></a> <span class="n">reset_cache</span> <span class="o">=</span> <span class="kc">False</span>
</span><span id="__span-0-646"><a id="__codelineno-0-646" name="__codelineno-0-646"></a> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">ctx</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">ctx</span><span class="o">.</span><span class="n">parent</span><span class="p">:</span>
</span><span id="__span-0-647"><a id="__codelineno-0-647" name="__codelineno-0-647"></a> <span class="n">no_cache</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">ctx</span><span class="o">.</span><span class="n">parent</span><span class="o">.</span><span class="n">params</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"no_cache"</span><span class="p">,</span> <span class="kc">False</span><span class="p">)</span>
</span><span id="__span-0-648"><a id="__codelineno-0-648" name="__codelineno-0-648"></a> <span class="n">reset_cache</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">ctx</span><span class="o">.</span><span class="n">parent</span><span class="o">.</span><span class="n">params</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"reset_cache"</span><span class="p">,</span> <span class="kc">False</span><span class="p">)</span>
</span><span id="__span-0-649"><a id="__codelineno-0-649" name="__codelineno-0-649"></a>
</span><span id="__span-0-650"><a id="__codelineno-0-650" name="__codelineno-0-650"></a> <span class="c1"># Get account hash for cache key</span>
</span><span id="__span-0-651"><a id="__codelineno-0-651" name="__codelineno-0-651"></a> <span class="n">account_hash</span> <span class="o">=</span> <span class="n">get_account_hash</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">credential</span><span class="p">)</span>
</span><span id="__span-0-652"><a id="__codelineno-0-652" name="__codelineno-0-652"></a>
</span><span id="__span-0-653"><a id="__codelineno-0-653" name="__codelineno-0-653"></a> <span class="n">titles</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">title_cache</span><span class="o">.</span><span class="n">get_cached_titles</span><span class="p">(</span>
</span><span id="__span-0-654"><a id="__codelineno-0-654" name="__codelineno-0-654"></a> <span class="n">title_id</span><span class="o">=</span><span class="nb">str</span><span class="p">(</span><span class="n">title_id</span><span class="p">),</span>
</span><span id="__span-0-655"><a id="__codelineno-0-655" name="__codelineno-0-655"></a> <span class="n">fetch_function</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">get_titles</span><span class="p">,</span>
</span><span id="__span-0-656"><a id="__codelineno-0-656" name="__codelineno-0-656"></a> <span class="n">region</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">current_region</span><span class="p">,</span>
</span><span id="__span-0-657"><a id="__codelineno-0-657" name="__codelineno-0-657"></a> <span class="n">account_hash</span><span class="o">=</span><span class="n">account_hash</span><span class="p">,</span>
</span><span id="__span-0-658"><a id="__codelineno-0-658" name="__codelineno-0-658"></a> <span class="n">no_cache</span><span class="o">=</span><span class="n">no_cache</span><span class="p">,</span>
</span><span id="__span-0-659"><a id="__codelineno-0-659" name="__codelineno-0-659"></a> <span class="n">reset_cache</span><span class="o">=</span><span class="n">reset_cache</span><span class="p">,</span>
</span><span id="__span-0-660"><a id="__codelineno-0-660" name="__codelineno-0-660"></a> <span class="p">)</span>
</span><span id="__span-0-661"><a id="__codelineno-0-661" name="__codelineno-0-661"></a> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">apply_title_map</span><span class="p">(</span><span class="n">titles</span><span class="p">)</span>
</span></code></pre></div></td></tr></table></div>
</details>
</div>
@@ -4394,23 +4405,23 @@ title cache so config edits take effect without a cache reset, and before any
<details class="mkdocstrings-source">
<summary>Source code in <code>unshackle/core/service.py</code></summary>
<div class="language-python highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-658">658</a></span>
<span class="normal"><a href="#__codelineno-0-659">659</a></span>
<span class="normal"><a href="#__codelineno-0-660">660</a></span>
<span class="normal"><a href="#__codelineno-0-661">661</a></span>
<span class="normal"><a href="#__codelineno-0-662">662</a></span>
<span class="normal"><a href="#__codelineno-0-663">663</a></span>
<div class="language-python highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-663">663</a></span>
<span class="normal"><a href="#__codelineno-0-664">664</a></span>
<span class="normal"><a href="#__codelineno-0-665">665</a></span>
<span class="normal"><a href="#__codelineno-0-666">666</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-658"><a id="__codelineno-0-658" name="__codelineno-0-658"></a><span class="k">def</span><span class="w"> </span><span class="nf">apply_title_map</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">titles</span><span class="p">:</span> <span class="n">Titles_T</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Titles_T</span><span class="p">:</span>
</span><span id="__span-0-659"><a id="__codelineno-0-659" name="__codelineno-0-659"></a><span class="w"> </span><span class="sd">"""</span>
</span><span id="__span-0-660"><a id="__codelineno-0-660" name="__codelineno-0-660"></a><span class="sd"> Rewrite service-provided titles using the per-service ``title_map`` config.</span>
</span><span id="__span-0-661"><a id="__codelineno-0-661" name="__codelineno-0-661"></a>
</span><span id="__span-0-662"><a id="__codelineno-0-662" name="__codelineno-0-662"></a><span class="sd"> ``title_map`` lives under ``services.&lt;TAG&gt;`` in unshackle.yaml. Applied after the</span>
</span><span id="__span-0-663"><a id="__codelineno-0-663" name="__codelineno-0-663"></a><span class="sd"> title cache so config edits take effect without a cache reset, and before any</span>
</span><span id="__span-0-664"><a id="__codelineno-0-664" name="__codelineno-0-664"></a><span class="sd"> ``--enrich`` override so enrich wins. See ``remap_titles`` for the match rules.</span>
</span><span id="__span-0-665"><a id="__codelineno-0-665" name="__codelineno-0-665"></a><span class="sd"> """</span>
</span><span id="__span-0-666"><a id="__codelineno-0-666" name="__codelineno-0-666"></a> <span class="k">return</span> <span class="n">remap_titles</span><span class="p">(</span><span class="n">titles</span><span class="p">,</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">config</span> <span class="ow">or</span> <span class="p">{})</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"title_map"</span><span class="p">)</span> <span class="ow">or</span> <span class="p">{})</span>
<span class="normal"><a href="#__codelineno-0-666">666</a></span>
<span class="normal"><a href="#__codelineno-0-667">667</a></span>
<span class="normal"><a href="#__codelineno-0-668">668</a></span>
<span class="normal"><a href="#__codelineno-0-669">669</a></span>
<span class="normal"><a href="#__codelineno-0-670">670</a></span>
<span class="normal"><a href="#__codelineno-0-671">671</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-663"><a id="__codelineno-0-663" name="__codelineno-0-663"></a><span class="k">def</span><span class="w"> </span><span class="nf">apply_title_map</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">titles</span><span class="p">:</span> <span class="n">Titles_T</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Titles_T</span><span class="p">:</span>
</span><span id="__span-0-664"><a id="__codelineno-0-664" name="__codelineno-0-664"></a><span class="w"> </span><span class="sd">"""</span>
</span><span id="__span-0-665"><a id="__codelineno-0-665" name="__codelineno-0-665"></a><span class="sd"> Rewrite service-provided titles using the per-service ``title_map`` config.</span>
</span><span id="__span-0-666"><a id="__codelineno-0-666" name="__codelineno-0-666"></a>
</span><span id="__span-0-667"><a id="__codelineno-0-667" name="__codelineno-0-667"></a><span class="sd"> ``title_map`` lives under ``services.&lt;TAG&gt;`` in unshackle.yaml. Applied after the</span>
</span><span id="__span-0-668"><a id="__codelineno-0-668" name="__codelineno-0-668"></a><span class="sd"> title cache so config edits take effect without a cache reset, and before any</span>
</span><span id="__span-0-669"><a id="__codelineno-0-669" name="__codelineno-0-669"></a><span class="sd"> ``--enrich`` override so enrich wins. See ``remap_titles`` for the match rules.</span>
</span><span id="__span-0-670"><a id="__codelineno-0-670" name="__codelineno-0-670"></a><span class="sd"> """</span>
</span><span id="__span-0-671"><a id="__codelineno-0-671" name="__codelineno-0-671"></a> <span class="k">return</span> <span class="n">remap_titles</span><span class="p">(</span><span class="n">titles</span><span class="p">,</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">config</span> <span class="ow">or</span> <span class="p">{})</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"title_map"</span><span class="p">)</span> <span class="ow">or</span> <span class="p">{})</span>
</span></code></pre></div></td></tr></table></div>
</details>
</div>
@@ -4457,12 +4468,7 @@ the Track's media data, then do.</p>
<details class="mkdocstrings-source">
<summary>Source code in <code>unshackle/core/service.py</code></summary>
<div class="language-python highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-668">668</a></span>
<span class="normal"><a href="#__codelineno-0-669">669</a></span>
<span class="normal"><a href="#__codelineno-0-670">670</a></span>
<span class="normal"><a href="#__codelineno-0-671">671</a></span>
<span class="normal"><a href="#__codelineno-0-672">672</a></span>
<span class="normal"><a href="#__codelineno-0-673">673</a></span>
<div class="language-python highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-673">673</a></span>
<span class="normal"><a href="#__codelineno-0-674">674</a></span>
<span class="normal"><a href="#__codelineno-0-675">675</a></span>
<span class="normal"><a href="#__codelineno-0-676">676</a></span>
@@ -4486,36 +4492,41 @@ the Track's media data, then do.</p>
<span class="normal"><a href="#__codelineno-0-694">694</a></span>
<span class="normal"><a href="#__codelineno-0-695">695</a></span>
<span class="normal"><a href="#__codelineno-0-696">696</a></span>
<span class="normal"><a href="#__codelineno-0-697">697</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-668"><a id="__codelineno-0-668" name="__codelineno-0-668"></a><span class="nd">@abstractmethod</span>
</span><span id="__span-0-669"><a id="__codelineno-0-669" name="__codelineno-0-669"></a><span class="k">def</span><span class="w"> </span><span class="nf">get_tracks</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">title</span><span class="p">:</span> <span class="n">Title_T</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Tracks</span><span class="p">:</span>
</span><span id="__span-0-670"><a id="__codelineno-0-670" name="__codelineno-0-670"></a><span class="w"> </span><span class="sd">"""</span>
</span><span id="__span-0-671"><a id="__codelineno-0-671" name="__codelineno-0-671"></a><span class="sd"> Get Track objects of the Title.</span>
</span><span id="__span-0-672"><a id="__codelineno-0-672" name="__codelineno-0-672"></a>
</span><span id="__span-0-673"><a id="__codelineno-0-673" name="__codelineno-0-673"></a><span class="sd"> Return a Tracks object, which itself can contain Video, Audio, Subtitle or even Chapters.</span>
</span><span id="__span-0-674"><a id="__codelineno-0-674" name="__codelineno-0-674"></a><span class="sd"> Tracks.videos, Tracks.audio, Tracks.subtitles, and Track.chapters should be a List of Track objects.</span>
</span><span id="__span-0-675"><a id="__codelineno-0-675" name="__codelineno-0-675"></a>
</span><span id="__span-0-676"><a id="__codelineno-0-676" name="__codelineno-0-676"></a><span class="sd"> Each Track in the Tracks should represent a Video/Audio track, Representation, or</span>
</span><span id="__span-0-677"><a id="__codelineno-0-677" name="__codelineno-0-677"></a><span class="sd"> Adaptation, or a Subtitle file.</span>
</span><span id="__span-0-678"><a id="__codelineno-0-678" name="__codelineno-0-678"></a>
</span><span id="__span-0-679"><a id="__codelineno-0-679" name="__codelineno-0-679"></a><span class="sd"> While one Track should only hold information for one downloadable track, try to get as many</span>
</span><span id="__span-0-680"><a id="__codelineno-0-680" name="__codelineno-0-680"></a><span class="sd"> unique Track objects per track type so track selection by the root code can give you more</span>
</span><span id="__span-0-681"><a id="__codelineno-0-681" name="__codelineno-0-681"></a><span class="sd"> options in terms of Resolution, Bitrate, Codecs, Language, and such.</span>
</span><span id="__span-0-682"><a id="__codelineno-0-682" name="__codelineno-0-682"></a>
</span><span id="__span-0-683"><a id="__codelineno-0-683" name="__codelineno-0-683"></a><span class="sd"> No decision making or filtering of which Tracks get returned should happen here. It can be</span>
</span><span id="__span-0-684"><a id="__codelineno-0-684" name="__codelineno-0-684"></a><span class="sd"> considered an error to filter for e.g. resolution, codec, and such. All filtering based on</span>
</span><span id="__span-0-685"><a id="__codelineno-0-685" name="__codelineno-0-685"></a><span class="sd"> arguments will be done by the root code automatically when needed.</span>
</span><span id="__span-0-686"><a id="__codelineno-0-686" name="__codelineno-0-686"></a>
</span><span id="__span-0-687"><a id="__codelineno-0-687" name="__codelineno-0-687"></a><span class="sd"> Make sure you correctly mark which Tracks have encryption, and which DRM System they</span>
</span><span id="__span-0-688"><a id="__codelineno-0-688" name="__codelineno-0-688"></a><span class="sd"> use, with the `drm` property.</span>
</span><span id="__span-0-689"><a id="__codelineno-0-689" name="__codelineno-0-689"></a>
</span><span id="__span-0-690"><a id="__codelineno-0-690" name="__codelineno-0-690"></a><span class="sd"> If you can get the Track's KID (Key ID) as a 32 char (16 bit) HEX string, give it to the</span>
</span><span id="__span-0-691"><a id="__codelineno-0-691" name="__codelineno-0-691"></a><span class="sd"> Track's `kid` variable, as it will speed up the decryption process later on. The service</span>
</span><span id="__span-0-692"><a id="__codelineno-0-692" name="__codelineno-0-692"></a><span class="sd"> decides whether it is necessary. Generally if you can give it, without downloading any of</span>
</span><span id="__span-0-693"><a id="__codelineno-0-693" name="__codelineno-0-693"></a><span class="sd"> the Track's media data, then do.</span>
<span class="normal"><a href="#__codelineno-0-697">697</a></span>
<span class="normal"><a href="#__codelineno-0-698">698</a></span>
<span class="normal"><a href="#__codelineno-0-699">699</a></span>
<span class="normal"><a href="#__codelineno-0-700">700</a></span>
<span class="normal"><a href="#__codelineno-0-701">701</a></span>
<span class="normal"><a href="#__codelineno-0-702">702</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-673"><a id="__codelineno-0-673" name="__codelineno-0-673"></a><span class="nd">@abstractmethod</span>
</span><span id="__span-0-674"><a id="__codelineno-0-674" name="__codelineno-0-674"></a><span class="k">def</span><span class="w"> </span><span class="nf">get_tracks</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">title</span><span class="p">:</span> <span class="n">Title_T</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Tracks</span><span class="p">:</span>
</span><span id="__span-0-675"><a id="__codelineno-0-675" name="__codelineno-0-675"></a><span class="w"> </span><span class="sd">"""</span>
</span><span id="__span-0-676"><a id="__codelineno-0-676" name="__codelineno-0-676"></a><span class="sd"> Get Track objects of the Title.</span>
</span><span id="__span-0-677"><a id="__codelineno-0-677" name="__codelineno-0-677"></a>
</span><span id="__span-0-678"><a id="__codelineno-0-678" name="__codelineno-0-678"></a><span class="sd"> Return a Tracks object, which itself can contain Video, Audio, Subtitle or even Chapters.</span>
</span><span id="__span-0-679"><a id="__codelineno-0-679" name="__codelineno-0-679"></a><span class="sd"> Tracks.videos, Tracks.audio, Tracks.subtitles, and Track.chapters should be a List of Track objects.</span>
</span><span id="__span-0-680"><a id="__codelineno-0-680" name="__codelineno-0-680"></a>
</span><span id="__span-0-681"><a id="__codelineno-0-681" name="__codelineno-0-681"></a><span class="sd"> Each Track in the Tracks should represent a Video/Audio track, Representation, or</span>
</span><span id="__span-0-682"><a id="__codelineno-0-682" name="__codelineno-0-682"></a><span class="sd"> Adaptation, or a Subtitle file.</span>
</span><span id="__span-0-683"><a id="__codelineno-0-683" name="__codelineno-0-683"></a>
</span><span id="__span-0-684"><a id="__codelineno-0-684" name="__codelineno-0-684"></a><span class="sd"> While one Track should only hold information for one downloadable track, try to get as many</span>
</span><span id="__span-0-685"><a id="__codelineno-0-685" name="__codelineno-0-685"></a><span class="sd"> unique Track objects per track type so track selection by the root code can give you more</span>
</span><span id="__span-0-686"><a id="__codelineno-0-686" name="__codelineno-0-686"></a><span class="sd"> options in terms of Resolution, Bitrate, Codecs, Language, and such.</span>
</span><span id="__span-0-687"><a id="__codelineno-0-687" name="__codelineno-0-687"></a>
</span><span id="__span-0-688"><a id="__codelineno-0-688" name="__codelineno-0-688"></a><span class="sd"> No decision making or filtering of which Tracks get returned should happen here. It can be</span>
</span><span id="__span-0-689"><a id="__codelineno-0-689" name="__codelineno-0-689"></a><span class="sd"> considered an error to filter for e.g. resolution, codec, and such. All filtering based on</span>
</span><span id="__span-0-690"><a id="__codelineno-0-690" name="__codelineno-0-690"></a><span class="sd"> arguments will be done by the root code automatically when needed.</span>
</span><span id="__span-0-691"><a id="__codelineno-0-691" name="__codelineno-0-691"></a>
</span><span id="__span-0-692"><a id="__codelineno-0-692" name="__codelineno-0-692"></a><span class="sd"> Make sure you correctly mark which Tracks have encryption, and which DRM System they</span>
</span><span id="__span-0-693"><a id="__codelineno-0-693" name="__codelineno-0-693"></a><span class="sd"> use, with the `drm` property.</span>
</span><span id="__span-0-694"><a id="__codelineno-0-694" name="__codelineno-0-694"></a>
</span><span id="__span-0-695"><a id="__codelineno-0-695" name="__codelineno-0-695"></a><span class="sd"> :param title: The current `Title` from get_titles that unshackle processes now.</span>
</span><span id="__span-0-696"><a id="__codelineno-0-696" name="__codelineno-0-696"></a><span class="sd"> :return: Tracks object containing Video, Audio, Subtitles, and Chapters, if available.</span>
</span><span id="__span-0-697"><a id="__codelineno-0-697" name="__codelineno-0-697"></a><span class="sd"> """</span>
</span><span id="__span-0-695"><a id="__codelineno-0-695" name="__codelineno-0-695"></a><span class="sd"> If you can get the Track's KID (Key ID) as a 32 char (16 bit) HEX string, give it to the</span>
</span><span id="__span-0-696"><a id="__codelineno-0-696" name="__codelineno-0-696"></a><span class="sd"> Track's `kid` variable, as it will speed up the decryption process later on. The service</span>
</span><span id="__span-0-697"><a id="__codelineno-0-697" name="__codelineno-0-697"></a><span class="sd"> decides whether it is necessary. Generally if you can give it, without downloading any of</span>
</span><span id="__span-0-698"><a id="__codelineno-0-698" name="__codelineno-0-698"></a><span class="sd"> the Track's media data, then do.</span>
</span><span id="__span-0-699"><a id="__codelineno-0-699" name="__codelineno-0-699"></a>
</span><span id="__span-0-700"><a id="__codelineno-0-700" name="__codelineno-0-700"></a><span class="sd"> :param title: The current `Title` from get_titles that unshackle processes now.</span>
</span><span id="__span-0-701"><a id="__codelineno-0-701" name="__codelineno-0-701"></a><span class="sd"> :return: Tracks object containing Video, Audio, Subtitles, and Chapters, if available.</span>
</span><span id="__span-0-702"><a id="__codelineno-0-702" name="__codelineno-0-702"></a><span class="sd"> """</span>
</span></code></pre></div></td></tr></table></div>
</details>
</div>
@@ -4582,12 +4593,7 @@ option <code>chapter_fallback_name</code>. For example, <code>"Chapter {i:02}"</
<details class="mkdocstrings-source">
<summary>Source code in <code>unshackle/core/service.py</code></summary>
<div class="language-python highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-699">699</a></span>
<span class="normal"><a href="#__codelineno-0-700">700</a></span>
<span class="normal"><a href="#__codelineno-0-701">701</a></span>
<span class="normal"><a href="#__codelineno-0-702">702</a></span>
<span class="normal"><a href="#__codelineno-0-703">703</a></span>
<span class="normal"><a href="#__codelineno-0-704">704</a></span>
<div class="language-python highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-704">704</a></span>
<span class="normal"><a href="#__codelineno-0-705">705</a></span>
<span class="normal"><a href="#__codelineno-0-706">706</a></span>
<span class="normal"><a href="#__codelineno-0-707">707</a></span>
@@ -4599,24 +4605,29 @@ option <code>chapter_fallback_name</code>. For example, <code>"Chapter {i:02}"</
<span class="normal"><a href="#__codelineno-0-713">713</a></span>
<span class="normal"><a href="#__codelineno-0-714">714</a></span>
<span class="normal"><a href="#__codelineno-0-715">715</a></span>
<span class="normal"><a href="#__codelineno-0-716">716</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-699"><a id="__codelineno-0-699" name="__codelineno-0-699"></a><span class="nd">@abstractmethod</span>
</span><span id="__span-0-700"><a id="__codelineno-0-700" name="__codelineno-0-700"></a><span class="k">def</span><span class="w"> </span><span class="nf">get_chapters</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">title</span><span class="p">:</span> <span class="n">Title_T</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Chapters</span><span class="p">:</span>
</span><span id="__span-0-701"><a id="__codelineno-0-701" name="__codelineno-0-701"></a><span class="w"> </span><span class="sd">"""</span>
</span><span id="__span-0-702"><a id="__codelineno-0-702" name="__codelineno-0-702"></a><span class="sd"> Get Chapters for the Title.</span>
</span><span id="__span-0-703"><a id="__codelineno-0-703" name="__codelineno-0-703"></a>
</span><span id="__span-0-704"><a id="__codelineno-0-704" name="__codelineno-0-704"></a><span class="sd"> Parameters:</span>
</span><span id="__span-0-705"><a id="__codelineno-0-705" name="__codelineno-0-705"></a><span class="sd"> title: The current Title from `get_titles` that unshackle processes now.</span>
</span><span id="__span-0-706"><a id="__codelineno-0-706" name="__codelineno-0-706"></a>
</span><span id="__span-0-707"><a id="__codelineno-0-707" name="__codelineno-0-707"></a><span class="sd"> You must return a Chapters object containing 0 or more Chapter objects.</span>
<span class="normal"><a href="#__codelineno-0-716">716</a></span>
<span class="normal"><a href="#__codelineno-0-717">717</a></span>
<span class="normal"><a href="#__codelineno-0-718">718</a></span>
<span class="normal"><a href="#__codelineno-0-719">719</a></span>
<span class="normal"><a href="#__codelineno-0-720">720</a></span>
<span class="normal"><a href="#__codelineno-0-721">721</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-704"><a id="__codelineno-0-704" name="__codelineno-0-704"></a><span class="nd">@abstractmethod</span>
</span><span id="__span-0-705"><a id="__codelineno-0-705" name="__codelineno-0-705"></a><span class="k">def</span><span class="w"> </span><span class="nf">get_chapters</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">title</span><span class="p">:</span> <span class="n">Title_T</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Chapters</span><span class="p">:</span>
</span><span id="__span-0-706"><a id="__codelineno-0-706" name="__codelineno-0-706"></a><span class="w"> </span><span class="sd">"""</span>
</span><span id="__span-0-707"><a id="__codelineno-0-707" name="__codelineno-0-707"></a><span class="sd"> Get Chapters for the Title.</span>
</span><span id="__span-0-708"><a id="__codelineno-0-708" name="__codelineno-0-708"></a>
</span><span id="__span-0-709"><a id="__codelineno-0-709" name="__codelineno-0-709"></a><span class="sd"> You do not need to set a Chapter number or sort/order the chapters in any way as</span>
</span><span id="__span-0-710"><a id="__codelineno-0-710" name="__codelineno-0-710"></a><span class="sd"> the Chapters class automatically handles all of that for you. If there is no</span>
</span><span id="__span-0-711"><a id="__codelineno-0-711" name="__codelineno-0-711"></a><span class="sd"> descriptive name for a Chapter then do not set a name at all.</span>
</span><span id="__span-0-712"><a id="__codelineno-0-712" name="__codelineno-0-712"></a>
</span><span id="__span-0-713"><a id="__codelineno-0-713" name="__codelineno-0-713"></a><span class="sd"> You must not set Chapter names to "Chapter {n}" or such. If you (or the user)</span>
</span><span id="__span-0-714"><a id="__codelineno-0-714" name="__codelineno-0-714"></a><span class="sd"> wants "Chapter {n}" style Chapter names (or similar) then they can use the config</span>
</span><span id="__span-0-715"><a id="__codelineno-0-715" name="__codelineno-0-715"></a><span class="sd"> option `chapter_fallback_name`. For example, `"Chapter {i:02}"` for "Chapter 01".</span>
</span><span id="__span-0-716"><a id="__codelineno-0-716" name="__codelineno-0-716"></a><span class="sd"> """</span>
</span><span id="__span-0-709"><a id="__codelineno-0-709" name="__codelineno-0-709"></a><span class="sd"> Parameters:</span>
</span><span id="__span-0-710"><a id="__codelineno-0-710" name="__codelineno-0-710"></a><span class="sd"> title: The current Title from `get_titles` that unshackle processes now.</span>
</span><span id="__span-0-711"><a id="__codelineno-0-711" name="__codelineno-0-711"></a>
</span><span id="__span-0-712"><a id="__codelineno-0-712" name="__codelineno-0-712"></a><span class="sd"> You must return a Chapters object containing 0 or more Chapter objects.</span>
</span><span id="__span-0-713"><a id="__codelineno-0-713" name="__codelineno-0-713"></a>
</span><span id="__span-0-714"><a id="__codelineno-0-714" name="__codelineno-0-714"></a><span class="sd"> You do not need to set a Chapter number or sort/order the chapters in any way as</span>
</span><span id="__span-0-715"><a id="__codelineno-0-715" name="__codelineno-0-715"></a><span class="sd"> the Chapters class automatically handles all of that for you. If there is no</span>
</span><span id="__span-0-716"><a id="__codelineno-0-716" name="__codelineno-0-716"></a><span class="sd"> descriptive name for a Chapter then do not set a name at all.</span>
</span><span id="__span-0-717"><a id="__codelineno-0-717" name="__codelineno-0-717"></a>
</span><span id="__span-0-718"><a id="__codelineno-0-718" name="__codelineno-0-718"></a><span class="sd"> You must not set Chapter names to "Chapter {n}" or such. If you (or the user)</span>
</span><span id="__span-0-719"><a id="__codelineno-0-719" name="__codelineno-0-719"></a><span class="sd"> wants "Chapter {n}" style Chapter names (or similar) then they can use the config</span>
</span><span id="__span-0-720"><a id="__codelineno-0-720" name="__codelineno-0-720"></a><span class="sd"> option `chapter_fallback_name`. For example, `"Chapter {i:02}"` for "Chapter 01".</span>
</span><span id="__span-0-721"><a id="__codelineno-0-721" name="__codelineno-0-721"></a><span class="sd"> """</span>
</span></code></pre></div></td></tr></table></div>
</details>
</div>
@@ -4688,21 +4699,21 @@ option <code>chapter_fallback_name</code>. For example, <code>"Chapter {i:02}"</
<details class="mkdocstrings-source">
<summary>Source code in <code>unshackle/core/service.py</code></summary>
<div class="language-python highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-720">720</a></span>
<span class="normal"><a href="#__codelineno-0-721">721</a></span>
<span class="normal"><a href="#__codelineno-0-722">722</a></span>
<span class="normal"><a href="#__codelineno-0-723">723</a></span>
<span class="normal"><a href="#__codelineno-0-724">724</a></span>
<span class="normal"><a href="#__codelineno-0-725">725</a></span>
<div class="language-python highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-725">725</a></span>
<span class="normal"><a href="#__codelineno-0-726">726</a></span>
<span class="normal"><a href="#__codelineno-0-727">727</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-720"><a id="__codelineno-0-720" name="__codelineno-0-720"></a><span class="k">def</span><span class="w"> </span><span class="nf">on_segment_downloaded</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">track</span><span class="p">:</span> <span class="n">AnyTrack</span><span class="p">,</span> <span class="n">segment</span><span class="p">:</span> <span class="n">Path</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span><span id="__span-0-721"><a id="__codelineno-0-721" name="__codelineno-0-721"></a><span class="w"> </span><span class="sd">"""</span>
</span><span id="__span-0-722"><a id="__codelineno-0-722" name="__codelineno-0-722"></a><span class="sd"> Called when one of a Track's Segments has finished downloading.</span>
</span><span id="__span-0-723"><a id="__codelineno-0-723" name="__codelineno-0-723"></a>
</span><span id="__span-0-724"><a id="__codelineno-0-724" name="__codelineno-0-724"></a><span class="sd"> Parameters:</span>
</span><span id="__span-0-725"><a id="__codelineno-0-725" name="__codelineno-0-725"></a><span class="sd"> track: The Track object that had a Segment downloaded.</span>
</span><span id="__span-0-726"><a id="__codelineno-0-726" name="__codelineno-0-726"></a><span class="sd"> segment: The Path to the downloaded Segment.</span>
</span><span id="__span-0-727"><a id="__codelineno-0-727" name="__codelineno-0-727"></a><span class="sd"> """</span>
<span class="normal"><a href="#__codelineno-0-727">727</a></span>
<span class="normal"><a href="#__codelineno-0-728">728</a></span>
<span class="normal"><a href="#__codelineno-0-729">729</a></span>
<span class="normal"><a href="#__codelineno-0-730">730</a></span>
<span class="normal"><a href="#__codelineno-0-731">731</a></span>
<span class="normal"><a href="#__codelineno-0-732">732</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-725"><a id="__codelineno-0-725" name="__codelineno-0-725"></a><span class="k">def</span><span class="w"> </span><span class="nf">on_segment_downloaded</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">track</span><span class="p">:</span> <span class="n">AnyTrack</span><span class="p">,</span> <span class="n">segment</span><span class="p">:</span> <span class="n">Path</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span><span id="__span-0-726"><a id="__codelineno-0-726" name="__codelineno-0-726"></a><span class="w"> </span><span class="sd">"""</span>
</span><span id="__span-0-727"><a id="__codelineno-0-727" name="__codelineno-0-727"></a><span class="sd"> Called when one of a Track's Segments has finished downloading.</span>
</span><span id="__span-0-728"><a id="__codelineno-0-728" name="__codelineno-0-728"></a>
</span><span id="__span-0-729"><a id="__codelineno-0-729" name="__codelineno-0-729"></a><span class="sd"> Parameters:</span>
</span><span id="__span-0-730"><a id="__codelineno-0-730" name="__codelineno-0-730"></a><span class="sd"> track: The Track object that had a Segment downloaded.</span>
</span><span id="__span-0-731"><a id="__codelineno-0-731" name="__codelineno-0-731"></a><span class="sd"> segment: The Path to the downloaded Segment.</span>
</span><span id="__span-0-732"><a id="__codelineno-0-732" name="__codelineno-0-732"></a><span class="sd"> """</span>
</span></code></pre></div></td></tr></table></div>
</details>
</div>
@@ -4758,19 +4769,19 @@ option <code>chapter_fallback_name</code>. For example, <code>"Chapter {i:02}"</
<details class="mkdocstrings-source">
<summary>Source code in <code>unshackle/core/service.py</code></summary>
<div class="language-python highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-729">729</a></span>
<span class="normal"><a href="#__codelineno-0-730">730</a></span>
<span class="normal"><a href="#__codelineno-0-731">731</a></span>
<span class="normal"><a href="#__codelineno-0-732">732</a></span>
<span class="normal"><a href="#__codelineno-0-733">733</a></span>
<span class="normal"><a href="#__codelineno-0-734">734</a></span>
<span class="normal"><a href="#__codelineno-0-735">735</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-729"><a id="__codelineno-0-729" name="__codelineno-0-729"></a><span class="k">def</span><span class="w"> </span><span class="nf">on_track_downloaded</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">track</span><span class="p">:</span> <span class="n">AnyTrack</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span><span id="__span-0-730"><a id="__codelineno-0-730" name="__codelineno-0-730"></a><span class="w"> </span><span class="sd">"""</span>
</span><span id="__span-0-731"><a id="__codelineno-0-731" name="__codelineno-0-731"></a><span class="sd"> Called when a Track has finished downloading.</span>
</span><span id="__span-0-732"><a id="__codelineno-0-732" name="__codelineno-0-732"></a>
</span><span id="__span-0-733"><a id="__codelineno-0-733" name="__codelineno-0-733"></a><span class="sd"> Parameters:</span>
</span><span id="__span-0-734"><a id="__codelineno-0-734" name="__codelineno-0-734"></a><span class="sd"> track: The downloaded Track object.</span>
</span><span id="__span-0-735"><a id="__codelineno-0-735" name="__codelineno-0-735"></a><span class="sd"> """</span>
<div class="language-python highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-734">734</a></span>
<span class="normal"><a href="#__codelineno-0-735">735</a></span>
<span class="normal"><a href="#__codelineno-0-736">736</a></span>
<span class="normal"><a href="#__codelineno-0-737">737</a></span>
<span class="normal"><a href="#__codelineno-0-738">738</a></span>
<span class="normal"><a href="#__codelineno-0-739">739</a></span>
<span class="normal"><a href="#__codelineno-0-740">740</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-734"><a id="__codelineno-0-734" name="__codelineno-0-734"></a><span class="k">def</span><span class="w"> </span><span class="nf">on_track_downloaded</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">track</span><span class="p">:</span> <span class="n">AnyTrack</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span><span id="__span-0-735"><a id="__codelineno-0-735" name="__codelineno-0-735"></a><span class="w"> </span><span class="sd">"""</span>
</span><span id="__span-0-736"><a id="__codelineno-0-736" name="__codelineno-0-736"></a><span class="sd"> Called when a Track has finished downloading.</span>
</span><span id="__span-0-737"><a id="__codelineno-0-737" name="__codelineno-0-737"></a>
</span><span id="__span-0-738"><a id="__codelineno-0-738" name="__codelineno-0-738"></a><span class="sd"> Parameters:</span>
</span><span id="__span-0-739"><a id="__codelineno-0-739" name="__codelineno-0-739"></a><span class="sd"> track: The downloaded Track object.</span>
</span><span id="__span-0-740"><a id="__codelineno-0-740" name="__codelineno-0-740"></a><span class="sd"> """</span>
</span></code></pre></div></td></tr></table></div>
</details>
</div>
@@ -4859,25 +4870,25 @@ for an HLS track that merged during the download (merge_segments).</p>
<details class="mkdocstrings-source">
<summary>Source code in <code>unshackle/core/service.py</code></summary>
<div class="language-python highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-737">737</a></span>
<span class="normal"><a href="#__codelineno-0-738">738</a></span>
<span class="normal"><a href="#__codelineno-0-739">739</a></span>
<span class="normal"><a href="#__codelineno-0-740">740</a></span>
<span class="normal"><a href="#__codelineno-0-741">741</a></span>
<span class="normal"><a href="#__codelineno-0-742">742</a></span>
<div class="language-python highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-742">742</a></span>
<span class="normal"><a href="#__codelineno-0-743">743</a></span>
<span class="normal"><a href="#__codelineno-0-744">744</a></span>
<span class="normal"><a href="#__codelineno-0-745">745</a></span>
<span class="normal"><a href="#__codelineno-0-746">746</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-737"><a id="__codelineno-0-737" name="__codelineno-0-737"></a><span class="k">def</span><span class="w"> </span><span class="nf">on_track_decrypted</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">track</span><span class="p">:</span> <span class="n">AnyTrack</span><span class="p">,</span> <span class="n">drm</span><span class="p">:</span> <span class="n">DRM_T</span><span class="p">,</span> <span class="n">segment</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">m3u8</span><span class="o">.</span><span class="n">Segment</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span><span id="__span-0-738"><a id="__codelineno-0-738" name="__codelineno-0-738"></a><span class="w"> </span><span class="sd">"""</span>
</span><span id="__span-0-739"><a id="__codelineno-0-739" name="__codelineno-0-739"></a><span class="sd"> Called when a Track has finished decrypting.</span>
</span><span id="__span-0-740"><a id="__codelineno-0-740" name="__codelineno-0-740"></a>
</span><span id="__span-0-741"><a id="__codelineno-0-741" name="__codelineno-0-741"></a><span class="sd"> Parameters:</span>
</span><span id="__span-0-742"><a id="__codelineno-0-742" name="__codelineno-0-742"></a><span class="sd"> track: The decrypted Track object.</span>
</span><span id="__span-0-743"><a id="__codelineno-0-743" name="__codelineno-0-743"></a><span class="sd"> drm: The DRM object it decrypted with.</span>
</span><span id="__span-0-744"><a id="__codelineno-0-744" name="__codelineno-0-744"></a><span class="sd"> segment: The decrypted HLS segment information. None for DASH and ISM tracks and</span>
</span><span id="__span-0-745"><a id="__codelineno-0-745" name="__codelineno-0-745"></a><span class="sd"> for an HLS track that merged during the download (merge_segments).</span>
</span><span id="__span-0-746"><a id="__codelineno-0-746" name="__codelineno-0-746"></a><span class="sd"> """</span>
<span class="normal"><a href="#__codelineno-0-746">746</a></span>
<span class="normal"><a href="#__codelineno-0-747">747</a></span>
<span class="normal"><a href="#__codelineno-0-748">748</a></span>
<span class="normal"><a href="#__codelineno-0-749">749</a></span>
<span class="normal"><a href="#__codelineno-0-750">750</a></span>
<span class="normal"><a href="#__codelineno-0-751">751</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-742"><a id="__codelineno-0-742" name="__codelineno-0-742"></a><span class="k">def</span><span class="w"> </span><span class="nf">on_track_decrypted</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">track</span><span class="p">:</span> <span class="n">AnyTrack</span><span class="p">,</span> <span class="n">drm</span><span class="p">:</span> <span class="n">DRM_T</span><span class="p">,</span> <span class="n">segment</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">m3u8</span><span class="o">.</span><span class="n">Segment</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span><span id="__span-0-743"><a id="__codelineno-0-743" name="__codelineno-0-743"></a><span class="w"> </span><span class="sd">"""</span>
</span><span id="__span-0-744"><a id="__codelineno-0-744" name="__codelineno-0-744"></a><span class="sd"> Called when a Track has finished decrypting.</span>
</span><span id="__span-0-745"><a id="__codelineno-0-745" name="__codelineno-0-745"></a>
</span><span id="__span-0-746"><a id="__codelineno-0-746" name="__codelineno-0-746"></a><span class="sd"> Parameters:</span>
</span><span id="__span-0-747"><a id="__codelineno-0-747" name="__codelineno-0-747"></a><span class="sd"> track: The decrypted Track object.</span>
</span><span id="__span-0-748"><a id="__codelineno-0-748" name="__codelineno-0-748"></a><span class="sd"> drm: The DRM object it decrypted with.</span>
</span><span id="__span-0-749"><a id="__codelineno-0-749" name="__codelineno-0-749"></a><span class="sd"> segment: The decrypted HLS segment information. None for DASH and ISM tracks and</span>
</span><span id="__span-0-750"><a id="__codelineno-0-750" name="__codelineno-0-750"></a><span class="sd"> for an HLS track that merged during the download (merge_segments).</span>
</span><span id="__span-0-751"><a id="__codelineno-0-751" name="__codelineno-0-751"></a><span class="sd"> """</span>
</span></code></pre></div></td></tr></table></div>
</details>
</div>
@@ -4933,19 +4944,19 @@ for an HLS track that merged during the download (merge_segments).</p>
<details class="mkdocstrings-source">
<summary>Source code in <code>unshackle/core/service.py</code></summary>
<div class="language-python highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-748">748</a></span>
<span class="normal"><a href="#__codelineno-0-749">749</a></span>
<span class="normal"><a href="#__codelineno-0-750">750</a></span>
<span class="normal"><a href="#__codelineno-0-751">751</a></span>
<span class="normal"><a href="#__codelineno-0-752">752</a></span>
<span class="normal"><a href="#__codelineno-0-753">753</a></span>
<span class="normal"><a href="#__codelineno-0-754">754</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-748"><a id="__codelineno-0-748" name="__codelineno-0-748"></a><span class="k">def</span><span class="w"> </span><span class="nf">on_track_repacked</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">track</span><span class="p">:</span> <span class="n">AnyTrack</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span><span id="__span-0-749"><a id="__codelineno-0-749" name="__codelineno-0-749"></a><span class="w"> </span><span class="sd">"""</span>
</span><span id="__span-0-750"><a id="__codelineno-0-750" name="__codelineno-0-750"></a><span class="sd"> Called when a Track has finished repacking.</span>
</span><span id="__span-0-751"><a id="__codelineno-0-751" name="__codelineno-0-751"></a>
</span><span id="__span-0-752"><a id="__codelineno-0-752" name="__codelineno-0-752"></a><span class="sd"> Parameters:</span>
</span><span id="__span-0-753"><a id="__codelineno-0-753" name="__codelineno-0-753"></a><span class="sd"> track: The repacked Track object.</span>
</span><span id="__span-0-754"><a id="__codelineno-0-754" name="__codelineno-0-754"></a><span class="sd"> """</span>
<div class="language-python highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-753">753</a></span>
<span class="normal"><a href="#__codelineno-0-754">754</a></span>
<span class="normal"><a href="#__codelineno-0-755">755</a></span>
<span class="normal"><a href="#__codelineno-0-756">756</a></span>
<span class="normal"><a href="#__codelineno-0-757">757</a></span>
<span class="normal"><a href="#__codelineno-0-758">758</a></span>
<span class="normal"><a href="#__codelineno-0-759">759</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-753"><a id="__codelineno-0-753" name="__codelineno-0-753"></a><span class="k">def</span><span class="w"> </span><span class="nf">on_track_repacked</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">track</span><span class="p">:</span> <span class="n">AnyTrack</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span><span id="__span-0-754"><a id="__codelineno-0-754" name="__codelineno-0-754"></a><span class="w"> </span><span class="sd">"""</span>
</span><span id="__span-0-755"><a id="__codelineno-0-755" name="__codelineno-0-755"></a><span class="sd"> Called when a Track has finished repacking.</span>
</span><span id="__span-0-756"><a id="__codelineno-0-756" name="__codelineno-0-756"></a>
</span><span id="__span-0-757"><a id="__codelineno-0-757" name="__codelineno-0-757"></a><span class="sd"> Parameters:</span>
</span><span id="__span-0-758"><a id="__codelineno-0-758" name="__codelineno-0-758"></a><span class="sd"> track: The repacked Track object.</span>
</span><span id="__span-0-759"><a id="__codelineno-0-759" name="__codelineno-0-759"></a><span class="sd"> """</span>
</span></code></pre></div></td></tr></table></div>
</details>
</div>
@@ -5004,27 +5015,27 @@ MP4 with FFmpeg/mp4box.</p>
<details class="mkdocstrings-source">
<summary>Source code in <code>unshackle/core/service.py</code></summary>
<div class="language-python highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-756">756</a></span>
<span class="normal"><a href="#__codelineno-0-757">757</a></span>
<span class="normal"><a href="#__codelineno-0-758">758</a></span>
<span class="normal"><a href="#__codelineno-0-759">759</a></span>
<span class="normal"><a href="#__codelineno-0-760">760</a></span>
<span class="normal"><a href="#__codelineno-0-761">761</a></span>
<div class="language-python highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-761">761</a></span>
<span class="normal"><a href="#__codelineno-0-762">762</a></span>
<span class="normal"><a href="#__codelineno-0-763">763</a></span>
<span class="normal"><a href="#__codelineno-0-764">764</a></span>
<span class="normal"><a href="#__codelineno-0-765">765</a></span>
<span class="normal"><a href="#__codelineno-0-766">766</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-756"><a id="__codelineno-0-756" name="__codelineno-0-756"></a><span class="k">def</span><span class="w"> </span><span class="nf">on_track_multiplex</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">track</span><span class="p">:</span> <span class="n">AnyTrack</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span><span id="__span-0-757"><a id="__codelineno-0-757" name="__codelineno-0-757"></a><span class="w"> </span><span class="sd">"""</span>
</span><span id="__span-0-758"><a id="__codelineno-0-758" name="__codelineno-0-758"></a><span class="sd"> Called immediately before unshackle multiplexes a Track into a Container.</span>
</span><span id="__span-0-759"><a id="__codelineno-0-759" name="__codelineno-0-759"></a>
</span><span id="__span-0-760"><a id="__codelineno-0-760" name="__codelineno-0-760"></a><span class="sd"> Note: Right now unshackle multiplexes only MKV containers. In the future</span>
</span><span id="__span-0-761"><a id="__codelineno-0-761" name="__codelineno-0-761"></a><span class="sd"> unshackle can also call this when it multiplexes to other containers like</span>
</span><span id="__span-0-762"><a id="__codelineno-0-762" name="__codelineno-0-762"></a><span class="sd"> MP4 with FFmpeg/mp4box.</span>
</span><span id="__span-0-763"><a id="__codelineno-0-763" name="__codelineno-0-763"></a>
</span><span id="__span-0-764"><a id="__codelineno-0-764" name="__codelineno-0-764"></a><span class="sd"> Parameters:</span>
</span><span id="__span-0-765"><a id="__codelineno-0-765" name="__codelineno-0-765"></a><span class="sd"> track: The repacked Track object.</span>
</span><span id="__span-0-766"><a id="__codelineno-0-766" name="__codelineno-0-766"></a><span class="sd"> """</span>
<span class="normal"><a href="#__codelineno-0-766">766</a></span>
<span class="normal"><a href="#__codelineno-0-767">767</a></span>
<span class="normal"><a href="#__codelineno-0-768">768</a></span>
<span class="normal"><a href="#__codelineno-0-769">769</a></span>
<span class="normal"><a href="#__codelineno-0-770">770</a></span>
<span class="normal"><a href="#__codelineno-0-771">771</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-761"><a id="__codelineno-0-761" name="__codelineno-0-761"></a><span class="k">def</span><span class="w"> </span><span class="nf">on_track_multiplex</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">track</span><span class="p">:</span> <span class="n">AnyTrack</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span><span id="__span-0-762"><a id="__codelineno-0-762" name="__codelineno-0-762"></a><span class="w"> </span><span class="sd">"""</span>
</span><span id="__span-0-763"><a id="__codelineno-0-763" name="__codelineno-0-763"></a><span class="sd"> Called immediately before unshackle multiplexes a Track into a Container.</span>
</span><span id="__span-0-764"><a id="__codelineno-0-764" name="__codelineno-0-764"></a>
</span><span id="__span-0-765"><a id="__codelineno-0-765" name="__codelineno-0-765"></a><span class="sd"> Note: Right now unshackle multiplexes only MKV containers. In the future</span>
</span><span id="__span-0-766"><a id="__codelineno-0-766" name="__codelineno-0-766"></a><span class="sd"> unshackle can also call this when it multiplexes to other containers like</span>
</span><span id="__span-0-767"><a id="__codelineno-0-767" name="__codelineno-0-767"></a><span class="sd"> MP4 with FFmpeg/mp4box.</span>
</span><span id="__span-0-768"><a id="__codelineno-0-768" name="__codelineno-0-768"></a>
</span><span id="__span-0-769"><a id="__codelineno-0-769" name="__codelineno-0-769"></a><span class="sd"> Parameters:</span>
</span><span id="__span-0-770"><a id="__codelineno-0-770" name="__codelineno-0-770"></a><span class="sd"> track: The repacked Track object.</span>
</span><span id="__span-0-771"><a id="__codelineno-0-771" name="__codelineno-0-771"></a><span class="sd"> """</span>
</span></code></pre></div></td></tr></table></div>
</details>
</div>
File diff suppressed because one or more lines are too long