Files
unshackle/reference/api/service/index.html
T
2026-08-17 04:20:46 +00:00

4922 lines
267 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html>
<html lang="en" class="no-js">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="description" content="Movie, TV, and Music archival software — user guide and REST API reference">
<link rel="canonical" href="https://docs.unshackle.dev/reference/api/service/">
<link rel="prev" href="../../../dev/rest-api/errors/">
<link rel="next" href="../config/">
<link rel="icon" href="../../../assets/favicon.svg">
<meta name="generator" content="mkdocs-1.6.1, mkdocs-material-9.7.7">
<title>Service - unshackle</title>
<link rel="stylesheet" href="../../../assets/stylesheets/main.ec1eaa64.min.css">
<link rel="stylesheet" href="../../../assets/stylesheets/palette.ab4e12ef.min.css">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,300i,400,400i,700,700i%7CRoboto+Mono:400,400i,700,700i&display=fallback">
<style>:root{--md-text-font:"Roboto";--md-code-font:"Roboto Mono"}</style>
<link rel="stylesheet" href="../../../assets/_mkdocstrings.css">
<script>__md_scope=new URL("../../..",location),__md_hash=e=>[...e].reduce(((e,_)=>(e<<5)-e+_.charCodeAt(0)),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
</head>
<body dir="ltr" data-md-color-scheme="default" data-md-color-primary="black" data-md-color-accent="indigo">
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
<label class="md-overlay" for="__drawer"></label>
<div data-md-component="skip">
<a href="#service-api" class="md-skip">
Skip to content
</a>
</div>
<div data-md-component="announce">
</div>
<header class="md-header" data-md-component="header">
<nav class="md-header__inner md-grid" aria-label="Header">
<a href="../../.." title="unshackle" class="md-header__button md-logo" aria-label="unshackle" data-md-component="logo">
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="m800-274-80-80v-206H514l-80-80h166v-80q0-50-34.5-85T481-840q-50 0-84 34.5T363-720v9l-73-73q22-61 75-98.5T481-920q83 0 141 58.5T680-720v80h40q33 0 56.5 23.5T800-560v286Zm20 246-62-62q-11 5-20 7.5T720-80H240q-33 0-56.5-23.5T160-160v-400q0-25 14.5-46t37.5-30L28-820l56-56L876-84l-56 56ZM686-160 539-309q-11 11-25.5 17t-31.5 6q-33 0-56.5-23.5T402-366q0-17 6-31.5t17-25.5L286-560h-46v400h446ZM486-360Zm131-97Z"/></svg>
</a>
<label class="md-header__button md-icon" for="__drawer">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 6h18v2H3zm0 5h18v2H3zm0 5h18v2H3z"/></svg>
</label>
<div class="md-header__title" data-md-component="header-title">
<div class="md-header__ellipsis">
<div class="md-header__topic">
<span class="md-ellipsis">
unshackle
</span>
</div>
<div class="md-header__topic" data-md-component="header-topic">
<span class="md-ellipsis">
Service
</span>
</div>
</div>
</div>
<form class="md-header__option" data-md-component="palette">
<input class="md-option" data-md-color-media="(prefers-color-scheme)" data-md-color-scheme="default" data-md-color-primary="black" data-md-color-accent="indigo" aria-label="Switch to light mode" type="radio" name="__palette" id="__palette_0">
<label class="md-header__button md-icon" title="Switch to light mode" for="__palette_1" hidden>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7a5 5 0 0 0-5 5 5 5 0 0 0 5 5h4v-1.9H7c-1.71 0-3.1-1.39-3.1-3.1M8 13h8v-2H8zm9-6h-4v1.9h4c1.71 0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4a5 5 0 0 0 5-5 5 5 0 0 0-5-5"/></svg>
</label>
<input class="md-option" data-md-color-media="(prefers-color-scheme: light)" data-md-color-scheme="default" data-md-color-primary="black" data-md-color-accent="indigo" aria-label="Switch to dark mode" type="radio" name="__palette" id="__palette_1">
<label class="md-header__button md-icon" title="Switch to dark mode" for="__palette_2" hidden>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M17 7H7a5 5 0 0 0-5 5 5 5 0 0 0 5 5h10a5 5 0 0 0 5-5 5 5 0 0 0-5-5m0 8a3 3 0 0 1-3-3 3 3 0 0 1 3-3 3 3 0 0 1 3 3 3 3 0 0 1-3 3"/></svg>
</label>
<input class="md-option" data-md-color-media="(prefers-color-scheme: dark)" data-md-color-scheme="slate" data-md-color-primary="black" data-md-color-accent="indigo" aria-label="Switch to system preference" type="radio" name="__palette" id="__palette_2">
<label class="md-header__button md-icon" title="Switch to system preference" for="__palette_0" hidden>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M17 7H7a5 5 0 0 0-5 5 5 5 0 0 0 5 5h10a5 5 0 0 0 5-5 5 5 0 0 0-5-5M7 15a3 3 0 0 1-3-3 3 3 0 0 1 3-3 3 3 0 0 1 3 3 3 3 0 0 1-3 3"/></svg>
</label>
</form>
<script>var palette=__md_get("__palette");if(palette&&palette.color){if("(prefers-color-scheme)"===palette.color.media){var media=matchMedia("(prefers-color-scheme: light)"),input=document.querySelector(media.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']");palette.color.media=input.getAttribute("data-md-color-media"),palette.color.scheme=input.getAttribute("data-md-color-scheme"),palette.color.primary=input.getAttribute("data-md-color-primary"),palette.color.accent=input.getAttribute("data-md-color-accent")}for(var[key,value]of Object.entries(palette.color))document.body.setAttribute("data-md-color-"+key,value)}</script>
<label class="md-header__button md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"/></svg>
</label>
<div class="md-search" data-md-component="search" role="dialog">
<label class="md-search__overlay" for="__search"></label>
<div class="md-search__inner" role="search">
<form class="md-search__form" name="search">
<input type="text" class="md-search__input" name="query" aria-label="Search" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="search-query" required>
<label class="md-search__icon md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11z"/></svg>
</label>
<nav class="md-search__options" aria-label="Search">
<a href="javascript:void(0)" class="md-search__icon md-icon" title="Share" aria-label="Share" data-clipboard data-clipboard-text="" data-md-component="search-share" tabindex="-1">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M18 16.08c-.76 0-1.44.3-1.96.77L8.91 12.7c.05-.23.09-.46.09-.7s-.04-.47-.09-.7l7.05-4.11c.54.5 1.25.81 2.04.81a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3c0 .24.04.47.09.7L8.04 9.81C7.5 9.31 6.79 9 6 9a3 3 0 0 0-3 3 3 3 0 0 0 3 3c.79 0 1.5-.31 2.04-.81l7.12 4.15c-.05.21-.08.43-.08.66 0 1.61 1.31 2.91 2.92 2.91s2.92-1.3 2.92-2.91A2.92 2.92 0 0 0 18 16.08"/></svg>
</a>
<button type="reset" class="md-search__icon md-icon" title="Clear" aria-label="Clear" tabindex="-1">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>
</button>
</nav>
<div class="md-search__suggest" data-md-component="search-suggest"></div>
</form>
<div class="md-search__output">
<div class="md-search__scrollwrap" tabindex="0" data-md-scrollfix>
<div class="md-search-result" data-md-component="search-result">
<div class="md-search-result__meta">
Initializing search
</div>
<ol class="md-search-result__list" role="presentation"></ol>
</div>
</div>
</div>
</div>
</div>
<div class="md-header__source">
<a href="https://github.com/unshackle-dl/unshackle" title="Go to repository" class="md-source" data-md-component="source">
<div class="md-source__icon md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2025 Fonticons, Inc.--><path d="M439.6 236.1 244 40.5c-5.4-5.5-12.8-8.5-20.4-8.5s-15 3-20.4 8.4L162.5 81l51.5 51.5c27.1-9.1 52.7 16.8 43.4 43.7l49.7 49.7c34.2-11.8 61.2 31 35.5 56.7-26.5 26.5-70.2-2.9-56-37.3L240.3 199v121.9c25.3 12.5 22.3 41.8 9.1 55-6.4 6.4-15.2 10.1-24.3 10.1s-17.8-3.6-24.3-10.1c-17.6-17.6-11.1-46.9 11.2-56v-123c-20.8-8.5-24.6-30.7-18.6-45L142.6 101 8.5 235.1C3 240.6 0 247.9 0 255.5s3 15 8.5 20.4l195.6 195.7c5.4 5.4 12.7 8.4 20.4 8.4s15-3 20.4-8.4l194.7-194.7c5.4-5.4 8.4-12.8 8.4-20.4s-3-15-8.4-20.4"/></svg>
</div>
<div class="md-source__repository">
unshackle-dl/unshackle
</div>
</a>
</div>
</nav>
</header>
<div class="md-container" data-md-component="container">
<nav class="md-tabs" aria-label="Tabs" data-md-component="tabs">
<div class="md-grid">
<ul class="md-tabs__list">
<li class="md-tabs__item">
<a href="../../.." class="md-tabs__link">
Home
</a>
</li>
<li class="md-tabs__item">
<a href="../../../getting-started/installation/" class="md-tabs__link">
Getting Started
</a>
</li>
<li class="md-tabs__item">
<a href="../../../guide/downloading/" class="md-tabs__link">
User Guide
</a>
</li>
<li class="md-tabs__item">
<a href="../../configuration/" class="md-tabs__link">
Configuration
</a>
</li>
<li class="md-tabs__item">
<a href="../../../dev/creating-a-service/" class="md-tabs__link">
Developer
</a>
</li>
<li class="md-tabs__item md-tabs__item--active">
<a href="./" class="md-tabs__link">
API Reference
</a>
</li>
</ul>
</div>
</nav>
<main class="md-main" data-md-component="main">
<div class="md-main__inner md-grid">
<div class="md-sidebar md-sidebar--primary" data-md-component="sidebar" data-md-type="navigation" >
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--primary md-nav--lifted" aria-label="Navigation" data-md-level="0">
<label class="md-nav__title" for="__drawer">
<a href="../../.." title="unshackle" class="md-nav__button md-logo" aria-label="unshackle" data-md-component="logo">
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="m800-274-80-80v-206H514l-80-80h166v-80q0-50-34.5-85T481-840q-50 0-84 34.5T363-720v9l-73-73q22-61 75-98.5T481-920q83 0 141 58.5T680-720v80h40q33 0 56.5 23.5T800-560v286Zm20 246-62-62q-11 5-20 7.5T720-80H240q-33 0-56.5-23.5T160-160v-400q0-25 14.5-46t37.5-30L28-820l56-56L876-84l-56 56ZM686-160 539-309q-11 11-25.5 17t-31.5 6q-33 0-56.5-23.5T402-366q0-17 6-31.5t17-25.5L286-560h-46v400h446ZM486-360Zm131-97Z"/></svg>
</a>
unshackle
</label>
<div class="md-nav__source">
<a href="https://github.com/unshackle-dl/unshackle" title="Go to repository" class="md-source" data-md-component="source">
<div class="md-source__icon md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2025 Fonticons, Inc.--><path d="M439.6 236.1 244 40.5c-5.4-5.5-12.8-8.5-20.4-8.5s-15 3-20.4 8.4L162.5 81l51.5 51.5c27.1-9.1 52.7 16.8 43.4 43.7l49.7 49.7c34.2-11.8 61.2 31 35.5 56.7-26.5 26.5-70.2-2.9-56-37.3L240.3 199v121.9c25.3 12.5 22.3 41.8 9.1 55-6.4 6.4-15.2 10.1-24.3 10.1s-17.8-3.6-24.3-10.1c-17.6-17.6-11.1-46.9 11.2-56v-123c-20.8-8.5-24.6-30.7-18.6-45L142.6 101 8.5 235.1C3 240.6 0 247.9 0 255.5s3 15 8.5 20.4l195.6 195.7c5.4 5.4 12.7 8.4 20.4 8.4s15-3 20.4-8.4l194.7-194.7c5.4-5.4 8.4-12.8 8.4-20.4s-3-15-8.4-20.4"/></svg>
</div>
<div class="md-source__repository">
unshackle-dl/unshackle
</div>
</a>
</div>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../.." class="md-nav__link">
<span class="md-ellipsis">
Home
</span>
</a>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2" >
<label class="md-nav__link" for="__nav_2" id="__nav_2_label" tabindex="0">
<span class="md-ellipsis">
Getting Started
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_2_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_2">
<span class="md-nav__icon md-icon"></span>
Getting Started
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../../getting-started/installation/" class="md-nav__link">
<span class="md-ellipsis">
Installation
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../getting-started/quickstart/" class="md-nav__link">
<span class="md-ellipsis">
Quick Start
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../getting-started/configuration-file/" class="md-nav__link">
<span class="md-ellipsis">
The Configuration File
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_3" >
<label class="md-nav__link" for="__nav_3" id="__nav_3_label" tabindex="0">
<span class="md-ellipsis">
User Guide
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_3_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_3">
<span class="md-nav__icon md-icon"></span>
User Guide
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../../guide/downloading/" class="md-nav__link">
<span class="md-ellipsis">
Downloading
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../guide/cli-reference/" class="md-nav__link">
<span class="md-ellipsis">
CLI Reference
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../guide/drm-and-cdm/" class="md-nav__link">
<span class="md-ellipsis">
DRM & CDM Setup
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../guide/proxies-and-vpn/" class="md-nav__link">
<span class="md-ellipsis">
Proxies & VPN
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../guide/vaults/" class="md-nav__link">
<span class="md-ellipsis">
Key Vaults
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../guide/output-and-naming/" class="md-nav__link">
<span class="md-ellipsis">
Output & Naming
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../guide/subtitles/" class="md-nav__link">
<span class="md-ellipsis">
Subtitles
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../guide/troubleshooting/" class="md-nav__link">
<span class="md-ellipsis">
Troubleshooting
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_4" >
<div class="md-nav__link md-nav__container">
<a href="../../configuration/" class="md-nav__link ">
<span class="md-ellipsis">
Configuration
</span>
</a>
<label class="md-nav__link " for="__nav_4" id="__nav_4_label" tabindex="0">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_4_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_4">
<span class="md-nav__icon md-icon"></span>
Configuration
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../configuration/directories/" class="md-nav__link">
<span class="md-ellipsis">
Directories
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../configuration/services/" class="md-nav__link">
<span class="md-ellipsis">
Services & Authentication
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../configuration/download/" class="md-nav__link">
<span class="md-ellipsis">
Download & Processing
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../configuration/output/" class="md-nav__link">
<span class="md-ellipsis">
Output & Naming
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../configuration/drm/" class="md-nav__link">
<span class="md-ellipsis">
DRM & CDM
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../configuration/network/" class="md-nav__link">
<span class="md-ellipsis">
Network & Proxy
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../configuration/vaults/" class="md-nav__link">
<span class="md-ellipsis">
Key Vaults
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../configuration/misc/" class="md-nav__link">
<span class="md-ellipsis">
Other Settings
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../configuration/example/" class="md-nav__link">
<span class="md-ellipsis">
Annotated Example
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_5" >
<label class="md-nav__link" for="__nav_5" id="__nav_5_label" tabindex="0">
<span class="md-ellipsis">
Developer
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_5_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_5">
<span class="md-nav__icon md-icon"></span>
Developer
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../../dev/creating-a-service/" class="md-nav__link">
<span class="md-ellipsis">
Creating a Service
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../dev/service-architecture/" class="md-nav__link">
<span class="md-ellipsis">
Service Architecture
</span>
</a>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_5_3" >
<div class="md-nav__link md-nav__container">
<a href="../../../dev/rest-api/" class="md-nav__link ">
<span class="md-ellipsis">
REST API
</span>
</a>
<label class="md-nav__link " for="__nav_5_3" id="__nav_5_3_label" tabindex="0">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_5_3_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_5_3">
<span class="md-nav__icon md-icon"></span>
REST API
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../../dev/rest-api/quickstart/" class="md-nav__link">
<span class="md-ellipsis">
Quick Start
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../dev/rest-api/authentication/" class="md-nav__link">
<span class="md-ellipsis">
Authentication
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../dev/rest-api/endpoints/" class="md-nav__link">
<span class="md-ellipsis">
Endpoints
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../dev/rest-api/job-lifecycle/" class="md-nav__link">
<span class="md-ellipsis">
Job Lifecycle
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../dev/rest-api/remote-sessions/" class="md-nav__link">
<span class="md-ellipsis">
Remote Sessions
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../dev/rest-api/errors/" class="md-nav__link">
<span class="md-ellipsis">
Error Responses
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--active md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_6" checked>
<label class="md-nav__link" for="__nav_6" id="__nav_6_label" tabindex="">
<span class="md-ellipsis">
API Reference
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_6_label" aria-expanded="true">
<label class="md-nav__title" for="__nav_6">
<span class="md-nav__icon md-icon"></span>
API Reference
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item md-nav__item--active">
<input class="md-nav__toggle md-toggle" type="checkbox" id="__toc">
<label class="md-nav__link md-nav__link--active" for="__toc">
<span class="md-ellipsis">
Service
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<a href="./" class="md-nav__link md-nav__link--active">
<span class="md-ellipsis">
Service
</span>
</a>
<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
<label class="md-nav__title" for="__toc">
<span class="md-nav__icon md-icon"></span>
Table of contents
</label>
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
<li class="md-nav__item">
<a href="#unshackle.core.service" class="md-nav__link">
<span class="md-ellipsis">
<code class="doc-symbol doc-symbol-toc doc-symbol-module"></code>&nbsp;service
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#unshackle.core.service.TimeoutSession" class="md-nav__link">
<span class="md-ellipsis">
<code class="doc-symbol doc-symbol-toc doc-symbol-class"></code>&nbsp;TimeoutSession
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#unshackle.core.service.TimeoutHTTPAdapter" class="md-nav__link">
<span class="md-ellipsis">
<code class="doc-symbol doc-symbol-toc doc-symbol-class"></code>&nbsp;TimeoutHTTPAdapter
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#unshackle.core.service.TrackRequest" class="md-nav__link">
<span class="md-ellipsis">
<code class="doc-symbol doc-symbol-toc doc-symbol-class"></code>&nbsp;TrackRequest
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#unshackle.core.service.Service" class="md-nav__link">
<span class="md-ellipsis">
<code class="doc-symbol doc-symbol-toc doc-symbol-class"></code>&nbsp;Service
</span>
</a>
<nav class="md-nav" aria-label=" Service">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#unshackle.core.service.Service.get_tracks_for_variants" class="md-nav__link">
<span class="md-ellipsis">
<code class="doc-symbol doc-symbol-toc doc-symbol-method"></code>&nbsp;get_tracks_for_variants
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#unshackle.core.service.Service.get_session" class="md-nav__link">
<span class="md-ellipsis">
<code class="doc-symbol doc-symbol-toc doc-symbol-method"></code>&nbsp;get_session
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#unshackle.core.service.Service.authenticate" class="md-nav__link">
<span class="md-ellipsis">
<code class="doc-symbol doc-symbol-toc doc-symbol-method"></code>&nbsp;authenticate
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#unshackle.core.service.Service.request_input" class="md-nav__link">
<span class="md-ellipsis">
<code class="doc-symbol doc-symbol-toc doc-symbol-method"></code>&nbsp;request_input
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#unshackle.core.service.Service.search" class="md-nav__link">
<span class="md-ellipsis">
<code class="doc-symbol doc-symbol-toc doc-symbol-method"></code>&nbsp;search
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#unshackle.core.service.Service.get_widevine_service_certificate" class="md-nav__link">
<span class="md-ellipsis">
<code class="doc-symbol doc-symbol-toc doc-symbol-method"></code>&nbsp;get_widevine_service_certificate
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#unshackle.core.service.Service.get_widevine_license" class="md-nav__link">
<span class="md-ellipsis">
<code class="doc-symbol doc-symbol-toc doc-symbol-method"></code>&nbsp;get_widevine_license
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#unshackle.core.service.Service.get_playready_license" class="md-nav__link">
<span class="md-ellipsis">
<code class="doc-symbol doc-symbol-toc doc-symbol-method"></code>&nbsp;get_playready_license
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#unshackle.core.service.Service.get_clearkey_license" class="md-nav__link">
<span class="md-ellipsis">
<code class="doc-symbol doc-symbol-toc doc-symbol-method"></code>&nbsp;get_clearkey_license
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#unshackle.core.service.Service.get_titles" class="md-nav__link">
<span class="md-ellipsis">
<code class="doc-symbol doc-symbol-toc doc-symbol-method"></code>&nbsp;get_titles
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#unshackle.core.service.Service.get_titles_cached" class="md-nav__link">
<span class="md-ellipsis">
<code class="doc-symbol doc-symbol-toc doc-symbol-method"></code>&nbsp;get_titles_cached
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#unshackle.core.service.Service.apply_title_map" class="md-nav__link">
<span class="md-ellipsis">
<code class="doc-symbol doc-symbol-toc doc-symbol-method"></code>&nbsp;apply_title_map
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#unshackle.core.service.Service.get_tracks" class="md-nav__link">
<span class="md-ellipsis">
<code class="doc-symbol doc-symbol-toc doc-symbol-method"></code>&nbsp;get_tracks
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#unshackle.core.service.Service.get_chapters" class="md-nav__link">
<span class="md-ellipsis">
<code class="doc-symbol doc-symbol-toc doc-symbol-method"></code>&nbsp;get_chapters
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#unshackle.core.service.Service.on_segment_downloaded" class="md-nav__link">
<span class="md-ellipsis">
<code class="doc-symbol doc-symbol-toc doc-symbol-method"></code>&nbsp;on_segment_downloaded
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#unshackle.core.service.Service.on_track_downloaded" class="md-nav__link">
<span class="md-ellipsis">
<code class="doc-symbol doc-symbol-toc doc-symbol-method"></code>&nbsp;on_track_downloaded
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#unshackle.core.service.Service.on_track_decrypted" class="md-nav__link">
<span class="md-ellipsis">
<code class="doc-symbol doc-symbol-toc doc-symbol-method"></code>&nbsp;on_track_decrypted
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#unshackle.core.service.Service.on_track_repacked" class="md-nav__link">
<span class="md-ellipsis">
<code class="doc-symbol doc-symbol-toc doc-symbol-method"></code>&nbsp;on_track_repacked
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#unshackle.core.service.Service.on_track_multiplex" class="md-nav__link">
<span class="md-ellipsis">
<code class="doc-symbol doc-symbol-toc doc-symbol-method"></code>&nbsp;on_track_multiplex
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#unshackle.core.service.sanitize_proxy_for_log" class="md-nav__link">
<span class="md-ellipsis">
<code class="doc-symbol doc-symbol-toc doc-symbol-function"></code>&nbsp;sanitize_proxy_for_log
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../config/" class="md-nav__link">
<span class="md-ellipsis">
Config
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../tracks/" class="md-nav__link">
<span class="md-ellipsis">
Tracks
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../titles/" class="md-nav__link">
<span class="md-ellipsis">
Titles
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../drm/" class="md-nav__link">
<span class="md-ellipsis">
DRM
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-sidebar md-sidebar--secondary" data-md-component="sidebar" data-md-type="toc" >
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
<label class="md-nav__title" for="__toc">
<span class="md-nav__icon md-icon"></span>
Table of contents
</label>
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
<li class="md-nav__item">
<a href="#unshackle.core.service" class="md-nav__link">
<span class="md-ellipsis">
<code class="doc-symbol doc-symbol-toc doc-symbol-module"></code>&nbsp;service
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#unshackle.core.service.TimeoutSession" class="md-nav__link">
<span class="md-ellipsis">
<code class="doc-symbol doc-symbol-toc doc-symbol-class"></code>&nbsp;TimeoutSession
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#unshackle.core.service.TimeoutHTTPAdapter" class="md-nav__link">
<span class="md-ellipsis">
<code class="doc-symbol doc-symbol-toc doc-symbol-class"></code>&nbsp;TimeoutHTTPAdapter
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#unshackle.core.service.TrackRequest" class="md-nav__link">
<span class="md-ellipsis">
<code class="doc-symbol doc-symbol-toc doc-symbol-class"></code>&nbsp;TrackRequest
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#unshackle.core.service.Service" class="md-nav__link">
<span class="md-ellipsis">
<code class="doc-symbol doc-symbol-toc doc-symbol-class"></code>&nbsp;Service
</span>
</a>
<nav class="md-nav" aria-label=" Service">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#unshackle.core.service.Service.get_tracks_for_variants" class="md-nav__link">
<span class="md-ellipsis">
<code class="doc-symbol doc-symbol-toc doc-symbol-method"></code>&nbsp;get_tracks_for_variants
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#unshackle.core.service.Service.get_session" class="md-nav__link">
<span class="md-ellipsis">
<code class="doc-symbol doc-symbol-toc doc-symbol-method"></code>&nbsp;get_session
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#unshackle.core.service.Service.authenticate" class="md-nav__link">
<span class="md-ellipsis">
<code class="doc-symbol doc-symbol-toc doc-symbol-method"></code>&nbsp;authenticate
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#unshackle.core.service.Service.request_input" class="md-nav__link">
<span class="md-ellipsis">
<code class="doc-symbol doc-symbol-toc doc-symbol-method"></code>&nbsp;request_input
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#unshackle.core.service.Service.search" class="md-nav__link">
<span class="md-ellipsis">
<code class="doc-symbol doc-symbol-toc doc-symbol-method"></code>&nbsp;search
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#unshackle.core.service.Service.get_widevine_service_certificate" class="md-nav__link">
<span class="md-ellipsis">
<code class="doc-symbol doc-symbol-toc doc-symbol-method"></code>&nbsp;get_widevine_service_certificate
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#unshackle.core.service.Service.get_widevine_license" class="md-nav__link">
<span class="md-ellipsis">
<code class="doc-symbol doc-symbol-toc doc-symbol-method"></code>&nbsp;get_widevine_license
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#unshackle.core.service.Service.get_playready_license" class="md-nav__link">
<span class="md-ellipsis">
<code class="doc-symbol doc-symbol-toc doc-symbol-method"></code>&nbsp;get_playready_license
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#unshackle.core.service.Service.get_clearkey_license" class="md-nav__link">
<span class="md-ellipsis">
<code class="doc-symbol doc-symbol-toc doc-symbol-method"></code>&nbsp;get_clearkey_license
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#unshackle.core.service.Service.get_titles" class="md-nav__link">
<span class="md-ellipsis">
<code class="doc-symbol doc-symbol-toc doc-symbol-method"></code>&nbsp;get_titles
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#unshackle.core.service.Service.get_titles_cached" class="md-nav__link">
<span class="md-ellipsis">
<code class="doc-symbol doc-symbol-toc doc-symbol-method"></code>&nbsp;get_titles_cached
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#unshackle.core.service.Service.apply_title_map" class="md-nav__link">
<span class="md-ellipsis">
<code class="doc-symbol doc-symbol-toc doc-symbol-method"></code>&nbsp;apply_title_map
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#unshackle.core.service.Service.get_tracks" class="md-nav__link">
<span class="md-ellipsis">
<code class="doc-symbol doc-symbol-toc doc-symbol-method"></code>&nbsp;get_tracks
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#unshackle.core.service.Service.get_chapters" class="md-nav__link">
<span class="md-ellipsis">
<code class="doc-symbol doc-symbol-toc doc-symbol-method"></code>&nbsp;get_chapters
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#unshackle.core.service.Service.on_segment_downloaded" class="md-nav__link">
<span class="md-ellipsis">
<code class="doc-symbol doc-symbol-toc doc-symbol-method"></code>&nbsp;on_segment_downloaded
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#unshackle.core.service.Service.on_track_downloaded" class="md-nav__link">
<span class="md-ellipsis">
<code class="doc-symbol doc-symbol-toc doc-symbol-method"></code>&nbsp;on_track_downloaded
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#unshackle.core.service.Service.on_track_decrypted" class="md-nav__link">
<span class="md-ellipsis">
<code class="doc-symbol doc-symbol-toc doc-symbol-method"></code>&nbsp;on_track_decrypted
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#unshackle.core.service.Service.on_track_repacked" class="md-nav__link">
<span class="md-ellipsis">
<code class="doc-symbol doc-symbol-toc doc-symbol-method"></code>&nbsp;on_track_repacked
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#unshackle.core.service.Service.on_track_multiplex" class="md-nav__link">
<span class="md-ellipsis">
<code class="doc-symbol doc-symbol-toc doc-symbol-method"></code>&nbsp;on_track_multiplex
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#unshackle.core.service.sanitize_proxy_for_log" class="md-nav__link">
<span class="md-ellipsis">
<code class="doc-symbol doc-symbol-toc doc-symbol-function"></code>&nbsp;sanitize_proxy_for_log
</span>
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-content" data-md-component="content">
<article class="md-content__inner md-typeset">
<h1 id="service-api">Service API<a class="headerlink" href="#service-api" title="Permanent link">&para;</a></h1>
<p>Auto-generated reference for the <a class="autorefs autorefs-internal" title="&lt;code class=&quot;doc-symbol doc-symbol-heading doc-symbol-class&quot;&gt;&lt;/code&gt; &lt;span class=&quot;doc doc-object-name doc-class-name&quot;&gt;Service&lt;/span&gt;" href="#unshackle.core.service.Service"><code>Service</code></a> base class that every
service plugin subclasses. See <a href="../../../dev/creating-a-service/">Creating a Service</a> for a guided
walkthrough and <a href="../../../dev/service-architecture/">Service Architecture</a> for the wider object model.</p>
<div class="doc doc-object doc-module">
<a id="unshackle.core.service"></a>
<div class="doc doc-contents first">
<div class="doc doc-children">
<div class="doc doc-object doc-class">
<h2 id="unshackle.core.service.TimeoutSession" class="doc doc-heading">
<code class="doc-symbol doc-symbol-heading doc-symbol-class"></code> <span class="doc doc-object-name doc-class-name">TimeoutSession</span>
<a href="#unshackle.core.service.TimeoutSession" class="headerlink" title="Permanent link">&para;</a></h2>
<div class="doc doc-contents ">
<p class="doc doc-class-bases">
Bases: <code><span title="requests.Session">Session</span></code></p>
<p>requests.Session applying DEFAULT_TIMEOUT when the caller passes none.</p>
<p>requests has no native default timeout; without one a stalled connect or
read hangs forever. RnetSession bounds every request via its client's
connect_timeout/read_timeout, so this mirrors that on the requests path.
A per-request non-None <code>timeout=</code> wins; an explicit <code>timeout=None</code> is
still replaced with the default by :class:<code>TimeoutHTTPAdapter</code> on the
mounted adapters, so there is no unbounded read, matching RnetSession where
the client-level timeouts always apply. Pass a large timeout instead.</p>
<div class="doc doc-children">
</div>
</div>
</div>
<div class="doc doc-object doc-class">
<h2 id="unshackle.core.service.TimeoutHTTPAdapter" class="doc doc-heading">
<code class="doc-symbol doc-symbol-heading doc-symbol-class"></code> <span class="doc doc-object-name doc-class-name">TimeoutHTTPAdapter</span>
<a href="#unshackle.core.service.TimeoutHTTPAdapter" class="headerlink" title="Permanent link">&para;</a></h2>
<div class="language-python doc-signature highlight"><pre><span></span><code><span id="__span-0-1"><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a><span class="nf">TimeoutHTTPAdapter</span><span class="p">(</span>
</span><span id="__span-0-2"><a id="__codelineno-0-2" name="__codelineno-0-2" href="#__codelineno-0-2"></a> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="n">timeout</span><span class="o">=</span><span class="n"><span title="unshackle.core.service.DEFAULT_TIMEOUT">DEFAULT_TIMEOUT</span></span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span>
</span><span id="__span-0-3"><a id="__codelineno-0-3" name="__codelineno-0-3" href="#__codelineno-0-3"></a><span class="p">)</span>
</span></code></pre></div>
<div class="doc doc-contents ">
<p class="doc doc-class-bases">
Bases: <code><span title="requests.adapters.HTTPAdapter">HTTPAdapter</span></code></p>
<p>HTTPAdapter applying DEFAULT_TIMEOUT when the caller passes none.</p>
<p>Backstops :class:<code>TimeoutSession</code> for the <code>session.send(prepared)</code> path,
which bypasses <code>Session.request</code>; RnetSession bounds those too via its
client, so this keeps parity. A per-request non-None <code>timeout=</code> wins;
<code>None</code> (unset, or explicitly passed) gets the default, because the adapter
cannot distinguish the two, and rnet has no unbounded mode either.</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-75">75</a></span>
<span class="normal"><a href="#__codelineno-0-76">76</a></span>
<span class="normal"><a href="#__codelineno-0-77">77</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-75"><a id="__codelineno-0-75" name="__codelineno-0-75"></a><span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">:</span> <span class="n">Any</span><span class="p">,</span> <span class="n">timeout</span><span class="p">:</span> <span class="n">Any</span> <span class="o">=</span> <span class="n">DEFAULT_TIMEOUT</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">:</span> <span class="n">Any</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span><span id="__span-0-76"><a id="__codelineno-0-76" name="__codelineno-0-76"></a> <span class="bp">self</span><span class="o">.</span><span class="n">default_timeout</span> <span class="o">=</span> <span class="n">timeout</span>
</span><span id="__span-0-77"><a id="__codelineno-0-77" name="__codelineno-0-77"></a> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
</span></code></pre></div></td></tr></table></div>
</details>
<div class="doc doc-children">
</div>
</div>
</div>
<div class="doc doc-object doc-class">
<h2 id="unshackle.core.service.TrackRequest" class="doc doc-heading">
<code class="doc-symbol doc-symbol-heading doc-symbol-class"></code> <span class="doc doc-object-name doc-class-name">TrackRequest</span>
<span class="doc doc-labels">
<small class="doc doc-label doc-label-dataclass"><code>dataclass</code></small>
</span>
<a href="#unshackle.core.service.TrackRequest" class="headerlink" title="Permanent link">&para;</a></h2>
<div class="language-python doc-signature highlight"><pre><span></span><code><span id="__span-0-1"><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a><span class="nf">TrackRequest</span><span class="p">(</span>
</span><span id="__span-0-2"><a id="__codelineno-0-2" name="__codelineno-0-2" href="#__codelineno-0-2"></a> <span class="n">codecs</span><span class="o">=</span><span class="n"><span title="list">list</span></span><span class="p">(),</span>
</span><span id="__span-0-3"><a id="__codelineno-0-3" name="__codelineno-0-3" href="#__codelineno-0-3"></a> <span class="n">ranges</span><span class="o">=</span><span class="p">(</span><span class="k">lambda</span><span class="p">:</span> <span class="p">[</span><span class="n"><span title="unshackle.core.tracks.video.Video.Range.SDR">SDR</span></span><span class="p">])(),</span>
</span><span id="__span-0-4"><a id="__codelineno-0-4" name="__codelineno-0-4" href="#__codelineno-0-4"></a> <span class="n">best_available</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
</span><span id="__span-0-5"><a id="__codelineno-0-5" name="__codelineno-0-5" href="#__codelineno-0-5"></a><span class="p">)</span>
</span></code></pre></div>
<div class="doc doc-contents ">
<p>Holds what the user requested for video codec and range selection.</p>
<p>Services read from this instead of ctx.parent.params for vcodec/range.</p>
<p><span class="doc-section-title">Attributes:</span></p>
<table>
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr class="doc-section-item">
<td><code><span title="unshackle.core.service.TrackRequest.codecs">codecs</span></code></td>
<td>
<code><span title="list">list</span>[<span title="unshackle.core.tracks.video.Video.Codec">Codec</span>]</code>
</td>
<td>
<div class="doc-md-description">
<p>Requested codecs from CLI. Empty list means no filter (accept any).</p>
</div>
</td>
</tr>
<tr class="doc-section-item">
<td><code><span title="unshackle.core.service.TrackRequest.ranges">ranges</span></code></td>
<td>
<code><span title="list">list</span>[<a class="autorefs autorefs-internal" title="&lt;code class=&quot;doc-symbol doc-symbol-heading doc-symbol-class&quot;&gt;&lt;/code&gt; &lt;span class=&quot;doc doc-object-name doc-class-name&quot;&gt;Range&lt;/span&gt; (&lt;code&gt;unshackle.core.tracks.video.Video.Range&lt;/code&gt;)" href="../tracks/#unshackle.core.tracks.Video.Range">Range</a>]</code>
</td>
<td>
<div class="doc-md-description">
<p>Requested ranges from CLI. Defaults to [SDR].</p>
</div>
</td>
</tr>
</tbody>
</table>
<div class="doc doc-children">
</div>
</div>
</div>
<div class="doc doc-object doc-class">
<h2 id="unshackle.core.service.Service" class="doc doc-heading">
<code class="doc-symbol doc-symbol-heading doc-symbol-class"></code> <span class="doc doc-object-name doc-class-name">Service</span>
<a href="#unshackle.core.service.Service" class="headerlink" title="Permanent link">&para;</a></h2>
<div class="language-python doc-signature highlight"><pre><span></span><code><span id="__span-0-1"><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a><span class="nf">Service</span><span class="p">(</span><span class="n">ctx</span><span class="p">)</span>
</span></code></pre></div>
<div class="doc doc-contents ">
<p>The Service Base Class.</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-154">154</a></span>
<span class="normal"><a href="#__codelineno-0-155">155</a></span>
<span class="normal"><a href="#__codelineno-0-156">156</a></span>
<span class="normal"><a href="#__codelineno-0-157">157</a></span>
<span class="normal"><a href="#__codelineno-0-158">158</a></span>
<span class="normal"><a href="#__codelineno-0-159">159</a></span>
<span class="normal"><a href="#__codelineno-0-160">160</a></span>
<span class="normal"><a href="#__codelineno-0-161">161</a></span>
<span class="normal"><a href="#__codelineno-0-162">162</a></span>
<span class="normal"><a href="#__codelineno-0-163">163</a></span>
<span class="normal"><a href="#__codelineno-0-164">164</a></span>
<span class="normal"><a href="#__codelineno-0-165">165</a></span>
<span class="normal"><a href="#__codelineno-0-166">166</a></span>
<span class="normal"><a href="#__codelineno-0-167">167</a></span>
<span class="normal"><a href="#__codelineno-0-168">168</a></span>
<span class="normal"><a href="#__codelineno-0-169">169</a></span>
<span class="normal"><a href="#__codelineno-0-170">170</a></span>
<span class="normal"><a href="#__codelineno-0-171">171</a></span>
<span class="normal"><a href="#__codelineno-0-172">172</a></span>
<span class="normal"><a href="#__codelineno-0-173">173</a></span>
<span class="normal"><a href="#__codelineno-0-174">174</a></span>
<span class="normal"><a href="#__codelineno-0-175">175</a></span>
<span class="normal"><a href="#__codelineno-0-176">176</a></span>
<span class="normal"><a href="#__codelineno-0-177">177</a></span>
<span class="normal"><a href="#__codelineno-0-178">178</a></span>
<span class="normal"><a href="#__codelineno-0-179">179</a></span>
<span class="normal"><a href="#__codelineno-0-180">180</a></span>
<span class="normal"><a href="#__codelineno-0-181">181</a></span>
<span class="normal"><a href="#__codelineno-0-182">182</a></span>
<span class="normal"><a href="#__codelineno-0-183">183</a></span>
<span class="normal"><a href="#__codelineno-0-184">184</a></span>
<span class="normal"><a href="#__codelineno-0-185">185</a></span>
<span class="normal"><a href="#__codelineno-0-186">186</a></span>
<span class="normal"><a href="#__codelineno-0-187">187</a></span>
<span class="normal"><a href="#__codelineno-0-188">188</a></span>
<span class="normal"><a href="#__codelineno-0-189">189</a></span>
<span class="normal"><a href="#__codelineno-0-190">190</a></span>
<span class="normal"><a href="#__codelineno-0-191">191</a></span>
<span class="normal"><a href="#__codelineno-0-192">192</a></span>
<span class="normal"><a href="#__codelineno-0-193">193</a></span>
<span class="normal"><a href="#__codelineno-0-194">194</a></span>
<span class="normal"><a href="#__codelineno-0-195">195</a></span>
<span class="normal"><a href="#__codelineno-0-196">196</a></span>
<span class="normal"><a href="#__codelineno-0-197">197</a></span>
<span class="normal"><a href="#__codelineno-0-198">198</a></span>
<span class="normal"><a href="#__codelineno-0-199">199</a></span>
<span class="normal"><a href="#__codelineno-0-200">200</a></span>
<span class="normal"><a href="#__codelineno-0-201">201</a></span>
<span class="normal"><a href="#__codelineno-0-202">202</a></span>
<span class="normal"><a href="#__codelineno-0-203">203</a></span>
<span class="normal"><a href="#__codelineno-0-204">204</a></span>
<span class="normal"><a href="#__codelineno-0-205">205</a></span>
<span class="normal"><a href="#__codelineno-0-206">206</a></span>
<span class="normal"><a href="#__codelineno-0-207">207</a></span>
<span class="normal"><a href="#__codelineno-0-208">208</a></span>
<span class="normal"><a href="#__codelineno-0-209">209</a></span>
<span class="normal"><a href="#__codelineno-0-210">210</a></span>
<span class="normal"><a href="#__codelineno-0-211">211</a></span>
<span class="normal"><a href="#__codelineno-0-212">212</a></span>
<span class="normal"><a href="#__codelineno-0-213">213</a></span>
<span class="normal"><a href="#__codelineno-0-214">214</a></span>
<span class="normal"><a href="#__codelineno-0-215">215</a></span>
<span class="normal"><a href="#__codelineno-0-216">216</a></span>
<span class="normal"><a href="#__codelineno-0-217">217</a></span>
<span class="normal"><a href="#__codelineno-0-218">218</a></span>
<span class="normal"><a href="#__codelineno-0-219">219</a></span>
<span class="normal"><a href="#__codelineno-0-220">220</a></span>
<span class="normal"><a href="#__codelineno-0-221">221</a></span>
<span class="normal"><a href="#__codelineno-0-222">222</a></span>
<span class="normal"><a href="#__codelineno-0-223">223</a></span>
<span class="normal"><a href="#__codelineno-0-224">224</a></span>
<span class="normal"><a href="#__codelineno-0-225">225</a></span>
<span class="normal"><a href="#__codelineno-0-226">226</a></span>
<span class="normal"><a href="#__codelineno-0-227">227</a></span>
<span class="normal"><a href="#__codelineno-0-228">228</a></span>
<span class="normal"><a href="#__codelineno-0-229">229</a></span>
<span class="normal"><a href="#__codelineno-0-230">230</a></span>
<span class="normal"><a href="#__codelineno-0-231">231</a></span>
<span class="normal"><a href="#__codelineno-0-232">232</a></span>
<span class="normal"><a href="#__codelineno-0-233">233</a></span>
<span class="normal"><a href="#__codelineno-0-234">234</a></span>
<span class="normal"><a href="#__codelineno-0-235">235</a></span>
<span class="normal"><a href="#__codelineno-0-236">236</a></span>
<span class="normal"><a href="#__codelineno-0-237">237</a></span>
<span class="normal"><a href="#__codelineno-0-238">238</a></span>
<span class="normal"><a href="#__codelineno-0-239">239</a></span>
<span class="normal"><a href="#__codelineno-0-240">240</a></span>
<span class="normal"><a href="#__codelineno-0-241">241</a></span>
<span class="normal"><a href="#__codelineno-0-242">242</a></span>
<span class="normal"><a href="#__codelineno-0-243">243</a></span>
<span class="normal"><a href="#__codelineno-0-244">244</a></span>
<span class="normal"><a href="#__codelineno-0-245">245</a></span>
<span class="normal"><a href="#__codelineno-0-246">246</a></span>
<span class="normal"><a href="#__codelineno-0-247">247</a></span>
<span class="normal"><a href="#__codelineno-0-248">248</a></span>
<span class="normal"><a href="#__codelineno-0-249">249</a></span>
<span class="normal"><a href="#__codelineno-0-250">250</a></span>
<span class="normal"><a href="#__codelineno-0-251">251</a></span>
<span class="normal"><a href="#__codelineno-0-252">252</a></span>
<span class="normal"><a href="#__codelineno-0-253">253</a></span>
<span class="normal"><a href="#__codelineno-0-254">254</a></span>
<span class="normal"><a href="#__codelineno-0-255">255</a></span>
<span class="normal"><a href="#__codelineno-0-256">256</a></span>
<span class="normal"><a href="#__codelineno-0-257">257</a></span>
<span class="normal"><a href="#__codelineno-0-258">258</a></span>
<span class="normal"><a href="#__codelineno-0-259">259</a></span>
<span class="normal"><a href="#__codelineno-0-260">260</a></span>
<span class="normal"><a href="#__codelineno-0-261">261</a></span>
<span class="normal"><a href="#__codelineno-0-262">262</a></span>
<span class="normal"><a href="#__codelineno-0-263">263</a></span>
<span class="normal"><a href="#__codelineno-0-264">264</a></span>
<span class="normal"><a href="#__codelineno-0-265">265</a></span>
<span class="normal"><a href="#__codelineno-0-266">266</a></span>
<span class="normal"><a href="#__codelineno-0-267">267</a></span>
<span class="normal"><a href="#__codelineno-0-268">268</a></span>
<span class="normal"><a href="#__codelineno-0-269">269</a></span>
<span class="normal"><a href="#__codelineno-0-270">270</a></span>
<span class="normal"><a href="#__codelineno-0-271">271</a></span>
<span class="normal"><a href="#__codelineno-0-272">272</a></span>
<span class="normal"><a href="#__codelineno-0-273">273</a></span>
<span class="normal"><a href="#__codelineno-0-274">274</a></span>
<span class="normal"><a href="#__codelineno-0-275">275</a></span>
<span class="normal"><a href="#__codelineno-0-276">276</a></span>
<span class="normal"><a href="#__codelineno-0-277">277</a></span>
<span class="normal"><a href="#__codelineno-0-278">278</a></span>
<span class="normal"><a href="#__codelineno-0-279">279</a></span>
<span class="normal"><a href="#__codelineno-0-280">280</a></span>
<span class="normal"><a href="#__codelineno-0-281">281</a></span>
<span class="normal"><a href="#__codelineno-0-282">282</a></span>
<span class="normal"><a href="#__codelineno-0-283">283</a></span>
<span class="normal"><a href="#__codelineno-0-284">284</a></span>
<span class="normal"><a href="#__codelineno-0-285">285</a></span>
<span class="normal"><a href="#__codelineno-0-286">286</a></span>
<span class="normal"><a href="#__codelineno-0-287">287</a></span>
<span class="normal"><a href="#__codelineno-0-288">288</a></span>
<span class="normal"><a href="#__codelineno-0-289">289</a></span>
<span class="normal"><a href="#__codelineno-0-290">290</a></span>
<span class="normal"><a href="#__codelineno-0-291">291</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-154"><a id="__codelineno-0-154" name="__codelineno-0-154"></a><span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">ctx</span><span class="p">:</span> <span class="n">click</span><span class="o">.</span><span class="n">Context</span><span class="p">):</span>
</span><span id="__span-0-155"><a id="__codelineno-0-155" name="__codelineno-0-155"></a> <span class="n">console</span><span class="o">.</span><span class="n">print</span><span class="p">(</span><span class="n">Padding</span><span class="p">(</span><span class="n">Rule</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;[rule.text]Service: </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">&quot;</span><span class="p">),</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">)))</span>
</span><span id="__span-0-156"><a id="__codelineno-0-156" name="__codelineno-0-156"></a>
</span><span id="__span-0-157"><a id="__codelineno-0-157" name="__codelineno-0-157"></a> <span class="bp">self</span><span class="o">.</span><span class="n">config</span> <span class="o">=</span> <span class="n">ctx</span><span class="o">.</span><span class="n">obj</span><span class="o">.</span><span class="n">config</span>
</span><span id="__span-0-158"><a id="__codelineno-0-158" name="__codelineno-0-158"></a>
</span><span id="__span-0-159"><a id="__codelineno-0-159" name="__codelineno-0-159"></a> <span class="bp">self</span><span class="o">.</span><span class="n">log</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</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="p">)</span>
</span><span id="__span-0-160"><a id="__codelineno-0-160" name="__codelineno-0-160"></a>
</span><span id="__span-0-161"><a id="__codelineno-0-161" name="__codelineno-0-161"></a> <span class="bp">self</span><span class="o">.</span><span class="n">session</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_session</span><span class="p">()</span>
</span><span id="__span-0-162"><a id="__codelineno-0-162" name="__codelineno-0-162"></a> <span class="bp">self</span><span class="o">.</span><span class="n">cache</span> <span class="o">=</span> <span class="n">Cacher</span><span class="p">(</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="p">)</span>
</span><span id="__span-0-163"><a id="__codelineno-0-163" name="__codelineno-0-163"></a> <span class="bp">self</span><span class="o">.</span><span class="n">title_cache</span> <span class="o">=</span> <span class="n">TitleCacher</span><span class="p">(</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="p">)</span>
</span><span id="__span-0-164"><a id="__codelineno-0-164" name="__codelineno-0-164"></a> <span class="bp">self</span><span class="o">.</span><span class="n">cache_dir</span> <span class="o">=</span> <span class="n">config</span><span class="o">.</span><span class="n">directories</span><span class="o">.</span><span class="n">cache</span> <span class="o">/</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><span id="__span-0-165"><a id="__codelineno-0-165" name="__codelineno-0-165"></a>
</span><span id="__span-0-166"><a id="__codelineno-0-166" name="__codelineno-0-166"></a> <span class="c1"># Store context for cache control flags and credential</span>
</span><span id="__span-0-167"><a id="__codelineno-0-167" name="__codelineno-0-167"></a> <span class="bp">self</span><span class="o">.</span><span class="n">ctx</span> <span class="o">=</span> <span class="n">ctx</span>
</span><span id="__span-0-168"><a id="__codelineno-0-168" name="__codelineno-0-168"></a> <span class="bp">self</span><span class="o">.</span><span class="n">credential</span> <span class="o">=</span> <span class="kc">None</span> <span class="c1"># Will be set in authenticate()</span>
</span><span id="__span-0-169"><a id="__codelineno-0-169" name="__codelineno-0-169"></a> <span class="bp">self</span><span class="o">.</span><span class="n">current_region</span> <span class="o">=</span> <span class="kc">None</span> <span class="c1"># Will be set based on proxy/geolocation</span>
</span><span id="__span-0-170"><a id="__codelineno-0-170" name="__codelineno-0-170"></a> <span class="bp">self</span><span class="o">.</span><span class="n">_input_bridge</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">InputBridge</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
</span><span id="__span-0-171"><a id="__codelineno-0-171" name="__codelineno-0-171"></a>
</span><span id="__span-0-172"><a id="__codelineno-0-172" name="__codelineno-0-172"></a> <span class="c1"># Set track request from CLI params - services can read/override in their __init__</span>
</span><span id="__span-0-173"><a id="__codelineno-0-173" name="__codelineno-0-173"></a> <span class="n">vcodec</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">&quot;vcodec&quot;</span><span class="p">)</span> <span class="k">if</span> <span class="n">ctx</span><span class="o">.</span><span class="n">parent</span> <span class="k">else</span> <span class="kc">None</span>
</span><span id="__span-0-174"><a id="__codelineno-0-174" name="__codelineno-0-174"></a> <span class="n">range_</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">&quot;range_&quot;</span><span class="p">)</span> <span class="k">if</span> <span class="n">ctx</span><span class="o">.</span><span class="n">parent</span> <span class="k">else</span> <span class="kc">None</span>
</span><span id="__span-0-175"><a id="__codelineno-0-175" name="__codelineno-0-175"></a> <span class="n">best_available</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">&quot;best_available&quot;</span><span class="p">,</span> <span class="kc">False</span><span class="p">)</span> <span class="k">if</span> <span class="n">ctx</span><span class="o">.</span><span class="n">parent</span> <span class="k">else</span> <span class="kc">False</span>
</span><span id="__span-0-176"><a id="__codelineno-0-176" name="__codelineno-0-176"></a> <span class="bp">self</span><span class="o">.</span><span class="n">track_request</span> <span class="o">=</span> <span class="n">TrackRequest</span><span class="p">(</span>
</span><span id="__span-0-177"><a id="__codelineno-0-177" name="__codelineno-0-177"></a> <span class="n">codecs</span><span class="o">=</span><span class="nb">list</span><span class="p">(</span><span class="n">vcodec</span><span class="p">)</span> <span class="k">if</span> <span class="n">vcodec</span> <span class="k">else</span> <span class="p">[],</span>
</span><span id="__span-0-178"><a id="__codelineno-0-178" name="__codelineno-0-178"></a> <span class="n">ranges</span><span class="o">=</span><span class="nb">list</span><span class="p">(</span><span class="n">range_</span><span class="p">)</span> <span class="k">if</span> <span class="n">range_</span> <span class="k">else</span> <span class="p">[</span><span class="n">Video</span><span class="o">.</span><span class="n">Range</span><span class="o">.</span><span class="n">SDR</span><span class="p">],</span>
</span><span id="__span-0-179"><a id="__codelineno-0-179" name="__codelineno-0-179"></a> <span class="n">best_available</span><span class="o">=</span><span class="nb">bool</span><span class="p">(</span><span class="n">best_available</span><span class="p">),</span>
</span><span id="__span-0-180"><a id="__codelineno-0-180" name="__codelineno-0-180"></a> <span class="p">)</span>
</span><span id="__span-0-181"><a id="__codelineno-0-181" name="__codelineno-0-181"></a>
</span><span id="__span-0-182"><a id="__codelineno-0-182" name="__codelineno-0-182"></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">ctx</span><span class="o">.</span><span class="n">parent</span> <span class="ow">or</span> <span class="ow">not</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">&quot;no_proxy&quot;</span><span class="p">):</span>
</span><span id="__span-0-183"><a id="__codelineno-0-183" name="__codelineno-0-183"></a> <span class="k">if</span> <span class="n">ctx</span><span class="o">.</span><span class="n">parent</span><span class="p">:</span>
</span><span id="__span-0-184"><a id="__codelineno-0-184" name="__codelineno-0-184"></a> <span class="n">proxy</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="p">[</span><span class="s2">&quot;proxy&quot;</span><span class="p">]</span>
</span><span id="__span-0-185"><a id="__codelineno-0-185" name="__codelineno-0-185"></a> <span class="n">proxy_query</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">&quot;proxy_query&quot;</span><span class="p">)</span>
</span><span id="__span-0-186"><a id="__codelineno-0-186" name="__codelineno-0-186"></a> <span class="n">proxy_provider_name</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">&quot;proxy_provider&quot;</span><span class="p">)</span>
</span><span id="__span-0-187"><a id="__codelineno-0-187" name="__codelineno-0-187"></a> <span class="k">else</span><span class="p">:</span>
</span><span id="__span-0-188"><a id="__codelineno-0-188" name="__codelineno-0-188"></a> <span class="n">proxy</span> <span class="o">=</span> <span class="kc">None</span>
</span><span id="__span-0-189"><a id="__codelineno-0-189" name="__codelineno-0-189"></a> <span class="n">proxy_query</span> <span class="o">=</span> <span class="kc">None</span>
</span><span id="__span-0-190"><a id="__codelineno-0-190" name="__codelineno-0-190"></a> <span class="n">proxy_provider_name</span> <span class="o">=</span> <span class="kc">None</span>
</span><span id="__span-0-191"><a id="__codelineno-0-191" name="__codelineno-0-191"></a>
</span><span id="__span-0-192"><a id="__codelineno-0-192" name="__codelineno-0-192"></a> <span class="c1"># Check for service-specific proxy mapping</span>
</span><span id="__span-0-193"><a id="__codelineno-0-193" name="__codelineno-0-193"></a> <span class="n">service_name</span> <span class="o">=</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><span id="__span-0-194"><a id="__codelineno-0-194" name="__codelineno-0-194"></a> <span class="n">service_config_dict</span> <span class="o">=</span> <span class="n">config</span><span class="o">.</span><span class="n">services</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">service_name</span><span class="p">,</span> <span class="p">{})</span>
</span><span id="__span-0-195"><a id="__codelineno-0-195" name="__codelineno-0-195"></a> <span class="n">proxy_map</span> <span class="o">=</span> <span class="n">service_config_dict</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;proxy_map&quot;</span><span class="p">,</span> <span class="p">{})</span>
</span><span id="__span-0-196"><a id="__codelineno-0-196" name="__codelineno-0-196"></a>
</span><span id="__span-0-197"><a id="__codelineno-0-197" name="__codelineno-0-197"></a> <span class="k">if</span> <span class="n">proxy_map</span> <span class="ow">and</span> <span class="n">proxy_query</span><span class="p">:</span>
</span><span id="__span-0-198"><a id="__codelineno-0-198" name="__codelineno-0-198"></a> <span class="c1"># Build the full proxy query key (e.g., &quot;nordvpn:ca&quot; or &quot;us&quot;)</span>
</span><span id="__span-0-199"><a id="__codelineno-0-199" name="__codelineno-0-199"></a> <span class="k">if</span> <span class="n">proxy_provider_name</span><span class="p">:</span>
</span><span id="__span-0-200"><a id="__codelineno-0-200" name="__codelineno-0-200"></a> <span class="n">full_proxy_key</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">proxy_provider_name</span><span class="si">}</span><span class="s2">:</span><span class="si">{</span><span class="n">proxy_query</span><span class="si">}</span><span class="s2">&quot;</span>
</span><span id="__span-0-201"><a id="__codelineno-0-201" name="__codelineno-0-201"></a> <span class="k">else</span><span class="p">:</span>
</span><span id="__span-0-202"><a id="__codelineno-0-202" name="__codelineno-0-202"></a> <span class="n">full_proxy_key</span> <span class="o">=</span> <span class="n">proxy_query</span>
</span><span id="__span-0-203"><a id="__codelineno-0-203" name="__codelineno-0-203"></a>
</span><span id="__span-0-204"><a id="__codelineno-0-204" name="__codelineno-0-204"></a> <span class="c1"># Check if there&#39;s a mapping for this query</span>
</span><span id="__span-0-205"><a id="__codelineno-0-205" name="__codelineno-0-205"></a> <span class="n">mapped_value</span> <span class="o">=</span> <span class="n">proxy_map</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">full_proxy_key</span><span class="p">)</span>
</span><span id="__span-0-206"><a id="__codelineno-0-206" name="__codelineno-0-206"></a> <span class="k">if</span> <span class="n">mapped_value</span><span class="p">:</span>
</span><span id="__span-0-207"><a id="__codelineno-0-207" name="__codelineno-0-207"></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><span id="__span-0-208"><a id="__codelineno-0-208" name="__codelineno-0-208"></a> <span class="sa">f</span><span class="s2">&quot;Found service-specific proxy mapping: </span><span class="si">{</span><span class="n">full_proxy_key</span><span class="si">}</span><span class="s2"> -&gt; </span><span class="si">{</span><span class="n">sanitize_proxy_for_log</span><span class="p">(</span><span class="n">mapped_value</span><span class="p">)</span><span class="si">}</span><span class="s2">&quot;</span>
</span><span id="__span-0-209"><a id="__codelineno-0-209" name="__codelineno-0-209"></a> <span class="p">)</span>
</span><span id="__span-0-210"><a id="__codelineno-0-210" name="__codelineno-0-210"></a> <span class="c1"># Query the proxy provider with the mapped value</span>
</span><span id="__span-0-211"><a id="__codelineno-0-211" name="__codelineno-0-211"></a> <span class="k">if</span> <span class="n">proxy_provider_name</span><span class="p">:</span>
</span><span id="__span-0-212"><a id="__codelineno-0-212" name="__codelineno-0-212"></a> <span class="c1"># Specific provider requested</span>
</span><span id="__span-0-213"><a id="__codelineno-0-213" name="__codelineno-0-213"></a> <span class="n">proxy_provider</span> <span class="o">=</span> <span class="nb">next</span><span class="p">(</span>
</span><span id="__span-0-214"><a id="__codelineno-0-214" name="__codelineno-0-214"></a> <span class="p">(</span><span class="n">x</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">ctx</span><span class="o">.</span><span class="n">obj</span><span class="o">.</span><span class="n">proxy_providers</span> <span class="k">if</span> <span class="n">x</span><span class="o">.</span><span class="vm">__class__</span><span class="o">.</span><span class="vm">__name__</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="o">==</span> <span class="n">proxy_provider_name</span><span class="p">),</span>
</span><span id="__span-0-215"><a id="__codelineno-0-215" name="__codelineno-0-215"></a> <span class="kc">None</span><span class="p">,</span>
</span><span id="__span-0-216"><a id="__codelineno-0-216" name="__codelineno-0-216"></a> <span class="p">)</span>
</span><span id="__span-0-217"><a id="__codelineno-0-217" name="__codelineno-0-217"></a> <span class="k">if</span> <span class="n">proxy_provider</span><span class="p">:</span>
</span><span id="__span-0-218"><a id="__codelineno-0-218" name="__codelineno-0-218"></a> <span class="n">mapped_proxy_uri</span> <span class="o">=</span> <span class="n">proxy_provider</span><span class="o">.</span><span class="n">get_proxy</span><span class="p">(</span><span class="n">mapped_value</span><span class="p">)</span>
</span><span id="__span-0-219"><a id="__codelineno-0-219" name="__codelineno-0-219"></a> <span class="k">if</span> <span class="n">mapped_proxy_uri</span><span class="p">:</span>
</span><span id="__span-0-220"><a id="__codelineno-0-220" name="__codelineno-0-220"></a> <span class="n">proxy</span> <span class="o">=</span> <span class="n">mapped_proxy_uri</span>
</span><span id="__span-0-221"><a id="__codelineno-0-221" name="__codelineno-0-221"></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><span id="__span-0-222"><a id="__codelineno-0-222" name="__codelineno-0-222"></a> <span class="sa">f</span><span class="s2">&quot;Using mapped proxy from </span><span class="si">{</span><span class="n">proxy_provider</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="si">{</span><span class="n">sanitize_proxy_for_log</span><span class="p">(</span><span class="n">proxy</span><span class="p">)</span><span class="si">}</span><span class="s2">&quot;</span>
</span><span id="__span-0-223"><a id="__codelineno-0-223" name="__codelineno-0-223"></a> <span class="p">)</span>
</span><span id="__span-0-224"><a id="__codelineno-0-224" name="__codelineno-0-224"></a> <span class="k">else</span><span class="p">:</span>
</span><span id="__span-0-225"><a id="__codelineno-0-225" name="__codelineno-0-225"></a> <span class="bp">self</span><span class="o">.</span><span class="n">log</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span>
</span><span id="__span-0-226"><a id="__codelineno-0-226" name="__codelineno-0-226"></a> <span class="sa">f</span><span class="s2">&quot;Failed to get proxy for mapped value &#39;</span><span class="si">{</span><span class="n">sanitize_proxy_for_log</span><span class="p">(</span><span class="n">mapped_value</span><span class="p">)</span><span class="si">}</span><span class="s2">&#39;, using default&quot;</span>
</span><span id="__span-0-227"><a id="__codelineno-0-227" name="__codelineno-0-227"></a> <span class="p">)</span>
</span><span id="__span-0-228"><a id="__codelineno-0-228" name="__codelineno-0-228"></a> <span class="k">else</span><span class="p">:</span>
</span><span id="__span-0-229"><a id="__codelineno-0-229" name="__codelineno-0-229"></a> <span class="bp">self</span><span class="o">.</span><span class="n">log</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Proxy provider &#39;</span><span class="si">{</span><span class="n">proxy_provider_name</span><span class="si">}</span><span class="s2">&#39; not found, using default proxy&quot;</span><span class="p">)</span>
</span><span id="__span-0-230"><a id="__codelineno-0-230" name="__codelineno-0-230"></a> <span class="k">else</span><span class="p">:</span>
</span><span id="__span-0-231"><a id="__codelineno-0-231" name="__codelineno-0-231"></a> <span class="c1"># No specific provider, try all providers</span>
</span><span id="__span-0-232"><a id="__codelineno-0-232" name="__codelineno-0-232"></a> <span class="k">for</span> <span class="n">proxy_provider</span> <span class="ow">in</span> <span class="n">ctx</span><span class="o">.</span><span class="n">obj</span><span class="o">.</span><span class="n">proxy_providers</span><span class="p">:</span>
</span><span id="__span-0-233"><a id="__codelineno-0-233" name="__codelineno-0-233"></a> <span class="n">mapped_proxy_uri</span> <span class="o">=</span> <span class="n">proxy_provider</span><span class="o">.</span><span class="n">get_proxy</span><span class="p">(</span><span class="n">mapped_value</span><span class="p">)</span>
</span><span id="__span-0-234"><a id="__codelineno-0-234" name="__codelineno-0-234"></a> <span class="k">if</span> <span class="n">mapped_proxy_uri</span><span class="p">:</span>
</span><span id="__span-0-235"><a id="__codelineno-0-235" name="__codelineno-0-235"></a> <span class="n">proxy</span> <span class="o">=</span> <span class="n">mapped_proxy_uri</span>
</span><span id="__span-0-236"><a id="__codelineno-0-236" name="__codelineno-0-236"></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><span id="__span-0-237"><a id="__codelineno-0-237" name="__codelineno-0-237"></a> <span class="sa">f</span><span class="s2">&quot;Using mapped proxy from </span><span class="si">{</span><span class="n">proxy_provider</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="si">{</span><span class="n">sanitize_proxy_for_log</span><span class="p">(</span><span class="n">proxy</span><span class="p">)</span><span class="si">}</span><span class="s2">&quot;</span>
</span><span id="__span-0-238"><a id="__codelineno-0-238" name="__codelineno-0-238"></a> <span class="p">)</span>
</span><span id="__span-0-239"><a id="__codelineno-0-239" name="__codelineno-0-239"></a> <span class="k">break</span>
</span><span id="__span-0-240"><a id="__codelineno-0-240" name="__codelineno-0-240"></a> <span class="k">else</span><span class="p">:</span>
</span><span id="__span-0-241"><a id="__codelineno-0-241" name="__codelineno-0-241"></a> <span class="bp">self</span><span class="o">.</span><span class="n">log</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span>
</span><span id="__span-0-242"><a id="__codelineno-0-242" name="__codelineno-0-242"></a> <span class="sa">f</span><span class="s2">&quot;No provider could resolve mapped value &#39;</span><span class="si">{</span><span class="n">sanitize_proxy_for_log</span><span class="p">(</span><span class="n">mapped_value</span><span class="p">)</span><span class="si">}</span><span class="s2">&#39;, using default&quot;</span>
</span><span id="__span-0-243"><a id="__codelineno-0-243" name="__codelineno-0-243"></a> <span class="p">)</span>
</span><span id="__span-0-244"><a id="__codelineno-0-244" name="__codelineno-0-244"></a>
</span><span id="__span-0-245"><a id="__codelineno-0-245" name="__codelineno-0-245"></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">proxy</span><span class="p">:</span>
</span><span id="__span-0-246"><a id="__codelineno-0-246" name="__codelineno-0-246"></a> <span class="c1"># don&#39;t override the explicit proxy set by the user, even if they may be geoblocked</span>
</span><span id="__span-0-247"><a id="__codelineno-0-247" name="__codelineno-0-247"></a> <span class="k">with</span> <span class="n">console</span><span class="o">.</span><span class="n">status</span><span class="p">(</span><span class="s2">&quot;Checking if current region is Geoblocked...&quot;</span><span class="p">,</span> <span class="n">spinner</span><span class="o">=</span><span class="s2">&quot;dots&quot;</span><span class="p">):</span>
</span><span id="__span-0-248"><a id="__codelineno-0-248" name="__codelineno-0-248"></a> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">GEOFENCE</span><span class="p">:</span>
</span><span id="__span-0-249"><a id="__codelineno-0-249" name="__codelineno-0-249"></a> <span class="c1"># Service has geofence - need fresh IP check to determine if proxy needed</span>
</span><span id="__span-0-250"><a id="__codelineno-0-250" name="__codelineno-0-250"></a> <span class="k">try</span><span class="p">:</span>
</span><span id="__span-0-251"><a id="__codelineno-0-251" name="__codelineno-0-251"></a> <span class="n">current_region</span> <span class="o">=</span> <span class="n">get_ip_info</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">session</span><span class="p">)[</span><span class="s2">&quot;country&quot;</span><span class="p">]</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span>
</span><span id="__span-0-252"><a id="__codelineno-0-252" name="__codelineno-0-252"></a> <span class="k">if</span> <span class="nb">any</span><span class="p">(</span><span class="n">x</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="o">==</span> <span class="n">current_region</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">GEOFENCE</span><span class="p">):</span>
</span><span id="__span-0-253"><a id="__codelineno-0-253" name="__codelineno-0-253"></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="s2">&quot;Service is not Geoblocked in your region&quot;</span><span class="p">)</span>
</span><span id="__span-0-254"><a id="__codelineno-0-254" name="__codelineno-0-254"></a> <span class="k">else</span><span class="p">:</span>
</span><span id="__span-0-255"><a id="__codelineno-0-255" name="__codelineno-0-255"></a> <span class="n">requested_proxy</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">GEOFENCE</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="c1"># first is likely main region</span>
</span><span id="__span-0-256"><a id="__codelineno-0-256" name="__codelineno-0-256"></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><span id="__span-0-257"><a id="__codelineno-0-257" name="__codelineno-0-257"></a> <span class="sa">f</span><span class="s2">&quot;Service is Geoblocked in your region, getting a Proxy to </span><span class="si">{</span><span class="n">requested_proxy</span><span class="si">}</span><span class="s2">&quot;</span>
</span><span id="__span-0-258"><a id="__codelineno-0-258" name="__codelineno-0-258"></a> <span class="p">)</span>
</span><span id="__span-0-259"><a id="__codelineno-0-259" name="__codelineno-0-259"></a> <span class="k">for</span> <span class="n">proxy_provider</span> <span class="ow">in</span> <span class="n">ctx</span><span class="o">.</span><span class="n">obj</span><span class="o">.</span><span class="n">proxy_providers</span><span class="p">:</span>
</span><span id="__span-0-260"><a id="__codelineno-0-260" name="__codelineno-0-260"></a> <span class="n">proxy</span> <span class="o">=</span> <span class="n">proxy_provider</span><span class="o">.</span><span class="n">get_proxy</span><span class="p">(</span><span class="n">requested_proxy</span><span class="p">)</span>
</span><span id="__span-0-261"><a id="__codelineno-0-261" name="__codelineno-0-261"></a> <span class="k">if</span> <span class="n">proxy</span><span class="p">:</span>
</span><span id="__span-0-262"><a id="__codelineno-0-262" name="__codelineno-0-262"></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="sa">f</span><span class="s2">&quot;Got Proxy from </span><span class="si">{</span><span class="n">proxy_provider</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">&quot;</span><span class="p">)</span>
</span><span id="__span-0-263"><a id="__codelineno-0-263" name="__codelineno-0-263"></a> <span class="k">break</span>
</span><span id="__span-0-264"><a id="__codelineno-0-264" name="__codelineno-0-264"></a> <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
</span><span id="__span-0-265"><a id="__codelineno-0-265" name="__codelineno-0-265"></a> <span class="bp">self</span><span class="o">.</span><span class="n">log</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Failed to check geofence: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
</span><span id="__span-0-266"><a id="__codelineno-0-266" name="__codelineno-0-266"></a> <span class="n">current_region</span> <span class="o">=</span> <span class="kc">None</span>
</span><span id="__span-0-267"><a id="__codelineno-0-267" name="__codelineno-0-267"></a> <span class="k">else</span><span class="p">:</span>
</span><span id="__span-0-268"><a id="__codelineno-0-268" name="__codelineno-0-268"></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="s2">&quot;Service has no Geofence&quot;</span><span class="p">)</span>
</span><span id="__span-0-269"><a id="__codelineno-0-269" name="__codelineno-0-269"></a>
</span><span id="__span-0-270"><a id="__codelineno-0-270" name="__codelineno-0-270"></a> <span class="k">if</span> <span class="n">proxy</span><span class="p">:</span>
</span><span id="__span-0-271"><a id="__codelineno-0-271" name="__codelineno-0-271"></a> <span class="bp">self</span><span class="o">.</span><span class="n">session</span><span class="o">.</span><span class="n">proxies</span><span class="o">.</span><span class="n">update</span><span class="p">({</span><span class="s2">&quot;all&quot;</span><span class="p">:</span> <span class="n">proxy</span><span class="p">})</span>
</span><span id="__span-0-272"><a id="__codelineno-0-272" name="__codelineno-0-272"></a> <span class="c1"># Don&#39;t set Proxy-Authorization manually: both rnet (Proxy.all) and</span>
</span><span id="__span-0-273"><a id="__codelineno-0-273" name="__codelineno-0-273"></a> <span class="c1"># requests authenticate from the credentials embedded in the proxy URL.</span>
</span><span id="__span-0-274"><a id="__codelineno-0-274" name="__codelineno-0-274"></a> <span class="c1"># A manual header here was malformed (no &quot;Basic &quot; scheme) and broke</span>
</span><span id="__span-0-275"><a id="__codelineno-0-275" name="__codelineno-0-275"></a> <span class="c1"># plaintext-http forward-proxy requests with HTTP 407.</span>
</span><span id="__span-0-276"><a id="__codelineno-0-276" name="__codelineno-0-276"></a> <span class="c1"># Always verify proxy IP - proxies can change exit nodes</span>
</span><span id="__span-0-277"><a id="__codelineno-0-277" name="__codelineno-0-277"></a> <span class="k">try</span><span class="p">:</span>
</span><span id="__span-0-278"><a id="__codelineno-0-278" name="__codelineno-0-278"></a> <span class="n">proxy_ip_info</span> <span class="o">=</span> <span class="n">get_ip_info</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">session</span><span class="p">)</span>
</span><span id="__span-0-279"><a id="__codelineno-0-279" name="__codelineno-0-279"></a> <span class="bp">self</span><span class="o">.</span><span class="n">current_region</span> <span class="o">=</span> <span class="n">proxy_ip_info</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;country&quot;</span><span class="p">,</span> <span class="s2">&quot;&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="k">if</span> <span class="n">proxy_ip_info</span> <span class="k">else</span> <span class="kc">None</span>
</span><span id="__span-0-280"><a id="__codelineno-0-280" name="__codelineno-0-280"></a> <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
</span><span id="__span-0-281"><a id="__codelineno-0-281" name="__codelineno-0-281"></a> <span class="bp">self</span><span class="o">.</span><span class="n">log</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Failed to verify proxy IP: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
</span><span id="__span-0-282"><a id="__codelineno-0-282" name="__codelineno-0-282"></a> <span class="c1"># Fallback to extracting region from proxy config</span>
</span><span id="__span-0-283"><a id="__codelineno-0-283" name="__codelineno-0-283"></a> <span class="bp">self</span><span class="o">.</span><span class="n">current_region</span> <span class="o">=</span> <span class="n">get_region_from_proxy</span><span class="p">(</span><span class="n">proxy</span><span class="p">)</span>
</span><span id="__span-0-284"><a id="__codelineno-0-284" name="__codelineno-0-284"></a> <span class="k">else</span><span class="p">:</span>
</span><span id="__span-0-285"><a id="__codelineno-0-285" name="__codelineno-0-285"></a> <span class="c1"># No proxy, use cached IP info for title caching (non-critical)</span>
</span><span id="__span-0-286"><a id="__codelineno-0-286" name="__codelineno-0-286"></a> <span class="k">try</span><span class="p">:</span>
</span><span id="__span-0-287"><a id="__codelineno-0-287" name="__codelineno-0-287"></a> <span class="n">ip_info</span> <span class="o">=</span> <span class="n">get_ip_info</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">session</span><span class="p">,</span> <span class="n">cached</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</span><span id="__span-0-288"><a id="__codelineno-0-288" name="__codelineno-0-288"></a> <span class="bp">self</span><span class="o">.</span><span class="n">current_region</span> <span class="o">=</span> <span class="n">ip_info</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;country&quot;</span><span class="p">,</span> <span class="s2">&quot;&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="k">if</span> <span class="n">ip_info</span> <span class="k">else</span> <span class="kc">None</span>
</span><span id="__span-0-289"><a id="__codelineno-0-289" name="__codelineno-0-289"></a> <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
</span><span id="__span-0-290"><a id="__codelineno-0-290" name="__codelineno-0-290"></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="sa">f</span><span class="s2">&quot;Failed to get cached IP info: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
</span><span id="__span-0-291"><a id="__codelineno-0-291" name="__codelineno-0-291"></a> <span class="bp">self</span><span class="o">.</span><span class="n">current_region</span> <span class="o">=</span> <span class="kc">None</span>
</span></code></pre></div></td></tr></table></div>
</details>
<div class="doc doc-children">
<div class="doc doc-object doc-function">
<h3 id="unshackle.core.service.Service.get_tracks_for_variants" class="doc doc-heading">
<code class="doc-symbol doc-symbol-heading doc-symbol-method"></code> <span class="doc doc-object-name doc-function-name">get_tracks_for_variants</span>
<a href="#unshackle.core.service.Service.get_tracks_for_variants" class="headerlink" title="Permanent link">&para;</a></h3>
<div class="language-python doc-signature highlight"><pre><span></span><code><span id="__span-0-1"><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a><span class="nf">get_tracks_for_variants</span><span class="p">(</span><span class="n">title</span><span class="p">,</span> <span class="n">fetch_fn</span><span class="p">)</span>
</span></code></pre></div>
<div class="doc doc-contents ">
<p>Call fetch_fn for each codec/range combo in track_request, merge results.</p>
<p>Services that need separate API calls per codec/range combo can use this
helper from their get_tracks() implementation.</p>
<p>The fetch_fn signature should be: (title, codec, range_) -&gt; Tracks</p>
<p>For HYBRID range, fetch_fn is called with HDR10 and DV separately and
the DV video tracks are merged into the HDR10 result.</p>
<p><span class="doc-section-title">Parameters:</span></p>
<table>
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Description</th>
<th>Default</th>
</tr>
</thead>
<tbody>
<tr class="doc-section-item">
<td>
<code>title</code>
</td>
<td>
<code><span title="unshackle.core.titles.Title_T">Title_T</span></code>
</td>
<td>
<div class="doc-md-description">
<p>The title being processed.</p>
</div>
</td>
<td>
<em>required</em>
</td>
</tr>
<tr class="doc-section-item">
<td>
<code>fetch_fn</code>
</td>
<td>
<code><span title="collections.abc.Callable">Callable</span>[..., <a class="autorefs autorefs-internal" title="&lt;code class=&quot;doc-symbol doc-symbol-heading doc-symbol-class&quot;&gt;&lt;/code&gt; &lt;span class=&quot;doc doc-object-name doc-class-name&quot;&gt;Tracks&lt;/span&gt; (&lt;code&gt;unshackle.core.tracks.Tracks&lt;/code&gt;)" href="../tracks/#unshackle.core.tracks.Tracks">Tracks</a>]</code>
</td>
<td>
<div class="doc-md-description">
<p>A callable that fetches tracks for a specific codec/range.</p>
</div>
</td>
<td>
<em>required</em>
</td>
</tr>
</tbody>
</table>
<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-293">293</a></span>
<span class="normal"><a href="#__codelineno-0-294">294</a></span>
<span class="normal"><a href="#__codelineno-0-295">295</a></span>
<span class="normal"><a href="#__codelineno-0-296">296</a></span>
<span class="normal"><a href="#__codelineno-0-297">297</a></span>
<span class="normal"><a href="#__codelineno-0-298">298</a></span>
<span class="normal"><a href="#__codelineno-0-299">299</a></span>
<span class="normal"><a href="#__codelineno-0-300">300</a></span>
<span class="normal"><a href="#__codelineno-0-301">301</a></span>
<span class="normal"><a href="#__codelineno-0-302">302</a></span>
<span class="normal"><a href="#__codelineno-0-303">303</a></span>
<span class="normal"><a href="#__codelineno-0-304">304</a></span>
<span class="normal"><a href="#__codelineno-0-305">305</a></span>
<span class="normal"><a href="#__codelineno-0-306">306</a></span>
<span class="normal"><a href="#__codelineno-0-307">307</a></span>
<span class="normal"><a href="#__codelineno-0-308">308</a></span>
<span class="normal"><a href="#__codelineno-0-309">309</a></span>
<span class="normal"><a href="#__codelineno-0-310">310</a></span>
<span class="normal"><a href="#__codelineno-0-311">311</a></span>
<span class="normal"><a href="#__codelineno-0-312">312</a></span>
<span class="normal"><a href="#__codelineno-0-313">313</a></span>
<span class="normal"><a href="#__codelineno-0-314">314</a></span>
<span class="normal"><a href="#__codelineno-0-315">315</a></span>
<span class="normal"><a href="#__codelineno-0-316">316</a></span>
<span class="normal"><a href="#__codelineno-0-317">317</a></span>
<span class="normal"><a href="#__codelineno-0-318">318</a></span>
<span class="normal"><a href="#__codelineno-0-319">319</a></span>
<span class="normal"><a href="#__codelineno-0-320">320</a></span>
<span class="normal"><a href="#__codelineno-0-321">321</a></span>
<span class="normal"><a href="#__codelineno-0-322">322</a></span>
<span class="normal"><a href="#__codelineno-0-323">323</a></span>
<span class="normal"><a href="#__codelineno-0-324">324</a></span>
<span class="normal"><a href="#__codelineno-0-325">325</a></span>
<span class="normal"><a href="#__codelineno-0-326">326</a></span>
<span class="normal"><a href="#__codelineno-0-327">327</a></span>
<span class="normal"><a href="#__codelineno-0-328">328</a></span>
<span class="normal"><a href="#__codelineno-0-329">329</a></span>
<span class="normal"><a href="#__codelineno-0-330">330</a></span>
<span class="normal"><a href="#__codelineno-0-331">331</a></span>
<span class="normal"><a href="#__codelineno-0-332">332</a></span>
<span class="normal"><a href="#__codelineno-0-333">333</a></span>
<span class="normal"><a href="#__codelineno-0-334">334</a></span>
<span class="normal"><a href="#__codelineno-0-335">335</a></span>
<span class="normal"><a href="#__codelineno-0-336">336</a></span>
<span class="normal"><a href="#__codelineno-0-337">337</a></span>
<span class="normal"><a href="#__codelineno-0-338">338</a></span>
<span class="normal"><a href="#__codelineno-0-339">339</a></span>
<span class="normal"><a href="#__codelineno-0-340">340</a></span>
<span class="normal"><a href="#__codelineno-0-341">341</a></span>
<span class="normal"><a href="#__codelineno-0-342">342</a></span>
<span class="normal"><a href="#__codelineno-0-343">343</a></span>
<span class="normal"><a href="#__codelineno-0-344">344</a></span>
<span class="normal"><a href="#__codelineno-0-345">345</a></span>
<span class="normal"><a href="#__codelineno-0-346">346</a></span>
<span class="normal"><a href="#__codelineno-0-347">347</a></span>
<span class="normal"><a href="#__codelineno-0-348">348</a></span>
<span class="normal"><a href="#__codelineno-0-349">349</a></span>
<span class="normal"><a href="#__codelineno-0-350">350</a></span>
<span class="normal"><a href="#__codelineno-0-351">351</a></span>
<span class="normal"><a href="#__codelineno-0-352">352</a></span>
<span class="normal"><a href="#__codelineno-0-353">353</a></span>
<span class="normal"><a href="#__codelineno-0-354">354</a></span>
<span class="normal"><a href="#__codelineno-0-355">355</a></span>
<span class="normal"><a href="#__codelineno-0-356">356</a></span>
<span class="normal"><a href="#__codelineno-0-357">357</a></span>
<span class="normal"><a href="#__codelineno-0-358">358</a></span>
<span class="normal"><a href="#__codelineno-0-359">359</a></span>
<span class="normal"><a href="#__codelineno-0-360">360</a></span>
<span class="normal"><a href="#__codelineno-0-361">361</a></span>
<span class="normal"><a href="#__codelineno-0-362">362</a></span>
<span class="normal"><a href="#__codelineno-0-363">363</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-293"><a id="__codelineno-0-293" name="__codelineno-0-293"></a><span class="k">def</span><span class="w"> </span><span class="nf">get_tracks_for_variants</span><span class="p">(</span>
</span><span id="__span-0-294"><a id="__codelineno-0-294" name="__codelineno-0-294"></a> <span class="bp">self</span><span class="p">,</span>
</span><span id="__span-0-295"><a id="__codelineno-0-295" name="__codelineno-0-295"></a> <span class="n">title</span><span class="p">:</span> <span class="n">Title_T</span><span class="p">,</span>
</span><span id="__span-0-296"><a id="__codelineno-0-296" name="__codelineno-0-296"></a> <span class="n">fetch_fn</span><span class="p">:</span> <span class="n">Callable</span><span class="p">[</span><span class="o">...</span><span class="p">,</span> <span class="n">Tracks</span><span class="p">],</span>
</span><span id="__span-0-297"><a id="__codelineno-0-297" name="__codelineno-0-297"></a><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Tracks</span><span class="p">:</span>
</span><span id="__span-0-298"><a id="__codelineno-0-298" name="__codelineno-0-298"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Call fetch_fn for each codec/range combo in track_request, merge results.</span>
</span><span id="__span-0-299"><a id="__codelineno-0-299" name="__codelineno-0-299"></a>
</span><span id="__span-0-300"><a id="__codelineno-0-300" name="__codelineno-0-300"></a><span class="sd"> Services that need separate API calls per codec/range combo can use this</span>
</span><span id="__span-0-301"><a id="__codelineno-0-301" name="__codelineno-0-301"></a><span class="sd"> helper from their get_tracks() implementation.</span>
</span><span id="__span-0-302"><a id="__codelineno-0-302" name="__codelineno-0-302"></a>
</span><span id="__span-0-303"><a id="__codelineno-0-303" name="__codelineno-0-303"></a><span class="sd"> The fetch_fn signature should be: (title, codec, range_) -&gt; Tracks</span>
</span><span id="__span-0-304"><a id="__codelineno-0-304" name="__codelineno-0-304"></a>
</span><span id="__span-0-305"><a id="__codelineno-0-305" name="__codelineno-0-305"></a><span class="sd"> For HYBRID range, fetch_fn is called with HDR10 and DV separately and</span>
</span><span id="__span-0-306"><a id="__codelineno-0-306" name="__codelineno-0-306"></a><span class="sd"> the DV video tracks are merged into the HDR10 result.</span>
</span><span id="__span-0-307"><a id="__codelineno-0-307" name="__codelineno-0-307"></a>
</span><span id="__span-0-308"><a id="__codelineno-0-308" name="__codelineno-0-308"></a><span class="sd"> Args:</span>
</span><span id="__span-0-309"><a id="__codelineno-0-309" name="__codelineno-0-309"></a><span class="sd"> title: The title being processed.</span>
</span><span id="__span-0-310"><a id="__codelineno-0-310" name="__codelineno-0-310"></a><span class="sd"> fetch_fn: A callable that fetches tracks for a specific codec/range.</span>
</span><span id="__span-0-311"><a id="__codelineno-0-311" name="__codelineno-0-311"></a><span class="sd"> &quot;&quot;&quot;</span>
</span><span id="__span-0-312"><a id="__codelineno-0-312" name="__codelineno-0-312"></a> <span class="n">all_tracks</span> <span class="o">=</span> <span class="n">Tracks</span><span class="p">()</span>
</span><span id="__span-0-313"><a id="__codelineno-0-313" name="__codelineno-0-313"></a> <span class="n">first</span> <span class="o">=</span> <span class="kc">True</span>
</span><span id="__span-0-314"><a id="__codelineno-0-314" name="__codelineno-0-314"></a>
</span><span id="__span-0-315"><a id="__codelineno-0-315" name="__codelineno-0-315"></a> <span class="n">codecs</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">track_request</span><span class="o">.</span><span class="n">codecs</span> <span class="ow">or</span> <span class="p">[</span><span class="kc">None</span><span class="p">]</span>
</span><span id="__span-0-316"><a id="__codelineno-0-316" name="__codelineno-0-316"></a> <span class="n">ranges</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">track_request</span><span class="o">.</span><span class="n">ranges</span> <span class="ow">or</span> <span class="p">[</span><span class="n">Video</span><span class="o">.</span><span class="n">Range</span><span class="o">.</span><span class="n">SDR</span><span class="p">]</span>
</span><span id="__span-0-317"><a id="__codelineno-0-317" name="__codelineno-0-317"></a>
</span><span id="__span-0-318"><a id="__codelineno-0-318" name="__codelineno-0-318"></a> <span class="k">for</span> <span class="n">range_val</span> <span class="ow">in</span> <span class="n">ranges</span><span class="p">:</span>
</span><span id="__span-0-319"><a id="__codelineno-0-319" name="__codelineno-0-319"></a> <span class="k">if</span> <span class="n">range_val</span> <span class="o">==</span> <span class="n">Video</span><span class="o">.</span><span class="n">Range</span><span class="o">.</span><span class="n">HYBRID</span><span class="p">:</span>
</span><span id="__span-0-320"><a id="__codelineno-0-320" name="__codelineno-0-320"></a> <span class="c1"># HYBRID: fetch HDR10 first (full tracks), then DV (video only)</span>
</span><span id="__span-0-321"><a id="__codelineno-0-321" name="__codelineno-0-321"></a> <span class="k">for</span> <span class="n">codec_val</span> <span class="ow">in</span> <span class="n">codecs</span><span class="p">:</span>
</span><span id="__span-0-322"><a id="__codelineno-0-322" name="__codelineno-0-322"></a> <span class="k">try</span><span class="p">:</span>
</span><span id="__span-0-323"><a id="__codelineno-0-323" name="__codelineno-0-323"></a> <span class="n">hdr_tracks</span> <span class="o">=</span> <span class="n">fetch_fn</span><span class="p">(</span><span class="n">title</span><span class="p">,</span> <span class="n">codec</span><span class="o">=</span><span class="n">codec_val</span><span class="p">,</span> <span class="n">range_</span><span class="o">=</span><span class="n">Video</span><span class="o">.</span><span class="n">Range</span><span class="o">.</span><span class="n">HDR10</span><span class="p">)</span>
</span><span id="__span-0-324"><a id="__codelineno-0-324" name="__codelineno-0-324"></a> <span class="k">except</span> <span class="p">(</span><span class="ne">ValueError</span><span class="p">,</span> <span class="ne">SystemExit</span><span class="p">)</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
</span><span id="__span-0-325"><a id="__codelineno-0-325" name="__codelineno-0-325"></a> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">track_request</span><span class="o">.</span><span class="n">best_available</span><span class="p">:</span>
</span><span id="__span-0-326"><a id="__codelineno-0-326" name="__codelineno-0-326"></a> <span class="bp">self</span><span class="o">.</span><span class="n">log</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot; - HDR10 not available for HYBRID, skipping (</span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">)&quot;</span><span class="p">)</span>
</span><span id="__span-0-327"><a id="__codelineno-0-327" name="__codelineno-0-327"></a> <span class="k">continue</span>
</span><span id="__span-0-328"><a id="__codelineno-0-328" name="__codelineno-0-328"></a> <span class="k">raise</span>
</span><span id="__span-0-329"><a id="__codelineno-0-329" name="__codelineno-0-329"></a> <span class="k">if</span> <span class="n">first</span><span class="p">:</span>
</span><span id="__span-0-330"><a id="__codelineno-0-330" name="__codelineno-0-330"></a> <span class="n">all_tracks</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">hdr_tracks</span><span class="p">,</span> <span class="n">warn_only</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</span><span id="__span-0-331"><a id="__codelineno-0-331" name="__codelineno-0-331"></a> <span class="k">if</span> <span class="n">hdr_tracks</span><span class="o">.</span><span class="n">manifest_url</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">all_tracks</span><span class="o">.</span><span class="n">manifest_url</span><span class="p">:</span>
</span><span id="__span-0-332"><a id="__codelineno-0-332" name="__codelineno-0-332"></a> <span class="n">all_tracks</span><span class="o">.</span><span class="n">manifest_url</span> <span class="o">=</span> <span class="n">hdr_tracks</span><span class="o">.</span><span class="n">manifest_url</span>
</span><span id="__span-0-333"><a id="__codelineno-0-333" name="__codelineno-0-333"></a> <span class="n">first</span> <span class="o">=</span> <span class="kc">False</span>
</span><span id="__span-0-334"><a id="__codelineno-0-334" name="__codelineno-0-334"></a> <span class="k">else</span><span class="p">:</span>
</span><span id="__span-0-335"><a id="__codelineno-0-335" name="__codelineno-0-335"></a> <span class="k">for</span> <span class="n">video</span> <span class="ow">in</span> <span class="n">hdr_tracks</span><span class="o">.</span><span class="n">videos</span><span class="p">:</span>
</span><span id="__span-0-336"><a id="__codelineno-0-336" name="__codelineno-0-336"></a> <span class="n">all_tracks</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">video</span><span class="p">,</span> <span class="n">warn_only</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</span><span id="__span-0-337"><a id="__codelineno-0-337" name="__codelineno-0-337"></a>
</span><span id="__span-0-338"><a id="__codelineno-0-338" name="__codelineno-0-338"></a> <span class="k">try</span><span class="p">:</span>
</span><span id="__span-0-339"><a id="__codelineno-0-339" name="__codelineno-0-339"></a> <span class="n">dv_tracks</span> <span class="o">=</span> <span class="n">fetch_fn</span><span class="p">(</span><span class="n">title</span><span class="p">,</span> <span class="n">codec</span><span class="o">=</span><span class="n">codec_val</span><span class="p">,</span> <span class="n">range_</span><span class="o">=</span><span class="n">Video</span><span class="o">.</span><span class="n">Range</span><span class="o">.</span><span class="n">DV</span><span class="p">)</span>
</span><span id="__span-0-340"><a id="__codelineno-0-340" name="__codelineno-0-340"></a> <span class="k">for</span> <span class="n">video</span> <span class="ow">in</span> <span class="n">dv_tracks</span><span class="o">.</span><span class="n">videos</span><span class="p">:</span>
</span><span id="__span-0-341"><a id="__codelineno-0-341" name="__codelineno-0-341"></a> <span class="n">all_tracks</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">video</span><span class="p">,</span> <span class="n">warn_only</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</span><span id="__span-0-342"><a id="__codelineno-0-342" name="__codelineno-0-342"></a> <span class="k">except</span> <span class="p">(</span><span class="ne">ValueError</span><span class="p">,</span> <span class="ne">SystemExit</span><span class="p">):</span>
</span><span id="__span-0-343"><a id="__codelineno-0-343" name="__codelineno-0-343"></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="s2">&quot; - No DolbyVision manifest available for HYBRID&quot;</span><span class="p">)</span>
</span><span id="__span-0-344"><a id="__codelineno-0-344" name="__codelineno-0-344"></a> <span class="k">else</span><span class="p">:</span>
</span><span id="__span-0-345"><a id="__codelineno-0-345" name="__codelineno-0-345"></a> <span class="k">for</span> <span class="n">codec_val</span> <span class="ow">in</span> <span class="n">codecs</span><span class="p">:</span>
</span><span id="__span-0-346"><a id="__codelineno-0-346" name="__codelineno-0-346"></a> <span class="k">try</span><span class="p">:</span>
</span><span id="__span-0-347"><a id="__codelineno-0-347" name="__codelineno-0-347"></a> <span class="n">tracks</span> <span class="o">=</span> <span class="n">fetch_fn</span><span class="p">(</span><span class="n">title</span><span class="p">,</span> <span class="n">codec</span><span class="o">=</span><span class="n">codec_val</span><span class="p">,</span> <span class="n">range_</span><span class="o">=</span><span class="n">range_val</span><span class="p">)</span>
</span><span id="__span-0-348"><a id="__codelineno-0-348" name="__codelineno-0-348"></a> <span class="k">except</span> <span class="p">(</span><span class="ne">ValueError</span><span class="p">,</span> <span class="ne">SystemExit</span><span class="p">)</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
</span><span id="__span-0-349"><a id="__codelineno-0-349" name="__codelineno-0-349"></a> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">track_request</span><span class="o">.</span><span class="n">best_available</span><span class="p">:</span>
</span><span id="__span-0-350"><a id="__codelineno-0-350" name="__codelineno-0-350"></a> <span class="n">codec_name</span> <span class="o">=</span> <span class="n">codec_val</span><span class="o">.</span><span class="n">name</span> <span class="k">if</span> <span class="n">codec_val</span> <span class="k">else</span> <span class="s2">&quot;default&quot;</span>
</span><span id="__span-0-351"><a id="__codelineno-0-351" name="__codelineno-0-351"></a> <span class="bp">self</span><span class="o">.</span><span class="n">log</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot; - </span><span class="si">{</span><span class="n">range_val</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">/</span><span class="si">{</span><span class="n">codec_name</span><span class="si">}</span><span class="s2"> not available, skipping (</span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">)&quot;</span><span class="p">)</span>
</span><span id="__span-0-352"><a id="__codelineno-0-352" name="__codelineno-0-352"></a> <span class="k">continue</span>
</span><span id="__span-0-353"><a id="__codelineno-0-353" name="__codelineno-0-353"></a> <span class="k">raise</span>
</span><span id="__span-0-354"><a id="__codelineno-0-354" name="__codelineno-0-354"></a> <span class="k">if</span> <span class="n">first</span><span class="p">:</span>
</span><span id="__span-0-355"><a id="__codelineno-0-355" name="__codelineno-0-355"></a> <span class="n">all_tracks</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">tracks</span><span class="p">,</span> <span class="n">warn_only</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</span><span id="__span-0-356"><a id="__codelineno-0-356" name="__codelineno-0-356"></a> <span class="k">if</span> <span class="n">tracks</span><span class="o">.</span><span class="n">manifest_url</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">all_tracks</span><span class="o">.</span><span class="n">manifest_url</span><span class="p">:</span>
</span><span id="__span-0-357"><a id="__codelineno-0-357" name="__codelineno-0-357"></a> <span class="n">all_tracks</span><span class="o">.</span><span class="n">manifest_url</span> <span class="o">=</span> <span class="n">tracks</span><span class="o">.</span><span class="n">manifest_url</span>
</span><span id="__span-0-358"><a id="__codelineno-0-358" name="__codelineno-0-358"></a> <span class="n">first</span> <span class="o">=</span> <span class="kc">False</span>
</span><span id="__span-0-359"><a id="__codelineno-0-359" name="__codelineno-0-359"></a> <span class="k">else</span><span class="p">:</span>
</span><span id="__span-0-360"><a id="__codelineno-0-360" name="__codelineno-0-360"></a> <span class="k">for</span> <span class="n">video</span> <span class="ow">in</span> <span class="n">tracks</span><span class="o">.</span><span class="n">videos</span><span class="p">:</span>
</span><span id="__span-0-361"><a id="__codelineno-0-361" name="__codelineno-0-361"></a> <span class="n">all_tracks</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">video</span><span class="p">,</span> <span class="n">warn_only</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</span><span id="__span-0-362"><a id="__codelineno-0-362" name="__codelineno-0-362"></a>
</span><span id="__span-0-363"><a id="__codelineno-0-363" name="__codelineno-0-363"></a> <span class="k">return</span> <span class="n">all_tracks</span>
</span></code></pre></div></td></tr></table></div>
</details>
</div>
</div>
<div class="doc doc-object doc-function">
<h3 id="unshackle.core.service.Service.get_session" class="doc doc-heading">
<code class="doc-symbol doc-symbol-heading doc-symbol-method"></code> <span class="doc doc-object-name doc-function-name">get_session</span>
<span class="doc doc-labels">
<small class="doc doc-label doc-label-staticmethod"><code>staticmethod</code></small>
</span>
<a href="#unshackle.core.service.Service.get_session" class="headerlink" title="Permanent link">&para;</a></h3>
<div class="language-python doc-signature highlight"><pre><span></span><code><span id="__span-0-1"><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a><span class="nf">get_session</span><span class="p">()</span>
</span></code></pre></div>
<div class="doc doc-contents ">
<p>Creates a Python-requests Session, adds common headers
from config, cookies, retry handler, and a proxy if available.
:returns: Prepared Python-requests Session</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-373">373</a></span>
<span class="normal"><a href="#__codelineno-0-374">374</a></span>
<span class="normal"><a href="#__codelineno-0-375">375</a></span>
<span class="normal"><a href="#__codelineno-0-376">376</a></span>
<span class="normal"><a href="#__codelineno-0-377">377</a></span>
<span class="normal"><a href="#__codelineno-0-378">378</a></span>
<span class="normal"><a href="#__codelineno-0-379">379</a></span>
<span class="normal"><a href="#__codelineno-0-380">380</a></span>
<span class="normal"><a href="#__codelineno-0-381">381</a></span>
<span class="normal"><a href="#__codelineno-0-382">382</a></span>
<span class="normal"><a href="#__codelineno-0-383">383</a></span>
<span class="normal"><a href="#__codelineno-0-384">384</a></span>
<span class="normal"><a href="#__codelineno-0-385">385</a></span>
<span class="normal"><a href="#__codelineno-0-386">386</a></span>
<span class="normal"><a href="#__codelineno-0-387">387</a></span>
<span class="normal"><a href="#__codelineno-0-388">388</a></span>
<span class="normal"><a href="#__codelineno-0-389">389</a></span>
<span class="normal"><a href="#__codelineno-0-390">390</a></span>
<span class="normal"><a href="#__codelineno-0-391">391</a></span>
<span class="normal"><a href="#__codelineno-0-392">392</a></span>
<span class="normal"><a href="#__codelineno-0-393">393</a></span>
<span class="normal"><a href="#__codelineno-0-394">394</a></span>
<span class="normal"><a href="#__codelineno-0-395">395</a></span>
<span class="normal"><a href="#__codelineno-0-396">396</a></span>
<span class="normal"><a href="#__codelineno-0-397">397</a></span>
<span class="normal"><a href="#__codelineno-0-398">398</a></span>
<span class="normal"><a href="#__codelineno-0-399">399</a></span>
<span class="normal"><a href="#__codelineno-0-400">400</a></span>
<span class="normal"><a href="#__codelineno-0-401">401</a></span>
<span class="normal"><a href="#__codelineno-0-402">402</a></span>
<span class="normal"><a href="#__codelineno-0-403">403</a></span>
<span class="normal"><a href="#__codelineno-0-404">404</a></span>
<span class="normal"><a href="#__codelineno-0-405">405</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-373"><a id="__codelineno-0-373" name="__codelineno-0-373"></a><span class="nd">@staticmethod</span>
</span><span id="__span-0-374"><a id="__codelineno-0-374" name="__codelineno-0-374"></a><span class="k">def</span><span class="w"> </span><span class="nf">get_session</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="n">requests</span><span class="o">.</span><span class="n">Session</span><span class="p">:</span>
</span><span id="__span-0-375"><a id="__codelineno-0-375" name="__codelineno-0-375"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
</span><span id="__span-0-376"><a id="__codelineno-0-376" name="__codelineno-0-376"></a><span class="sd"> Creates a Python-requests Session, adds common headers</span>
</span><span id="__span-0-377"><a id="__codelineno-0-377" name="__codelineno-0-377"></a><span class="sd"> from config, cookies, retry handler, and a proxy if available.</span>
</span><span id="__span-0-378"><a id="__codelineno-0-378" name="__codelineno-0-378"></a><span class="sd"> :returns: Prepared Python-requests Session</span>
</span><span id="__span-0-379"><a id="__codelineno-0-379" name="__codelineno-0-379"></a><span class="sd"> &quot;&quot;&quot;</span>
</span><span id="__span-0-380"><a id="__codelineno-0-380" name="__codelineno-0-380"></a> <span class="n">session</span> <span class="o">=</span> <span class="n">TimeoutSession</span><span class="p">()</span>
</span><span id="__span-0-381"><a id="__codelineno-0-381" name="__codelineno-0-381"></a> <span class="n">session</span><span class="o">.</span><span class="n">headers</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">config</span><span class="o">.</span><span class="n">headers</span><span class="p">)</span>
</span><span id="__span-0-382"><a id="__codelineno-0-382" name="__codelineno-0-382"></a> <span class="c1"># Retry / pool policy mirrors RnetSession via the shared constants in session.py:</span>
</span><span id="__span-0-383"><a id="__codelineno-0-383" name="__codelineno-0-383"></a> <span class="c1"># same total, forcelist, backoff cap, allowed_methods (incl. POST, so license</span>
</span><span id="__span-0-384"><a id="__codelineno-0-384" name="__codelineno-0-384"></a> <span class="c1"># requests retry on both paths), and pool size. Accepted divergence: urllib3&#39;s</span>
</span><span id="__span-0-385"><a id="__codelineno-0-385" name="__codelineno-0-385"></a> <span class="c1"># backoff_jitter adds an absolute 0..N seconds whereas rnet jitters ±10% of the</span>
</span><span id="__span-0-386"><a id="__codelineno-0-386" name="__codelineno-0-386"></a> <span class="c1"># backoff, the only intentional difference, not worth hand-rolling a retry loop.</span>
</span><span id="__span-0-387"><a id="__codelineno-0-387" name="__codelineno-0-387"></a> <span class="n">session</span><span class="o">.</span><span class="n">mount</span><span class="p">(</span>
</span><span id="__span-0-388"><a id="__codelineno-0-388" name="__codelineno-0-388"></a> <span class="s2">&quot;https://&quot;</span><span class="p">,</span>
</span><span id="__span-0-389"><a id="__codelineno-0-389" name="__codelineno-0-389"></a> <span class="n">TimeoutHTTPAdapter</span><span class="p">(</span>
</span><span id="__span-0-390"><a id="__codelineno-0-390" name="__codelineno-0-390"></a> <span class="n">max_retries</span><span class="o">=</span><span class="n">Retry</span><span class="p">(</span>
</span><span id="__span-0-391"><a id="__codelineno-0-391" name="__codelineno-0-391"></a> <span class="n">total</span><span class="o">=</span><span class="n">MAX_RETRIES</span><span class="p">,</span>
</span><span id="__span-0-392"><a id="__codelineno-0-392" name="__codelineno-0-392"></a> <span class="n">backoff_factor</span><span class="o">=</span><span class="n">BACKOFF_FACTOR</span><span class="p">,</span>
</span><span id="__span-0-393"><a id="__codelineno-0-393" name="__codelineno-0-393"></a> <span class="n">backoff_max</span><span class="o">=</span><span class="n">MAX_BACKOFF</span><span class="p">,</span>
</span><span id="__span-0-394"><a id="__codelineno-0-394" name="__codelineno-0-394"></a> <span class="n">backoff_jitter</span><span class="o">=</span><span class="mf">0.2</span><span class="p">,</span>
</span><span id="__span-0-395"><a id="__codelineno-0-395" name="__codelineno-0-395"></a> <span class="n">status_forcelist</span><span class="o">=</span><span class="n">STATUS_FORCELIST</span><span class="p">,</span>
</span><span id="__span-0-396"><a id="__codelineno-0-396" name="__codelineno-0-396"></a> <span class="n">allowed_methods</span><span class="o">=</span><span class="n">RETRY_METHODS</span><span class="p">,</span>
</span><span id="__span-0-397"><a id="__codelineno-0-397" name="__codelineno-0-397"></a> <span class="n">respect_retry_after_header</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
</span><span id="__span-0-398"><a id="__codelineno-0-398" name="__codelineno-0-398"></a> <span class="p">),</span>
</span><span id="__span-0-399"><a id="__codelineno-0-399" name="__codelineno-0-399"></a> <span class="n">pool_connections</span><span class="o">=</span><span class="n">POOL_MAX_SIZE</span><span class="p">,</span>
</span><span id="__span-0-400"><a id="__codelineno-0-400" name="__codelineno-0-400"></a> <span class="n">pool_maxsize</span><span class="o">=</span><span class="n">POOL_MAX_SIZE</span><span class="p">,</span>
</span><span id="__span-0-401"><a id="__codelineno-0-401" name="__codelineno-0-401"></a> <span class="n">pool_block</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
</span><span id="__span-0-402"><a id="__codelineno-0-402" name="__codelineno-0-402"></a> <span class="p">),</span>
</span><span id="__span-0-403"><a id="__codelineno-0-403" name="__codelineno-0-403"></a> <span class="p">)</span>
</span><span id="__span-0-404"><a id="__codelineno-0-404" name="__codelineno-0-404"></a> <span class="n">session</span><span class="o">.</span><span class="n">mount</span><span class="p">(</span><span class="s2">&quot;http://&quot;</span><span class="p">,</span> <span class="n">session</span><span class="o">.</span><span class="n">adapters</span><span class="p">[</span><span class="s2">&quot;https://&quot;</span><span class="p">])</span>
</span><span id="__span-0-405"><a id="__codelineno-0-405" name="__codelineno-0-405"></a> <span class="k">return</span> <span class="n">session</span>
</span></code></pre></div></td></tr></table></div>
</details>
</div>
</div>
<div class="doc doc-object doc-function">
<h3 id="unshackle.core.service.Service.authenticate" class="doc doc-heading">
<code class="doc-symbol doc-symbol-heading doc-symbol-method"></code> <span class="doc doc-object-name doc-function-name">authenticate</span>
<a href="#unshackle.core.service.Service.authenticate" class="headerlink" title="Permanent link">&para;</a></h3>
<div class="language-python doc-signature highlight"><pre><span></span><code><span id="__span-0-1"><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a><span class="nf">authenticate</span><span class="p">(</span><span class="n">cookies</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">credential</span><span class="o">=</span><span class="kc">None</span><span class="p">)</span>
</span></code></pre></div>
<div class="doc doc-contents ">
<p>Authenticate the Service with Cookies and/or Credentials (Email/Username and Password).</p>
<p>This is effectively a login() function. Any API calls or object initializations
needing to be made, should be made here. This will be run before any of the
following abstract functions.</p>
<p>You should avoid storing or using the Credential outside this function.
Make any calls you need for any Cookies, Tokens, or such, then use those.</p>
<p>The Cookie jar should also not be stored outside this function. However, you may load
the Cookie jar into the service session.</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-407">407</a></span>
<span class="normal"><a href="#__codelineno-0-408">408</a></span>
<span class="normal"><a href="#__codelineno-0-409">409</a></span>
<span class="normal"><a href="#__codelineno-0-410">410</a></span>
<span class="normal"><a href="#__codelineno-0-411">411</a></span>
<span class="normal"><a href="#__codelineno-0-412">412</a></span>
<span class="normal"><a href="#__codelineno-0-413">413</a></span>
<span class="normal"><a href="#__codelineno-0-414">414</a></span>
<span class="normal"><a href="#__codelineno-0-415">415</a></span>
<span class="normal"><a href="#__codelineno-0-416">416</a></span>
<span class="normal"><a href="#__codelineno-0-417">417</a></span>
<span class="normal"><a href="#__codelineno-0-418">418</a></span>
<span class="normal"><a href="#__codelineno-0-419">419</a></span>
<span class="normal"><a href="#__codelineno-0-420">420</a></span>
<span class="normal"><a href="#__codelineno-0-421">421</a></span>
<span class="normal"><a href="#__codelineno-0-422">422</a></span>
<span class="normal"><a href="#__codelineno-0-423">423</a></span>
<span class="normal"><a href="#__codelineno-0-424">424</a></span>
<span class="normal"><a href="#__codelineno-0-425">425</a></span>
<span class="normal"><a href="#__codelineno-0-426">426</a></span>
<span class="normal"><a href="#__codelineno-0-427">427</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-407"><a id="__codelineno-0-407" name="__codelineno-0-407"></a><span class="k">def</span><span class="w"> </span><span class="nf">authenticate</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">cookies</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">CookieJar</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span> <span class="n">credential</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">Credential</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-408"><a id="__codelineno-0-408" name="__codelineno-0-408"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
</span><span id="__span-0-409"><a id="__codelineno-0-409" name="__codelineno-0-409"></a><span class="sd"> Authenticate the Service with Cookies and/or Credentials (Email/Username and Password).</span>
</span><span id="__span-0-410"><a id="__codelineno-0-410" name="__codelineno-0-410"></a>
</span><span id="__span-0-411"><a id="__codelineno-0-411" name="__codelineno-0-411"></a><span class="sd"> This is effectively a login() function. Any API calls or object initializations</span>
</span><span id="__span-0-412"><a id="__codelineno-0-412" name="__codelineno-0-412"></a><span class="sd"> needing to be made, should be made here. This will be run before any of the</span>
</span><span id="__span-0-413"><a id="__codelineno-0-413" name="__codelineno-0-413"></a><span class="sd"> following abstract functions.</span>
</span><span id="__span-0-414"><a id="__codelineno-0-414" name="__codelineno-0-414"></a>
</span><span id="__span-0-415"><a id="__codelineno-0-415" name="__codelineno-0-415"></a><span class="sd"> You should avoid storing or using the Credential outside this function.</span>
</span><span id="__span-0-416"><a id="__codelineno-0-416" name="__codelineno-0-416"></a><span class="sd"> Make any calls you need for any Cookies, Tokens, or such, then use those.</span>
</span><span id="__span-0-417"><a id="__codelineno-0-417" name="__codelineno-0-417"></a>
</span><span id="__span-0-418"><a id="__codelineno-0-418" name="__codelineno-0-418"></a><span class="sd"> The Cookie jar should also not be stored outside this function. However, you may load</span>
</span><span id="__span-0-419"><a id="__codelineno-0-419" name="__codelineno-0-419"></a><span class="sd"> the Cookie jar into the service session.</span>
</span><span id="__span-0-420"><a id="__codelineno-0-420" name="__codelineno-0-420"></a><span class="sd"> &quot;&quot;&quot;</span>
</span><span id="__span-0-421"><a id="__codelineno-0-421" name="__codelineno-0-421"></a> <span class="k">if</span> <span class="n">cookies</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-422"><a id="__codelineno-0-422" name="__codelineno-0-422"></a> <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">cookies</span><span class="p">,</span> <span class="n">CookieJar</span><span class="p">):</span>
</span><span id="__span-0-423"><a id="__codelineno-0-423" name="__codelineno-0-423"></a> <span class="k">raise</span> <span class="ne">TypeError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Expected cookies to be a </span><span class="si">{</span><span class="n">CookieJar</span><span class="si">}</span><span class="s2">, not </span><span class="si">{</span><span class="n">cookies</span><span class="si">!r}</span><span class="s2">.&quot;</span><span class="p">)</span>
</span><span id="__span-0-424"><a id="__codelineno-0-424" name="__codelineno-0-424"></a> <span class="bp">self</span><span class="o">.</span><span class="n">session</span><span class="o">.</span><span class="n">cookies</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">cookies</span><span class="p">)</span>
</span><span id="__span-0-425"><a id="__codelineno-0-425" name="__codelineno-0-425"></a>
</span><span id="__span-0-426"><a id="__codelineno-0-426" name="__codelineno-0-426"></a> <span class="c1"># Store credential for cache key generation</span>
</span><span id="__span-0-427"><a id="__codelineno-0-427" name="__codelineno-0-427"></a> <span class="bp">self</span><span class="o">.</span><span class="n">credential</span> <span class="o">=</span> <span class="n">credential</span>
</span></code></pre></div></td></tr></table></div>
</details>
</div>
</div>
<div class="doc doc-object doc-function">
<h3 id="unshackle.core.service.Service.request_input" class="doc doc-heading">
<code class="doc-symbol doc-symbol-heading doc-symbol-method"></code> <span class="doc doc-object-name doc-function-name">request_input</span>
<a href="#unshackle.core.service.Service.request_input" class="headerlink" title="Permanent link">&para;</a></h3>
<div class="language-python doc-signature highlight"><pre><span></span><code><span id="__span-0-1"><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a><span class="nf">request_input</span><span class="p">(</span><span class="n">prompt</span><span class="p">)</span>
</span></code></pre></div>
<div class="doc doc-contents ">
<p>Request interactive input from the user.</p>
<p>When running locally (CLI), prompts via the shared rich console so the
prompt renders correctly alongside Live progress / log handlers.
When running in serve mode with an :class:<code>InputBridge</code> attached,
delegates to the bridge which relays the prompt to the remote client.</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-429">429</a></span>
<span class="normal"><a href="#__codelineno-0-430">430</a></span>
<span class="normal"><a href="#__codelineno-0-431">431</a></span>
<span class="normal"><a href="#__codelineno-0-432">432</a></span>
<span class="normal"><a href="#__codelineno-0-433">433</a></span>
<span class="normal"><a href="#__codelineno-0-434">434</a></span>
<span class="normal"><a href="#__codelineno-0-435">435</a></span>
<span class="normal"><a href="#__codelineno-0-436">436</a></span>
<span class="normal"><a href="#__codelineno-0-437">437</a></span>
<span class="normal"><a href="#__codelineno-0-438">438</a></span>
<span class="normal"><a href="#__codelineno-0-439">439</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-429"><a id="__codelineno-0-429" name="__codelineno-0-429"></a><span class="k">def</span><span class="w"> </span><span class="nf">request_input</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">prompt</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span><span id="__span-0-430"><a id="__codelineno-0-430" name="__codelineno-0-430"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Request interactive input from the user.</span>
</span><span id="__span-0-431"><a id="__codelineno-0-431" name="__codelineno-0-431"></a>
</span><span id="__span-0-432"><a id="__codelineno-0-432" name="__codelineno-0-432"></a><span class="sd"> When running locally (CLI), prompts via the shared rich console so the</span>
</span><span id="__span-0-433"><a id="__codelineno-0-433" name="__codelineno-0-433"></a><span class="sd"> prompt renders correctly alongside Live progress / log handlers.</span>
</span><span id="__span-0-434"><a id="__codelineno-0-434" name="__codelineno-0-434"></a><span class="sd"> When running in serve mode with an :class:`InputBridge` attached,</span>
</span><span id="__span-0-435"><a id="__codelineno-0-435" name="__codelineno-0-435"></a><span class="sd"> delegates to the bridge which relays the prompt to the remote client.</span>
</span><span id="__span-0-436"><a id="__codelineno-0-436" name="__codelineno-0-436"></a><span class="sd"> &quot;&quot;&quot;</span>
</span><span id="__span-0-437"><a id="__codelineno-0-437" name="__codelineno-0-437"></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-438"><a id="__codelineno-0-438" name="__codelineno-0-438"></a> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_input_bridge</span><span class="o">.</span><span class="n">request_input</span><span class="p">(</span><span class="n">prompt</span><span class="p">)</span>
</span><span id="__span-0-439"><a id="__codelineno-0-439" name="__codelineno-0-439"></a> <span class="k">return</span> <span class="n">prompt_user</span><span class="p">(</span><span class="n">prompt</span><span class="p">)</span>
</span></code></pre></div></td></tr></table></div>
</details>
</div>
</div>
<div class="doc doc-object doc-function">
<h3 id="unshackle.core.service.Service.search" class="doc doc-heading">
<code class="doc-symbol doc-symbol-heading doc-symbol-method"></code> <span class="doc doc-object-name doc-function-name">search</span>
<a href="#unshackle.core.service.Service.search" class="headerlink" title="Permanent link">&para;</a></h3>
<div class="language-python doc-signature highlight"><pre><span></span><code><span id="__span-0-1"><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a><span class="nf">search</span><span class="p">()</span>
</span></code></pre></div>
<div class="doc doc-contents ">
<p>Search by query for titles from the Service.</p>
<p>The query must be taken as a CLI argument by the Service class.
Ideally just re-use the title ID argument (i.e. self.title).</p>
<p>Search results will be displayed in the order yielded.</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-441">441</a></span>
<span class="normal"><a href="#__codelineno-0-442">442</a></span>
<span class="normal"><a href="#__codelineno-0-443">443</a></span>
<span class="normal"><a href="#__codelineno-0-444">444</a></span>
<span class="normal"><a href="#__codelineno-0-445">445</a></span>
<span class="normal"><a href="#__codelineno-0-446">446</a></span>
<span class="normal"><a href="#__codelineno-0-447">447</a></span>
<span class="normal"><a href="#__codelineno-0-448">448</a></span>
<span class="normal"><a href="#__codelineno-0-449">449</a></span>
<span class="normal"><a href="#__codelineno-0-450">450</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-441"><a id="__codelineno-0-441" name="__codelineno-0-441"></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-442"><a id="__codelineno-0-442" name="__codelineno-0-442"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
</span><span id="__span-0-443"><a id="__codelineno-0-443" name="__codelineno-0-443"></a><span class="sd"> Search by query for titles from the Service.</span>
</span><span id="__span-0-444"><a id="__codelineno-0-444" name="__codelineno-0-444"></a>
</span><span id="__span-0-445"><a id="__codelineno-0-445" name="__codelineno-0-445"></a><span class="sd"> The query must be taken as a CLI argument by the Service class.</span>
</span><span id="__span-0-446"><a id="__codelineno-0-446" name="__codelineno-0-446"></a><span class="sd"> Ideally just re-use the title ID argument (i.e. self.title).</span>
</span><span id="__span-0-447"><a id="__codelineno-0-447" name="__codelineno-0-447"></a>
</span><span id="__span-0-448"><a id="__codelineno-0-448" name="__codelineno-0-448"></a><span class="sd"> Search results will be displayed in the order yielded.</span>
</span><span id="__span-0-449"><a id="__codelineno-0-449" name="__codelineno-0-449"></a><span class="sd"> &quot;&quot;&quot;</span>
</span><span id="__span-0-450"><a id="__codelineno-0-450" name="__codelineno-0-450"></a> <span class="k">raise</span> <span class="ne">NotImplementedError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;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">&quot;</span><span class="p">)</span>
</span></code></pre></div></td></tr></table></div>
</details>
</div>
</div>
<div class="doc doc-object doc-function">
<h3 id="unshackle.core.service.Service.get_widevine_service_certificate" class="doc doc-heading">
<code class="doc-symbol doc-symbol-heading doc-symbol-method"></code> <span class="doc doc-object-name doc-function-name">get_widevine_service_certificate</span>
<a href="#unshackle.core.service.Service.get_widevine_service_certificate" class="headerlink" title="Permanent link">&para;</a></h3>
<div class="language-python doc-signature highlight"><pre><span></span><code><span id="__span-0-1"><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a><span class="nf">get_widevine_service_certificate</span><span class="p">(</span>
</span><span id="__span-0-2"><a id="__codelineno-0-2" name="__codelineno-0-2" href="#__codelineno-0-2"></a> <span class="o">*</span><span class="p">,</span> <span class="n">challenge</span><span class="p">,</span> <span class="n">title</span><span class="p">,</span> <span class="n">track</span>
</span><span id="__span-0-3"><a id="__codelineno-0-3" name="__codelineno-0-3" href="#__codelineno-0-3"></a><span class="p">)</span>
</span></code></pre></div>
<div class="doc doc-contents ">
<p>Get the Widevine Service Certificate used for Privacy Mode.</p>
<p>:param challenge: The service challenge, providing this to a License endpoint should return the
privacy certificate that the service uses.
:param title: The current <code>Title</code> from get_titles that is being executed. This is provided in
case it has data needed to be used, e.g. for a HTTP request.
:param track: The current <code>Track</code> needing decryption. Provided for same reason as <code>title</code>.
:return: The Service Privacy Certificate as Bytes or a Base64 string. Don't Base64 Encode or
Decode the data, return as is to reduce unnecessary computations.</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-452">452</a></span>
<span class="normal"><a href="#__codelineno-0-453">453</a></span>
<span class="normal"><a href="#__codelineno-0-454">454</a></span>
<span class="normal"><a href="#__codelineno-0-455">455</a></span>
<span class="normal"><a href="#__codelineno-0-456">456</a></span>
<span class="normal"><a href="#__codelineno-0-457">457</a></span>
<span class="normal"><a href="#__codelineno-0-458">458</a></span>
<span class="normal"><a href="#__codelineno-0-459">459</a></span>
<span class="normal"><a href="#__codelineno-0-460">460</a></span>
<span class="normal"><a href="#__codelineno-0-461">461</a></span>
<span class="normal"><a href="#__codelineno-0-462">462</a></span>
<span class="normal"><a href="#__codelineno-0-463">463</a></span>
<span class="normal"><a href="#__codelineno-0-464">464</a></span>
<span class="normal"><a href="#__codelineno-0-465">465</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-452"><a id="__codelineno-0-452" name="__codelineno-0-452"></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-453"><a id="__codelineno-0-453" name="__codelineno-0-453"></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-454"><a id="__codelineno-0-454" name="__codelineno-0-454"></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-455"><a id="__codelineno-0-455" name="__codelineno-0-455"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
</span><span id="__span-0-456"><a id="__codelineno-0-456" name="__codelineno-0-456"></a><span class="sd"> Get the Widevine Service Certificate used for Privacy Mode.</span>
</span><span id="__span-0-457"><a id="__codelineno-0-457" name="__codelineno-0-457"></a>
</span><span id="__span-0-458"><a id="__codelineno-0-458" name="__codelineno-0-458"></a><span class="sd"> :param challenge: The service challenge, providing this to a License endpoint should return the</span>
</span><span id="__span-0-459"><a id="__codelineno-0-459" name="__codelineno-0-459"></a><span class="sd"> privacy certificate that the service uses.</span>
</span><span id="__span-0-460"><a id="__codelineno-0-460" name="__codelineno-0-460"></a><span class="sd"> :param title: The current `Title` from get_titles that is being executed. This is provided in</span>
</span><span id="__span-0-461"><a id="__codelineno-0-461" name="__codelineno-0-461"></a><span class="sd"> case it has data needed to be used, e.g. for a HTTP request.</span>
</span><span id="__span-0-462"><a id="__codelineno-0-462" name="__codelineno-0-462"></a><span class="sd"> :param track: The current `Track` needing decryption. Provided for same reason as `title`.</span>
</span><span id="__span-0-463"><a id="__codelineno-0-463" name="__codelineno-0-463"></a><span class="sd"> :return: The Service Privacy Certificate as Bytes or a Base64 string. Don&#39;t Base64 Encode or</span>
</span><span id="__span-0-464"><a id="__codelineno-0-464" name="__codelineno-0-464"></a><span class="sd"> Decode the data, return as is to reduce unnecessary computations.</span>
</span><span id="__span-0-465"><a id="__codelineno-0-465" name="__codelineno-0-465"></a><span class="sd"> &quot;&quot;&quot;</span>
</span></code></pre></div></td></tr></table></div>
</details>
</div>
</div>
<div class="doc doc-object doc-function">
<h3 id="unshackle.core.service.Service.get_widevine_license" class="doc doc-heading">
<code class="doc-symbol doc-symbol-heading doc-symbol-method"></code> <span class="doc doc-object-name doc-function-name">get_widevine_license</span>
<a href="#unshackle.core.service.Service.get_widevine_license" class="headerlink" title="Permanent link">&para;</a></h3>
<div class="language-python doc-signature highlight"><pre><span></span><code><span id="__span-0-1"><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a><span class="nf">get_widevine_license</span><span class="p">(</span><span class="o">*</span><span class="p">,</span> <span class="n">challenge</span><span class="p">,</span> <span class="n">title</span><span class="p">,</span> <span class="n">track</span><span class="p">)</span>
</span></code></pre></div>
<div class="doc doc-contents ">
<p>Get a Widevine License message by sending a License Request (challenge).</p>
<p>This License message contains the encrypted Content Decryption Keys and will be
read by the Cdm and decrypted.</p>
<p>This is a very important request to get correct. A bad, unexpected, or missing
value in the request can cause your key to be detected and promptly banned,
revoked, disabled, or downgraded.</p>
<p>:param challenge: The license challenge from the Widevine CDM.
:param title: The current <code>Title</code> from get_titles that is being executed. This is provided in
case it has data needed to be used, e.g. for a HTTP request.
:param track: The current <code>Track</code> needing decryption. Provided for same reason as <code>title</code>.
:return: The License response as Bytes or a Base64 string. Don't Base64 Encode or
Decode the data, return as is to reduce unnecessary computations.</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-467">467</a></span>
<span class="normal"><a href="#__codelineno-0-468">468</a></span>
<span class="normal"><a href="#__codelineno-0-469">469</a></span>
<span class="normal"><a href="#__codelineno-0-470">470</a></span>
<span class="normal"><a href="#__codelineno-0-471">471</a></span>
<span class="normal"><a href="#__codelineno-0-472">472</a></span>
<span class="normal"><a href="#__codelineno-0-473">473</a></span>
<span class="normal"><a href="#__codelineno-0-474">474</a></span>
<span class="normal"><a href="#__codelineno-0-475">475</a></span>
<span class="normal"><a href="#__codelineno-0-476">476</a></span>
<span class="normal"><a href="#__codelineno-0-477">477</a></span>
<span class="normal"><a href="#__codelineno-0-478">478</a></span>
<span class="normal"><a href="#__codelineno-0-479">479</a></span>
<span class="normal"><a href="#__codelineno-0-480">480</a></span>
<span class="normal"><a href="#__codelineno-0-481">481</a></span>
<span class="normal"><a href="#__codelineno-0-482">482</a></span>
<span class="normal"><a href="#__codelineno-0-483">483</a></span>
<span class="normal"><a href="#__codelineno-0-484">484</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-467"><a id="__codelineno-0-467" name="__codelineno-0-467"></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-468"><a id="__codelineno-0-468" name="__codelineno-0-468"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
</span><span id="__span-0-469"><a id="__codelineno-0-469" name="__codelineno-0-469"></a><span class="sd"> Get a Widevine License message by sending a License Request (challenge).</span>
</span><span id="__span-0-470"><a id="__codelineno-0-470" name="__codelineno-0-470"></a>
</span><span id="__span-0-471"><a id="__codelineno-0-471" name="__codelineno-0-471"></a><span class="sd"> This License message contains the encrypted Content Decryption Keys and will be</span>
</span><span id="__span-0-472"><a id="__codelineno-0-472" name="__codelineno-0-472"></a><span class="sd"> read by the Cdm and decrypted.</span>
</span><span id="__span-0-473"><a id="__codelineno-0-473" name="__codelineno-0-473"></a>
</span><span id="__span-0-474"><a id="__codelineno-0-474" name="__codelineno-0-474"></a><span class="sd"> This is a very important request to get correct. A bad, unexpected, or missing</span>
</span><span id="__span-0-475"><a id="__codelineno-0-475" name="__codelineno-0-475"></a><span class="sd"> value in the request can cause your key to be detected and promptly banned,</span>
</span><span id="__span-0-476"><a id="__codelineno-0-476" name="__codelineno-0-476"></a><span class="sd"> revoked, disabled, or downgraded.</span>
</span><span id="__span-0-477"><a id="__codelineno-0-477" name="__codelineno-0-477"></a>
</span><span id="__span-0-478"><a id="__codelineno-0-478" name="__codelineno-0-478"></a><span class="sd"> :param challenge: The license challenge from the Widevine CDM.</span>
</span><span id="__span-0-479"><a id="__codelineno-0-479" name="__codelineno-0-479"></a><span class="sd"> :param title: The current `Title` from get_titles that is being executed. This is provided in</span>
</span><span id="__span-0-480"><a id="__codelineno-0-480" name="__codelineno-0-480"></a><span class="sd"> case it has data needed to be used, e.g. for a HTTP request.</span>
</span><span id="__span-0-481"><a id="__codelineno-0-481" name="__codelineno-0-481"></a><span class="sd"> :param track: The current `Track` needing decryption. Provided for same reason as `title`.</span>
</span><span id="__span-0-482"><a id="__codelineno-0-482" name="__codelineno-0-482"></a><span class="sd"> :return: The License response as Bytes or a Base64 string. Don&#39;t Base64 Encode or</span>
</span><span id="__span-0-483"><a id="__codelineno-0-483" name="__codelineno-0-483"></a><span class="sd"> Decode the data, return as is to reduce unnecessary computations.</span>
</span><span id="__span-0-484"><a id="__codelineno-0-484" name="__codelineno-0-484"></a><span class="sd"> &quot;&quot;&quot;</span>
</span></code></pre></div></td></tr></table></div>
</details>
</div>
</div>
<div class="doc doc-object doc-function">
<h3 id="unshackle.core.service.Service.get_playready_license" class="doc doc-heading">
<code class="doc-symbol doc-symbol-heading doc-symbol-method"></code> <span class="doc doc-object-name doc-function-name">get_playready_license</span>
<a href="#unshackle.core.service.Service.get_playready_license" class="headerlink" title="Permanent link">&para;</a></h3>
<div class="language-python doc-signature highlight"><pre><span></span><code><span id="__span-0-1"><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a><span class="nf">get_playready_license</span><span class="p">(</span><span class="o">*</span><span class="p">,</span> <span class="n">challenge</span><span class="p">,</span> <span class="n">title</span><span class="p">,</span> <span class="n">track</span><span class="p">)</span>
</span></code></pre></div>
<div class="doc doc-contents ">
<p>Get a PlayReady License message by sending a License Request (challenge).</p>
<p>This License message contains the encrypted Content Decryption Keys and will be
read by the CDM and decrypted.</p>
<p>This is a very important request to get correct. A bad, unexpected, or missing
value in the request can cause your key to be detected and promptly banned,
revoked, disabled, or downgraded.</p>
<p>:param challenge: The license challenge from the PlayReady CDM.
:param title: The current <code>Title</code> from get_titles that is being executed. This is provided in
case it has data needed to be used, e.g. for a HTTP request.
:param track: The current <code>Track</code> needing decryption. Provided for same reason as <code>title</code>.
:return: The License response as Bytes or a Base64 string. Don't Base64 Encode or
Decode the data, return as is to reduce unnecessary computations.</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-486">486</a></span>
<span class="normal"><a href="#__codelineno-0-487">487</a></span>
<span class="normal"><a href="#__codelineno-0-488">488</a></span>
<span class="normal"><a href="#__codelineno-0-489">489</a></span>
<span class="normal"><a href="#__codelineno-0-490">490</a></span>
<span class="normal"><a href="#__codelineno-0-491">491</a></span>
<span class="normal"><a href="#__codelineno-0-492">492</a></span>
<span class="normal"><a href="#__codelineno-0-493">493</a></span>
<span class="normal"><a href="#__codelineno-0-494">494</a></span>
<span class="normal"><a href="#__codelineno-0-495">495</a></span>
<span class="normal"><a href="#__codelineno-0-496">496</a></span>
<span class="normal"><a href="#__codelineno-0-497">497</a></span>
<span class="normal"><a href="#__codelineno-0-498">498</a></span>
<span class="normal"><a href="#__codelineno-0-499">499</a></span>
<span class="normal"><a href="#__codelineno-0-500">500</a></span>
<span class="normal"><a href="#__codelineno-0-501">501</a></span>
<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>
<span class="normal"><a href="#__codelineno-0-506">506</a></span>
<span class="normal"><a href="#__codelineno-0-507">507</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">get_playready_license</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="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-488"><a id="__codelineno-0-488" name="__codelineno-0-488"></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-489"><a id="__codelineno-0-489" name="__codelineno-0-489"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
</span><span id="__span-0-490"><a id="__codelineno-0-490" name="__codelineno-0-490"></a><span class="sd"> Get a PlayReady License message by sending a License Request (challenge).</span>
</span><span id="__span-0-491"><a id="__codelineno-0-491" name="__codelineno-0-491"></a>
</span><span id="__span-0-492"><a id="__codelineno-0-492" name="__codelineno-0-492"></a><span class="sd"> This License message contains the encrypted Content Decryption Keys and will be</span>
</span><span id="__span-0-493"><a id="__codelineno-0-493" name="__codelineno-0-493"></a><span class="sd"> read by the CDM and decrypted.</span>
</span><span id="__span-0-494"><a id="__codelineno-0-494" name="__codelineno-0-494"></a>
</span><span id="__span-0-495"><a id="__codelineno-0-495" name="__codelineno-0-495"></a><span class="sd"> This is a very important request to get correct. A bad, unexpected, or missing</span>
</span><span id="__span-0-496"><a id="__codelineno-0-496" name="__codelineno-0-496"></a><span class="sd"> value in the request can cause your key to be detected and promptly banned,</span>
</span><span id="__span-0-497"><a id="__codelineno-0-497" name="__codelineno-0-497"></a><span class="sd"> revoked, disabled, or downgraded.</span>
</span><span id="__span-0-498"><a id="__codelineno-0-498" name="__codelineno-0-498"></a>
</span><span id="__span-0-499"><a id="__codelineno-0-499" name="__codelineno-0-499"></a><span class="sd"> :param challenge: The license challenge from the PlayReady CDM.</span>
</span><span id="__span-0-500"><a id="__codelineno-0-500" name="__codelineno-0-500"></a><span class="sd"> :param title: The current `Title` from get_titles that is being executed. This is provided in</span>
</span><span id="__span-0-501"><a id="__codelineno-0-501" name="__codelineno-0-501"></a><span class="sd"> case it has data needed to be used, e.g. for a HTTP request.</span>
</span><span id="__span-0-502"><a id="__codelineno-0-502" name="__codelineno-0-502"></a><span class="sd"> :param track: The current `Track` needing decryption. Provided for same reason as `title`.</span>
</span><span id="__span-0-503"><a id="__codelineno-0-503" name="__codelineno-0-503"></a><span class="sd"> :return: The License response as Bytes or a Base64 string. Don&#39;t Base64 Encode or</span>
</span><span id="__span-0-504"><a id="__codelineno-0-504" name="__codelineno-0-504"></a><span class="sd"> Decode the data, return as is to reduce unnecessary computations.</span>
</span><span id="__span-0-505"><a id="__codelineno-0-505" name="__codelineno-0-505"></a><span class="sd"> &quot;&quot;&quot;</span>
</span><span id="__span-0-506"><a id="__codelineno-0-506" name="__codelineno-0-506"></a> <span class="c1"># Delegates license handling to the Widevine license method by default if a service-specific PlayReady implementation is not provided.</span>
</span><span id="__span-0-507"><a id="__codelineno-0-507" name="__codelineno-0-507"></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 class="n">challenge</span><span class="o">=</span><span class="n">challenge</span><span class="p">,</span> <span class="n">title</span><span class="o">=</span><span class="n">title</span><span class="p">,</span> <span class="n">track</span><span class="o">=</span><span class="n">track</span><span class="p">)</span>
</span></code></pre></div></td></tr></table></div>
</details>
</div>
</div>
<div class="doc doc-object doc-function">
<h3 id="unshackle.core.service.Service.get_clearkey_license" class="doc doc-heading">
<code class="doc-symbol doc-symbol-heading doc-symbol-method"></code> <span class="doc doc-object-name doc-function-name">get_clearkey_license</span>
<a href="#unshackle.core.service.Service.get_clearkey_license" class="headerlink" title="Permanent link">&para;</a></h3>
<div class="language-python doc-signature highlight"><pre><span></span><code><span id="__span-0-1"><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a><span class="nf">get_clearkey_license</span><span class="p">(</span><span class="o">*</span><span class="p">,</span> <span class="n">challenge</span><span class="p">,</span> <span class="n">title</span><span class="p">,</span> <span class="n">track</span><span class="p">)</span>
</span></code></pre></div>
<div class="doc doc-contents ">
<p>Get a W3C ClearKey License (JWK Set) by sending a License Request (challenge).</p>
<p>Used for DASH <code>org.w3.clearkey</code> content. No CDM is involved: the challenge is
the W3C EME JSON license request, e.g. <code>{"kids": ["&lt;base64url&gt;"], "type": "temporary"}</code>,
and the license is a JWK Set, e.g. <code>{"keys": [{"kty": "oct", "k": "...", "kid": "..."}]}</code>.</p>
<p>:param challenge: The JSON license request bytes to POST to the license server.
:param title: The current <code>Title</code> from get_titles that is being executed. This is provided in
case it has data needed to be used, e.g. for a HTTP request.
:param track: The current <code>Track</code> needing decryption. Provided for same reason as <code>title</code>.
:return: The JWK Set license as a dict, JSON str, or raw bytes. Return None (the default)
to let the framework POST the challenge to the manifest-provided Laurl, if any.
Services with no license server can instead pre-populate the DRM object's
<code>content_keys</code> in get_tracks.</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-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>
<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>
<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>
<span class="normal"><a href="#__codelineno-0-522">522</a></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>
<span class="normal"><a href="#__codelineno-0-527">527</a></span>
<span class="normal"><a href="#__codelineno-0-528">528</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-509"><a id="__codelineno-0-509" name="__codelineno-0-509"></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-510"><a id="__codelineno-0-510" name="__codelineno-0-510"></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-511"><a id="__codelineno-0-511" name="__codelineno-0-511"></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-512"><a id="__codelineno-0-512" name="__codelineno-0-512"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
</span><span id="__span-0-513"><a id="__codelineno-0-513" name="__codelineno-0-513"></a><span class="sd"> Get a W3C ClearKey License (JWK Set) by sending a License Request (challenge).</span>
</span><span id="__span-0-514"><a id="__codelineno-0-514" name="__codelineno-0-514"></a>
</span><span id="__span-0-515"><a id="__codelineno-0-515" name="__codelineno-0-515"></a><span class="sd"> Used for DASH `org.w3.clearkey` content. No CDM is involved: the challenge is</span>
</span><span id="__span-0-516"><a id="__codelineno-0-516" name="__codelineno-0-516"></a><span class="sd"> the W3C EME JSON license request, e.g. ``{&quot;kids&quot;: [&quot;&lt;base64url&gt;&quot;], &quot;type&quot;: &quot;temporary&quot;}``,</span>
</span><span id="__span-0-517"><a id="__codelineno-0-517" name="__codelineno-0-517"></a><span class="sd"> and the license is a JWK Set, e.g. ``{&quot;keys&quot;: [{&quot;kty&quot;: &quot;oct&quot;, &quot;k&quot;: &quot;...&quot;, &quot;kid&quot;: &quot;...&quot;}]}``.</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"> :param challenge: The JSON license request bytes to POST to the license server.</span>
</span><span id="__span-0-520"><a id="__codelineno-0-520" name="__codelineno-0-520"></a><span class="sd"> :param title: The current `Title` from get_titles that is being executed. This is provided in</span>
</span><span id="__span-0-521"><a id="__codelineno-0-521" name="__codelineno-0-521"></a><span class="sd"> case it has data needed to be used, e.g. for a HTTP request.</span>
</span><span id="__span-0-522"><a id="__codelineno-0-522" name="__codelineno-0-522"></a><span class="sd"> :param track: The current `Track` needing decryption. Provided for same reason as `title`.</span>
</span><span id="__span-0-523"><a id="__codelineno-0-523" name="__codelineno-0-523"></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-524"><a id="__codelineno-0-524" name="__codelineno-0-524"></a><span class="sd"> to let the framework POST the challenge to the manifest-provided Laurl, if any.</span>
</span><span id="__span-0-525"><a id="__codelineno-0-525" name="__codelineno-0-525"></a><span class="sd"> Services with no license server can instead pre-populate the DRM object&#39;s</span>
</span><span id="__span-0-526"><a id="__codelineno-0-526" name="__codelineno-0-526"></a><span class="sd"> `content_keys` in get_tracks.</span>
</span><span id="__span-0-527"><a id="__codelineno-0-527" name="__codelineno-0-527"></a><span class="sd"> &quot;&quot;&quot;</span>
</span><span id="__span-0-528"><a id="__codelineno-0-528" name="__codelineno-0-528"></a> <span class="k">return</span> <span class="kc">None</span>
</span></code></pre></div></td></tr></table></div>
</details>
</div>
</div>
<div class="doc doc-object doc-function">
<h3 id="unshackle.core.service.Service.get_titles" class="doc doc-heading">
<code class="doc-symbol doc-symbol-heading doc-symbol-method"></code> <span class="doc doc-object-name doc-function-name">get_titles</span>
<span class="doc doc-labels">
<small class="doc doc-label doc-label-abstractmethod"><code>abstractmethod</code></small>
</span>
<a href="#unshackle.core.service.Service.get_titles" class="headerlink" title="Permanent link">&para;</a></h3>
<div class="language-python doc-signature highlight"><pre><span></span><code><span id="__span-0-1"><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a><span class="nf">get_titles</span><span class="p">()</span>
</span></code></pre></div>
<div class="doc doc-contents ">
<p>Get Titles for the provided title ID.</p>
<p>Return a Movies, Series, or Album objects containing Movie, Episode, or Song title objects respectively.
The returned data must be for the given title ID, or a spawn of the title ID.</p>
<p>At least one object is expected to be returned, or it will presume an invalid Title ID was
provided.</p>
<p>You can use the <code>data</code> dictionary class instance attribute of each Title to store data you may need later on.
This can be useful to store information on each title that will be required like any sub-asset IDs, or such.</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-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>
<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>
<span class="normal"><a href="#__codelineno-0-542">542</a></span>
<span class="normal"><a href="#__codelineno-0-543">543</a></span>
<span class="normal"><a href="#__codelineno-0-544">544</a></span>
<span class="normal"><a href="#__codelineno-0-545">545</a></span>
<span class="normal"><a href="#__codelineno-0-546">546</a></span>
<span class="normal"><a href="#__codelineno-0-547">547</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-534"><a id="__codelineno-0-534" name="__codelineno-0-534"></a><span class="nd">@abstractmethod</span>
</span><span id="__span-0-535"><a id="__codelineno-0-535" name="__codelineno-0-535"></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-536"><a id="__codelineno-0-536" name="__codelineno-0-536"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
</span><span id="__span-0-537"><a id="__codelineno-0-537" name="__codelineno-0-537"></a><span class="sd"> Get Titles for the provided title ID.</span>
</span><span id="__span-0-538"><a id="__codelineno-0-538" name="__codelineno-0-538"></a>
</span><span id="__span-0-539"><a id="__codelineno-0-539" name="__codelineno-0-539"></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-540"><a id="__codelineno-0-540" name="__codelineno-0-540"></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-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"> At least one object is expected to be returned, or it will presume an invalid Title ID was</span>
</span><span id="__span-0-543"><a id="__codelineno-0-543" name="__codelineno-0-543"></a><span class="sd"> provided.</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"> 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-546"><a id="__codelineno-0-546" name="__codelineno-0-546"></a><span class="sd"> This can be useful to store information on each title that will be required like any sub-asset IDs, or such.</span>
</span><span id="__span-0-547"><a id="__codelineno-0-547" name="__codelineno-0-547"></a><span class="sd"> &quot;&quot;&quot;</span>
</span></code></pre></div></td></tr></table></div>
</details>
</div>
</div>
<div class="doc doc-object doc-function">
<h3 id="unshackle.core.service.Service.get_titles_cached" class="doc doc-heading">
<code class="doc-symbol doc-symbol-heading doc-symbol-method"></code> <span class="doc doc-object-name doc-function-name">get_titles_cached</span>
<a href="#unshackle.core.service.Service.get_titles_cached" class="headerlink" title="Permanent link">&para;</a></h3>
<div class="language-python doc-signature highlight"><pre><span></span><code><span id="__span-0-1"><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a><span class="nf">get_titles_cached</span><span class="p">(</span><span class="n">title_id</span><span class="o">=</span><span class="kc">None</span><span class="p">)</span>
</span></code></pre></div>
<div class="doc doc-contents ">
<p>Cached wrapper around get_titles() to reduce redundant API calls.</p>
<p>This method checks the cache before calling get_titles() and handles
fallback to cached data when API calls fail.</p>
<p><span class="doc-section-title">Parameters:</span></p>
<table>
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Description</th>
<th>Default</th>
</tr>
</thead>
<tbody>
<tr class="doc-section-item">
<td>
<code>title_id</code>
</td>
<td>
<code><span title="str">str</span></code>
</td>
<td>
<div class="doc-md-description">
<p>Optional title ID for cache key generation.
If not provided, will try to extract from service instance.</p>
</div>
</td>
<td>
<code>None</code>
</td>
</tr>
</tbody>
</table>
<p><span class="doc-section-title">Returns:</span></p>
<table>
<thead>
<tr>
<th>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr class="doc-section-item">
<td>
<code><span title="unshackle.core.titles.Titles_T">Titles_T</span></code>
</td>
<td>
<div class="doc-md-description">
<p>Titles object (Movies, Series, or Album)</p>
</div>
</td>
</tr>
</tbody>
</table>
<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-549">549</a></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>
<span class="normal"><a href="#__codelineno-0-556">556</a></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>
<span class="normal"><a href="#__codelineno-0-561">561</a></span>
<span class="normal"><a href="#__codelineno-0-562">562</a></span>
<span class="normal"><a href="#__codelineno-0-563">563</a></span>
<span class="normal"><a href="#__codelineno-0-564">564</a></span>
<span class="normal"><a href="#__codelineno-0-565">565</a></span>
<span class="normal"><a href="#__codelineno-0-566">566</a></span>
<span class="normal"><a href="#__codelineno-0-567">567</a></span>
<span class="normal"><a href="#__codelineno-0-568">568</a></span>
<span class="normal"><a href="#__codelineno-0-569">569</a></span>
<span class="normal"><a href="#__codelineno-0-570">570</a></span>
<span class="normal"><a href="#__codelineno-0-571">571</a></span>
<span class="normal"><a href="#__codelineno-0-572">572</a></span>
<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>
<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>
<span class="normal"><a href="#__codelineno-0-582">582</a></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>
<span class="normal"><a href="#__codelineno-0-587">587</a></span>
<span class="normal"><a href="#__codelineno-0-588">588</a></span>
<span class="normal"><a href="#__codelineno-0-589">589</a></span>
<span class="normal"><a href="#__codelineno-0-590">590</a></span>
<span class="normal"><a href="#__codelineno-0-591">591</a></span>
<span class="normal"><a href="#__codelineno-0-592">592</a></span>
<span class="normal"><a href="#__codelineno-0-593">593</a></span>
<span class="normal"><a href="#__codelineno-0-594">594</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-549"><a id="__codelineno-0-549" name="__codelineno-0-549"></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-550"><a id="__codelineno-0-550" name="__codelineno-0-550"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
</span><span id="__span-0-551"><a id="__codelineno-0-551" name="__codelineno-0-551"></a><span class="sd"> Cached wrapper around get_titles() to reduce redundant API calls.</span>
</span><span id="__span-0-552"><a id="__codelineno-0-552" name="__codelineno-0-552"></a>
</span><span id="__span-0-553"><a id="__codelineno-0-553" name="__codelineno-0-553"></a><span class="sd"> This method checks the cache before calling get_titles() and handles</span>
</span><span id="__span-0-554"><a id="__codelineno-0-554" name="__codelineno-0-554"></a><span class="sd"> fallback to cached data when API calls fail.</span>
</span><span id="__span-0-555"><a id="__codelineno-0-555" name="__codelineno-0-555"></a>
</span><span id="__span-0-556"><a id="__codelineno-0-556" name="__codelineno-0-556"></a><span class="sd"> Args:</span>
</span><span id="__span-0-557"><a id="__codelineno-0-557" name="__codelineno-0-557"></a><span class="sd"> title_id: Optional title ID for cache key generation.</span>
</span><span id="__span-0-558"><a id="__codelineno-0-558" name="__codelineno-0-558"></a><span class="sd"> If not provided, will try to extract from service instance.</span>
</span><span id="__span-0-559"><a id="__codelineno-0-559" name="__codelineno-0-559"></a>
</span><span id="__span-0-560"><a id="__codelineno-0-560" name="__codelineno-0-560"></a><span class="sd"> Returns:</span>
</span><span id="__span-0-561"><a id="__codelineno-0-561" name="__codelineno-0-561"></a><span class="sd"> Titles object (Movies, Series, or Album)</span>
</span><span id="__span-0-562"><a id="__codelineno-0-562" name="__codelineno-0-562"></a><span class="sd"> &quot;&quot;&quot;</span>
</span><span id="__span-0-563"><a id="__codelineno-0-563" name="__codelineno-0-563"></a> <span class="c1"># Try to get title_id from service instance if not provided</span>
</span><span id="__span-0-564"><a id="__codelineno-0-564" name="__codelineno-0-564"></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-565"><a id="__codelineno-0-565" name="__codelineno-0-565"></a> <span class="c1"># Different services store the title ID in different attributes</span>
</span><span id="__span-0-566"><a id="__codelineno-0-566" name="__codelineno-0-566"></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">&quot;title&quot;</span><span class="p">):</span>
</span><span id="__span-0-567"><a id="__codelineno-0-567" name="__codelineno-0-567"></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-568"><a id="__codelineno-0-568" name="__codelineno-0-568"></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">&quot;title_id&quot;</span><span class="p">):</span>
</span><span id="__span-0-569"><a id="__codelineno-0-569" name="__codelineno-0-569"></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-570"><a id="__codelineno-0-570" name="__codelineno-0-570"></a> <span class="k">else</span><span class="p">:</span>
</span><span id="__span-0-571"><a id="__codelineno-0-571" name="__codelineno-0-571"></a> <span class="c1"># If we can&#39;t determine title_id, just call get_titles directly</span>
</span><span id="__span-0-572"><a id="__codelineno-0-572" name="__codelineno-0-572"></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">&quot;Cannot determine title_id for caching, bypassing cache&quot;</span><span class="p">)</span>
</span><span id="__span-0-573"><a id="__codelineno-0-573" name="__codelineno-0-573"></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-574"><a id="__codelineno-0-574" name="__codelineno-0-574"></a>
</span><span id="__span-0-575"><a id="__codelineno-0-575" name="__codelineno-0-575"></a> <span class="c1"># Get cache control flags from context</span>
</span><span id="__span-0-576"><a id="__codelineno-0-576" name="__codelineno-0-576"></a> <span class="n">no_cache</span> <span class="o">=</span> <span class="kc">False</span>
</span><span id="__span-0-577"><a id="__codelineno-0-577" name="__codelineno-0-577"></a> <span class="n">reset_cache</span> <span class="o">=</span> <span class="kc">False</span>
</span><span id="__span-0-578"><a id="__codelineno-0-578" name="__codelineno-0-578"></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-579"><a id="__codelineno-0-579" name="__codelineno-0-579"></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">&quot;no_cache&quot;</span><span class="p">,</span> <span class="kc">False</span><span class="p">)</span>
</span><span id="__span-0-580"><a id="__codelineno-0-580" name="__codelineno-0-580"></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">&quot;reset_cache&quot;</span><span class="p">,</span> <span class="kc">False</span><span class="p">)</span>
</span><span id="__span-0-581"><a id="__codelineno-0-581" name="__codelineno-0-581"></a>
</span><span id="__span-0-582"><a id="__codelineno-0-582" name="__codelineno-0-582"></a> <span class="c1"># Get account hash for cache key</span>
</span><span id="__span-0-583"><a id="__codelineno-0-583" name="__codelineno-0-583"></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-584"><a id="__codelineno-0-584" name="__codelineno-0-584"></a>
</span><span id="__span-0-585"><a id="__codelineno-0-585" name="__codelineno-0-585"></a> <span class="c1"># Use title cache to get titles with fallback support</span>
</span><span id="__span-0-586"><a id="__codelineno-0-586" name="__codelineno-0-586"></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-587"><a id="__codelineno-0-587" name="__codelineno-0-587"></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-588"><a id="__codelineno-0-588" name="__codelineno-0-588"></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-589"><a id="__codelineno-0-589" name="__codelineno-0-589"></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-590"><a id="__codelineno-0-590" name="__codelineno-0-590"></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-591"><a id="__codelineno-0-591" name="__codelineno-0-591"></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-592"><a id="__codelineno-0-592" name="__codelineno-0-592"></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-593"><a id="__codelineno-0-593" name="__codelineno-0-593"></a> <span class="p">)</span>
</span><span id="__span-0-594"><a id="__codelineno-0-594" name="__codelineno-0-594"></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>
</div>
<div class="doc doc-object doc-function">
<h3 id="unshackle.core.service.Service.apply_title_map" class="doc doc-heading">
<code class="doc-symbol doc-symbol-heading doc-symbol-method"></code> <span class="doc doc-object-name doc-function-name">apply_title_map</span>
<a href="#unshackle.core.service.Service.apply_title_map" class="headerlink" title="Permanent link">&para;</a></h3>
<div class="language-python doc-signature highlight"><pre><span></span><code><span id="__span-0-1"><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a><span class="nf">apply_title_map</span><span class="p">(</span><span class="n">titles</span><span class="p">)</span>
</span></code></pre></div>
<div class="doc doc-contents ">
<p>Rewrite service-provided titles using the per-service <code>title_map</code> config.</p>
<p><code>title_map</code> lives under <code>services.&lt;TAG&gt;</code> in unshackle.yaml. Applied after the
title cache so config edits take effect without a cache reset, and before any
<code>--enrich</code> override so enrich wins. See <code>remap_titles</code> for the match rules.</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-596">596</a></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>
<span class="normal"><a href="#__codelineno-0-603">603</a></span>
<span class="normal"><a href="#__codelineno-0-604">604</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-596"><a id="__codelineno-0-596" name="__codelineno-0-596"></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-597"><a id="__codelineno-0-597" name="__codelineno-0-597"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
</span><span id="__span-0-598"><a id="__codelineno-0-598" name="__codelineno-0-598"></a><span class="sd"> Rewrite service-provided titles using the per-service ``title_map`` config.</span>
</span><span id="__span-0-599"><a id="__codelineno-0-599" name="__codelineno-0-599"></a>
</span><span id="__span-0-600"><a id="__codelineno-0-600" name="__codelineno-0-600"></a><span class="sd"> ``title_map`` lives under ``services.&lt;TAG&gt;`` in unshackle.yaml. Applied after the</span>
</span><span id="__span-0-601"><a id="__codelineno-0-601" name="__codelineno-0-601"></a><span class="sd"> title cache so config edits take effect without a cache reset, and before any</span>
</span><span id="__span-0-602"><a id="__codelineno-0-602" name="__codelineno-0-602"></a><span class="sd"> ``--enrich`` override so enrich wins. See ``remap_titles`` for the match rules.</span>
</span><span id="__span-0-603"><a id="__codelineno-0-603" name="__codelineno-0-603"></a><span class="sd"> &quot;&quot;&quot;</span>
</span><span id="__span-0-604"><a id="__codelineno-0-604" name="__codelineno-0-604"></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">&quot;title_map&quot;</span><span class="p">)</span> <span class="ow">or</span> <span class="p">{})</span>
</span></code></pre></div></td></tr></table></div>
</details>
</div>
</div>
<div class="doc doc-object doc-function">
<h3 id="unshackle.core.service.Service.get_tracks" class="doc doc-heading">
<code class="doc-symbol doc-symbol-heading doc-symbol-method"></code> <span class="doc doc-object-name doc-function-name">get_tracks</span>
<span class="doc doc-labels">
<small class="doc doc-label doc-label-abstractmethod"><code>abstractmethod</code></small>
</span>
<a href="#unshackle.core.service.Service.get_tracks" class="headerlink" title="Permanent link">&para;</a></h3>
<div class="language-python doc-signature highlight"><pre><span></span><code><span id="__span-0-1"><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a><span class="nf">get_tracks</span><span class="p">(</span><span class="n">title</span><span class="p">)</span>
</span></code></pre></div>
<div class="doc doc-contents ">
<p>Get Track objects of the Title.</p>
<p>Return a Tracks object, which itself can contain Video, Audio, Subtitle or even Chapters.
Tracks.videos, Tracks.audio, Tracks.subtitles, and Track.chapters should be a List of Track objects.</p>
<p>Each Track in the Tracks should represent a Video/Audio Stream/Representation/Adaptation or
a Subtitle file.</p>
<p>While one Track should only hold information for one stream/downloadable, try to get as many
unique Track objects per stream type so Stream selection by the root code can give you more
options in terms of Resolution, Bitrate, Codecs, Language, e.t.c.</p>
<p>No decision making or filtering of which Tracks get returned should happen here. It can be
considered an error to filter for e.g. resolution, codec, and such. All filtering based on
arguments will be done by the root code automatically when needed.</p>
<p>Make sure you correctly mark which Tracks are encrypted or not, and by which DRM System
via its <code>drm</code> property.</p>
<p>If you are able to obtain the Track's KID (Key ID) as a 32 char (16 bit) HEX string, provide
it to the Track's <code>kid</code> variable as it will speed up the decryption process later on. It may
or may not be needed, that depends on the service. Generally if you can provide it, without
downloading any of the Track's stream data, then do.</p>
<p>:param title: The current <code>Title</code> from get_titles that is being executed.
:return: Tracks object containing Video, Audio, Subtitles, and Chapters, if available.</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-606">606</a></span>
<span class="normal"><a href="#__codelineno-0-607">607</a></span>
<span class="normal"><a href="#__codelineno-0-608">608</a></span>
<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>
<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>
<span class="normal"><a href="#__codelineno-0-618">618</a></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>
<span class="normal"><a href="#__codelineno-0-623">623</a></span>
<span class="normal"><a href="#__codelineno-0-624">624</a></span>
<span class="normal"><a href="#__codelineno-0-625">625</a></span>
<span class="normal"><a href="#__codelineno-0-626">626</a></span>
<span class="normal"><a href="#__codelineno-0-627">627</a></span>
<span class="normal"><a href="#__codelineno-0-628">628</a></span>
<span class="normal"><a href="#__codelineno-0-629">629</a></span>
<span class="normal"><a href="#__codelineno-0-630">630</a></span>
<span class="normal"><a href="#__codelineno-0-631">631</a></span>
<span class="normal"><a href="#__codelineno-0-632">632</a></span>
<span class="normal"><a href="#__codelineno-0-633">633</a></span>
<span class="normal"><a href="#__codelineno-0-634">634</a></span>
<span class="normal"><a href="#__codelineno-0-635">635</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-606"><a id="__codelineno-0-606" name="__codelineno-0-606"></a><span class="nd">@abstractmethod</span>
</span><span id="__span-0-607"><a id="__codelineno-0-607" name="__codelineno-0-607"></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-608"><a id="__codelineno-0-608" name="__codelineno-0-608"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
</span><span id="__span-0-609"><a id="__codelineno-0-609" name="__codelineno-0-609"></a><span class="sd"> Get Track objects of the Title.</span>
</span><span id="__span-0-610"><a id="__codelineno-0-610" name="__codelineno-0-610"></a>
</span><span id="__span-0-611"><a id="__codelineno-0-611" name="__codelineno-0-611"></a><span class="sd"> Return a Tracks object, which itself can contain Video, Audio, Subtitle or even Chapters.</span>
</span><span id="__span-0-612"><a id="__codelineno-0-612" name="__codelineno-0-612"></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-613"><a id="__codelineno-0-613" name="__codelineno-0-613"></a>
</span><span id="__span-0-614"><a id="__codelineno-0-614" name="__codelineno-0-614"></a><span class="sd"> Each Track in the Tracks should represent a Video/Audio Stream/Representation/Adaptation or</span>
</span><span id="__span-0-615"><a id="__codelineno-0-615" name="__codelineno-0-615"></a><span class="sd"> a Subtitle file.</span>
</span><span id="__span-0-616"><a id="__codelineno-0-616" name="__codelineno-0-616"></a>
</span><span id="__span-0-617"><a id="__codelineno-0-617" name="__codelineno-0-617"></a><span class="sd"> While one Track should only hold information for one stream/downloadable, try to get as many</span>
</span><span id="__span-0-618"><a id="__codelineno-0-618" name="__codelineno-0-618"></a><span class="sd"> unique Track objects per stream type so Stream selection by the root code can give you more</span>
</span><span id="__span-0-619"><a id="__codelineno-0-619" name="__codelineno-0-619"></a><span class="sd"> options in terms of Resolution, Bitrate, Codecs, Language, e.t.c.</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"> No decision making or filtering of which Tracks get returned should happen here. It can be</span>
</span><span id="__span-0-622"><a id="__codelineno-0-622" name="__codelineno-0-622"></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-623"><a id="__codelineno-0-623" name="__codelineno-0-623"></a><span class="sd"> arguments will be done by the root code automatically when needed.</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"> Make sure you correctly mark which Tracks are encrypted or not, and by which DRM System</span>
</span><span id="__span-0-626"><a id="__codelineno-0-626" name="__codelineno-0-626"></a><span class="sd"> via its `drm` property.</span>
</span><span id="__span-0-627"><a id="__codelineno-0-627" name="__codelineno-0-627"></a>
</span><span id="__span-0-628"><a id="__codelineno-0-628" name="__codelineno-0-628"></a><span class="sd"> If you are able to obtain the Track&#39;s KID (Key ID) as a 32 char (16 bit) HEX string, provide</span>
</span><span id="__span-0-629"><a id="__codelineno-0-629" name="__codelineno-0-629"></a><span class="sd"> it to the Track&#39;s `kid` variable as it will speed up the decryption process later on. It may</span>
</span><span id="__span-0-630"><a id="__codelineno-0-630" name="__codelineno-0-630"></a><span class="sd"> or may not be needed, that depends on the service. Generally if you can provide it, without</span>
</span><span id="__span-0-631"><a id="__codelineno-0-631" name="__codelineno-0-631"></a><span class="sd"> downloading any of the Track&#39;s stream data, then do.</span>
</span><span id="__span-0-632"><a id="__codelineno-0-632" name="__codelineno-0-632"></a>
</span><span id="__span-0-633"><a id="__codelineno-0-633" name="__codelineno-0-633"></a><span class="sd"> :param title: The current `Title` from get_titles that is being executed.</span>
</span><span id="__span-0-634"><a id="__codelineno-0-634" name="__codelineno-0-634"></a><span class="sd"> :return: Tracks object containing Video, Audio, Subtitles, and Chapters, if available.</span>
</span><span id="__span-0-635"><a id="__codelineno-0-635" name="__codelineno-0-635"></a><span class="sd"> &quot;&quot;&quot;</span>
</span></code></pre></div></td></tr></table></div>
</details>
</div>
</div>
<div class="doc doc-object doc-function">
<h3 id="unshackle.core.service.Service.get_chapters" class="doc doc-heading">
<code class="doc-symbol doc-symbol-heading doc-symbol-method"></code> <span class="doc doc-object-name doc-function-name">get_chapters</span>
<span class="doc doc-labels">
<small class="doc doc-label doc-label-abstractmethod"><code>abstractmethod</code></small>
</span>
<a href="#unshackle.core.service.Service.get_chapters" class="headerlink" title="Permanent link">&para;</a></h3>
<div class="language-python doc-signature highlight"><pre><span></span><code><span id="__span-0-1"><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a><span class="nf">get_chapters</span><span class="p">(</span><span class="n">title</span><span class="p">)</span>
</span></code></pre></div>
<div class="doc doc-contents ">
<p>Get Chapters for the Title.</p>
<p><span class="doc-section-title">Parameters:</span></p>
<table>
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Description</th>
<th>Default</th>
</tr>
</thead>
<tbody>
<tr class="doc-section-item">
<td>
<code>title</code>
</td>
<td>
<code><span title="unshackle.core.titles.Title_T">Title_T</span></code>
</td>
<td>
<div class="doc-md-description">
<p>The current Title from <code>get_titles</code> that is being processed.</p>
</div>
</td>
<td>
<em>required</em>
</td>
</tr>
</tbody>
</table>
<p>You must return a Chapters object containing 0 or more Chapter objects.</p>
<p>You do not need to set a Chapter number or sort/order the chapters in any way as
the Chapters class automatically handles all of that for you. If there's no
descriptive name for a Chapter then do not set a name at all.</p>
<p>You must not set Chapter names to "Chapter {n}" or such. If you (or the user)
wants "Chapter {n}" style Chapter names (or similar) then they can use the config
option <code>chapter_fallback_name</code>. For example, <code>"Chapter {i:02}"</code> for "Chapter 01".</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-637">637</a></span>
<span class="normal"><a href="#__codelineno-0-638">638</a></span>
<span class="normal"><a href="#__codelineno-0-639">639</a></span>
<span class="normal"><a href="#__codelineno-0-640">640</a></span>
<span class="normal"><a href="#__codelineno-0-641">641</a></span>
<span class="normal"><a href="#__codelineno-0-642">642</a></span>
<span class="normal"><a href="#__codelineno-0-643">643</a></span>
<span class="normal"><a href="#__codelineno-0-644">644</a></span>
<span class="normal"><a href="#__codelineno-0-645">645</a></span>
<span class="normal"><a href="#__codelineno-0-646">646</a></span>
<span class="normal"><a href="#__codelineno-0-647">647</a></span>
<span class="normal"><a href="#__codelineno-0-648">648</a></span>
<span class="normal"><a href="#__codelineno-0-649">649</a></span>
<span class="normal"><a href="#__codelineno-0-650">650</a></span>
<span class="normal"><a href="#__codelineno-0-651">651</a></span>
<span class="normal"><a href="#__codelineno-0-652">652</a></span>
<span class="normal"><a href="#__codelineno-0-653">653</a></span>
<span class="normal"><a href="#__codelineno-0-654">654</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-637"><a id="__codelineno-0-637" name="__codelineno-0-637"></a><span class="nd">@abstractmethod</span>
</span><span id="__span-0-638"><a id="__codelineno-0-638" name="__codelineno-0-638"></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-639"><a id="__codelineno-0-639" name="__codelineno-0-639"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
</span><span id="__span-0-640"><a id="__codelineno-0-640" name="__codelineno-0-640"></a><span class="sd"> Get Chapters for the Title.</span>
</span><span id="__span-0-641"><a id="__codelineno-0-641" name="__codelineno-0-641"></a>
</span><span id="__span-0-642"><a id="__codelineno-0-642" name="__codelineno-0-642"></a><span class="sd"> Parameters:</span>
</span><span id="__span-0-643"><a id="__codelineno-0-643" name="__codelineno-0-643"></a><span class="sd"> title: The current Title from `get_titles` that is being processed.</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="sd"> You must return a Chapters object containing 0 or more Chapter objects.</span>
</span><span id="__span-0-646"><a id="__codelineno-0-646" name="__codelineno-0-646"></a>
</span><span id="__span-0-647"><a id="__codelineno-0-647" name="__codelineno-0-647"></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-648"><a id="__codelineno-0-648" name="__codelineno-0-648"></a><span class="sd"> the Chapters class automatically handles all of that for you. If there&#39;s no</span>
</span><span id="__span-0-649"><a id="__codelineno-0-649" name="__codelineno-0-649"></a><span class="sd"> descriptive name for a Chapter then do not set a name at all.</span>
</span><span id="__span-0-650"><a id="__codelineno-0-650" name="__codelineno-0-650"></a>
</span><span id="__span-0-651"><a id="__codelineno-0-651" name="__codelineno-0-651"></a><span class="sd"> You must not set Chapter names to &quot;Chapter {n}&quot; or such. If you (or the user)</span>
</span><span id="__span-0-652"><a id="__codelineno-0-652" name="__codelineno-0-652"></a><span class="sd"> wants &quot;Chapter {n}&quot; style Chapter names (or similar) then they can use the config</span>
</span><span id="__span-0-653"><a id="__codelineno-0-653" name="__codelineno-0-653"></a><span class="sd"> option `chapter_fallback_name`. For example, `&quot;Chapter {i:02}&quot;` for &quot;Chapter 01&quot;.</span>
</span><span id="__span-0-654"><a id="__codelineno-0-654" name="__codelineno-0-654"></a><span class="sd"> &quot;&quot;&quot;</span>
</span></code></pre></div></td></tr></table></div>
</details>
</div>
</div>
<div class="doc doc-object doc-function">
<h3 id="unshackle.core.service.Service.on_segment_downloaded" class="doc doc-heading">
<code class="doc-symbol doc-symbol-heading doc-symbol-method"></code> <span class="doc doc-object-name doc-function-name">on_segment_downloaded</span>
<a href="#unshackle.core.service.Service.on_segment_downloaded" class="headerlink" title="Permanent link">&para;</a></h3>
<div class="language-python doc-signature highlight"><pre><span></span><code><span id="__span-0-1"><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a><span class="nf">on_segment_downloaded</span><span class="p">(</span><span class="n">track</span><span class="p">,</span> <span class="n">segment</span><span class="p">)</span>
</span></code></pre></div>
<div class="doc doc-contents ">
<p>Called when one of a Track's Segments has finished downloading.</p>
<p><span class="doc-section-title">Parameters:</span></p>
<table>
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Description</th>
<th>Default</th>
</tr>
</thead>
<tbody>
<tr class="doc-section-item">
<td>
<code>track</code>
</td>
<td>
<code><span title="unshackle.core.constants.AnyTrack">AnyTrack</span></code>
</td>
<td>
<div class="doc-md-description">
<p>The Track object that had a Segment downloaded.</p>
</div>
</td>
<td>
<em>required</em>
</td>
</tr>
<tr class="doc-section-item">
<td>
<code>segment</code>
</td>
<td>
<code><span title="pathlib.Path">Path</span></code>
</td>
<td>
<div class="doc-md-description">
<p>The Path to the Segment that was downloaded.</p>
</div>
</td>
<td>
<em>required</em>
</td>
</tr>
</tbody>
</table>
<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>
<span class="normal"><a href="#__codelineno-0-664">664</a></span>
<span class="normal"><a href="#__codelineno-0-665">665</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">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-659"><a id="__codelineno-0-659" name="__codelineno-0-659"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
</span><span id="__span-0-660"><a id="__codelineno-0-660" name="__codelineno-0-660"></a><span class="sd"> Called when one of a Track&#39;s Segments has finished downloading.</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"> Parameters:</span>
</span><span id="__span-0-663"><a id="__codelineno-0-663" name="__codelineno-0-663"></a><span class="sd"> track: The Track object that had a Segment downloaded.</span>
</span><span id="__span-0-664"><a id="__codelineno-0-664" name="__codelineno-0-664"></a><span class="sd"> segment: The Path to the Segment that was downloaded.</span>
</span><span id="__span-0-665"><a id="__codelineno-0-665" name="__codelineno-0-665"></a><span class="sd"> &quot;&quot;&quot;</span>
</span></code></pre></div></td></tr></table></div>
</details>
</div>
</div>
<div class="doc doc-object doc-function">
<h3 id="unshackle.core.service.Service.on_track_downloaded" class="doc doc-heading">
<code class="doc-symbol doc-symbol-heading doc-symbol-method"></code> <span class="doc doc-object-name doc-function-name">on_track_downloaded</span>
<a href="#unshackle.core.service.Service.on_track_downloaded" class="headerlink" title="Permanent link">&para;</a></h3>
<div class="language-python doc-signature highlight"><pre><span></span><code><span id="__span-0-1"><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a><span class="nf">on_track_downloaded</span><span class="p">(</span><span class="n">track</span><span class="p">)</span>
</span></code></pre></div>
<div class="doc doc-contents ">
<p>Called when a Track has finished downloading.</p>
<p><span class="doc-section-title">Parameters:</span></p>
<table>
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Description</th>
<th>Default</th>
</tr>
</thead>
<tbody>
<tr class="doc-section-item">
<td>
<code>track</code>
</td>
<td>
<code><span title="unshackle.core.constants.AnyTrack">AnyTrack</span></code>
</td>
<td>
<div class="doc-md-description">
<p>The Track object that was downloaded.</p>
</div>
</td>
<td>
<em>required</em>
</td>
</tr>
</tbody>
</table>
<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-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>
<span class="normal"><a href="#__codelineno-0-672">672</a></span>
<span class="normal"><a href="#__codelineno-0-673">673</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-667"><a id="__codelineno-0-667" name="__codelineno-0-667"></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-668"><a id="__codelineno-0-668" name="__codelineno-0-668"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
</span><span id="__span-0-669"><a id="__codelineno-0-669" name="__codelineno-0-669"></a><span class="sd"> Called when a Track has finished downloading.</span>
</span><span id="__span-0-670"><a id="__codelineno-0-670" name="__codelineno-0-670"></a>
</span><span id="__span-0-671"><a id="__codelineno-0-671" name="__codelineno-0-671"></a><span class="sd"> Parameters:</span>
</span><span id="__span-0-672"><a id="__codelineno-0-672" name="__codelineno-0-672"></a><span class="sd"> track: The Track object that was downloaded.</span>
</span><span id="__span-0-673"><a id="__codelineno-0-673" name="__codelineno-0-673"></a><span class="sd"> &quot;&quot;&quot;</span>
</span></code></pre></div></td></tr></table></div>
</details>
</div>
</div>
<div class="doc doc-object doc-function">
<h3 id="unshackle.core.service.Service.on_track_decrypted" class="doc doc-heading">
<code class="doc-symbol doc-symbol-heading doc-symbol-method"></code> <span class="doc doc-object-name doc-function-name">on_track_decrypted</span>
<a href="#unshackle.core.service.Service.on_track_decrypted" class="headerlink" title="Permanent link">&para;</a></h3>
<div class="language-python doc-signature highlight"><pre><span></span><code><span id="__span-0-1"><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a><span class="nf">on_track_decrypted</span><span class="p">(</span><span class="n">track</span><span class="p">,</span> <span class="n">drm</span><span class="p">,</span> <span class="n">segment</span><span class="o">=</span><span class="kc">None</span><span class="p">)</span>
</span></code></pre></div>
<div class="doc doc-contents ">
<p>Called when a Track has finished decrypting.</p>
<p><span class="doc-section-title">Parameters:</span></p>
<table>
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Description</th>
<th>Default</th>
</tr>
</thead>
<tbody>
<tr class="doc-section-item">
<td>
<code>track</code>
</td>
<td>
<code><span title="unshackle.core.constants.AnyTrack">AnyTrack</span></code>
</td>
<td>
<div class="doc-md-description">
<p>The Track object that was decrypted.</p>
</div>
</td>
<td>
<em>required</em>
</td>
</tr>
<tr class="doc-section-item">
<td>
<code>drm</code>
</td>
<td>
<code><span title="unshackle.core.drm.DRM_T">DRM_T</span></code>
</td>
<td>
<div class="doc-md-description">
<p>The DRM object it decrypted with.</p>
</div>
</td>
<td>
<em>required</em>
</td>
</tr>
<tr class="doc-section-item">
<td>
<code>segment</code>
</td>
<td>
<code><span title="typing.Optional">Optional</span>[<span title="m3u8.Segment">Segment</span>]</code>
</td>
<td>
<div class="doc-md-description">
<p>The HLS segment information that was decrypted.</p>
</div>
</td>
<td>
<code>None</code>
</td>
</tr>
</tbody>
</table>
<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-675">675</a></span>
<span class="normal"><a href="#__codelineno-0-676">676</a></span>
<span class="normal"><a href="#__codelineno-0-677">677</a></span>
<span class="normal"><a href="#__codelineno-0-678">678</a></span>
<span class="normal"><a href="#__codelineno-0-679">679</a></span>
<span class="normal"><a href="#__codelineno-0-680">680</a></span>
<span class="normal"><a href="#__codelineno-0-681">681</a></span>
<span class="normal"><a href="#__codelineno-0-682">682</a></span>
<span class="normal"><a href="#__codelineno-0-683">683</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-675"><a id="__codelineno-0-675" name="__codelineno-0-675"></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-676"><a id="__codelineno-0-676" name="__codelineno-0-676"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
</span><span id="__span-0-677"><a id="__codelineno-0-677" name="__codelineno-0-677"></a><span class="sd"> Called when a Track has finished decrypting.</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"> Parameters:</span>
</span><span id="__span-0-680"><a id="__codelineno-0-680" name="__codelineno-0-680"></a><span class="sd"> track: The Track object that was decrypted.</span>
</span><span id="__span-0-681"><a id="__codelineno-0-681" name="__codelineno-0-681"></a><span class="sd"> drm: The DRM object it decrypted with.</span>
</span><span id="__span-0-682"><a id="__codelineno-0-682" name="__codelineno-0-682"></a><span class="sd"> segment: The HLS segment information that was decrypted.</span>
</span><span id="__span-0-683"><a id="__codelineno-0-683" name="__codelineno-0-683"></a><span class="sd"> &quot;&quot;&quot;</span>
</span></code></pre></div></td></tr></table></div>
</details>
</div>
</div>
<div class="doc doc-object doc-function">
<h3 id="unshackle.core.service.Service.on_track_repacked" class="doc doc-heading">
<code class="doc-symbol doc-symbol-heading doc-symbol-method"></code> <span class="doc doc-object-name doc-function-name">on_track_repacked</span>
<a href="#unshackle.core.service.Service.on_track_repacked" class="headerlink" title="Permanent link">&para;</a></h3>
<div class="language-python doc-signature highlight"><pre><span></span><code><span id="__span-0-1"><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a><span class="nf">on_track_repacked</span><span class="p">(</span><span class="n">track</span><span class="p">)</span>
</span></code></pre></div>
<div class="doc doc-contents ">
<p>Called when a Track has finished repacking.</p>
<p><span class="doc-section-title">Parameters:</span></p>
<table>
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Description</th>
<th>Default</th>
</tr>
</thead>
<tbody>
<tr class="doc-section-item">
<td>
<code>track</code>
</td>
<td>
<code><span title="unshackle.core.constants.AnyTrack">AnyTrack</span></code>
</td>
<td>
<div class="doc-md-description">
<p>The Track object that was repacked.</p>
</div>
</td>
<td>
<em>required</em>
</td>
</tr>
</tbody>
</table>
<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-685">685</a></span>
<span class="normal"><a href="#__codelineno-0-686">686</a></span>
<span class="normal"><a href="#__codelineno-0-687">687</a></span>
<span class="normal"><a href="#__codelineno-0-688">688</a></span>
<span class="normal"><a href="#__codelineno-0-689">689</a></span>
<span class="normal"><a href="#__codelineno-0-690">690</a></span>
<span class="normal"><a href="#__codelineno-0-691">691</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-685"><a id="__codelineno-0-685" name="__codelineno-0-685"></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-686"><a id="__codelineno-0-686" name="__codelineno-0-686"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
</span><span id="__span-0-687"><a id="__codelineno-0-687" name="__codelineno-0-687"></a><span class="sd"> Called when a Track has finished repacking.</span>
</span><span id="__span-0-688"><a id="__codelineno-0-688" name="__codelineno-0-688"></a>
</span><span id="__span-0-689"><a id="__codelineno-0-689" name="__codelineno-0-689"></a><span class="sd"> Parameters:</span>
</span><span id="__span-0-690"><a id="__codelineno-0-690" name="__codelineno-0-690"></a><span class="sd"> track: The Track object that was repacked.</span>
</span><span id="__span-0-691"><a id="__codelineno-0-691" name="__codelineno-0-691"></a><span class="sd"> &quot;&quot;&quot;</span>
</span></code></pre></div></td></tr></table></div>
</details>
</div>
</div>
<div class="doc doc-object doc-function">
<h3 id="unshackle.core.service.Service.on_track_multiplex" class="doc doc-heading">
<code class="doc-symbol doc-symbol-heading doc-symbol-method"></code> <span class="doc doc-object-name doc-function-name">on_track_multiplex</span>
<a href="#unshackle.core.service.Service.on_track_multiplex" class="headerlink" title="Permanent link">&para;</a></h3>
<div class="language-python doc-signature highlight"><pre><span></span><code><span id="__span-0-1"><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a><span class="nf">on_track_multiplex</span><span class="p">(</span><span class="n">track</span><span class="p">)</span>
</span></code></pre></div>
<div class="doc doc-contents ">
<p>Called when a Track is about to be Multiplexed into a Container.</p>
<p>Note: Right now only MKV containers are multiplexed but in the future
this may also be called when multiplexing to other containers like
MP4 via ffmpeg/mp4box.</p>
<p><span class="doc-section-title">Parameters:</span></p>
<table>
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Description</th>
<th>Default</th>
</tr>
</thead>
<tbody>
<tr class="doc-section-item">
<td>
<code>track</code>
</td>
<td>
<code><span title="unshackle.core.constants.AnyTrack">AnyTrack</span></code>
</td>
<td>
<div class="doc-md-description">
<p>The Track object that was repacked.</p>
</div>
</td>
<td>
<em>required</em>
</td>
</tr>
</tbody>
</table>
<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-693">693</a></span>
<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>
<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>
<span class="normal"><a href="#__codelineno-0-703">703</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-693"><a id="__codelineno-0-693" name="__codelineno-0-693"></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-694"><a id="__codelineno-0-694" name="__codelineno-0-694"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
</span><span id="__span-0-695"><a id="__codelineno-0-695" name="__codelineno-0-695"></a><span class="sd"> Called when a Track is about to be Multiplexed into a Container.</span>
</span><span id="__span-0-696"><a id="__codelineno-0-696" name="__codelineno-0-696"></a>
</span><span id="__span-0-697"><a id="__codelineno-0-697" name="__codelineno-0-697"></a><span class="sd"> Note: Right now only MKV containers are multiplexed but in the future</span>
</span><span id="__span-0-698"><a id="__codelineno-0-698" name="__codelineno-0-698"></a><span class="sd"> this may also be called when multiplexing to other containers like</span>
</span><span id="__span-0-699"><a id="__codelineno-0-699" name="__codelineno-0-699"></a><span class="sd"> MP4 via ffmpeg/mp4box.</span>
</span><span id="__span-0-700"><a id="__codelineno-0-700" name="__codelineno-0-700"></a>
</span><span id="__span-0-701"><a id="__codelineno-0-701" name="__codelineno-0-701"></a><span class="sd"> Parameters:</span>
</span><span id="__span-0-702"><a id="__codelineno-0-702" name="__codelineno-0-702"></a><span class="sd"> track: The Track object that was repacked.</span>
</span><span id="__span-0-703"><a id="__codelineno-0-703" name="__codelineno-0-703"></a><span class="sd"> &quot;&quot;&quot;</span>
</span></code></pre></div></td></tr></table></div>
</details>
</div>
</div>
</div>
</div>
</div>
<div class="doc doc-object doc-function">
<h2 id="unshackle.core.service.sanitize_proxy_for_log" class="doc doc-heading">
<code class="doc-symbol doc-symbol-heading doc-symbol-function"></code> <span class="doc doc-object-name doc-function-name">sanitize_proxy_for_log</span>
<a href="#unshackle.core.service.sanitize_proxy_for_log" class="headerlink" title="Permanent link">&para;</a></h2>
<div class="language-python doc-signature highlight"><pre><span></span><code><span id="__span-0-1"><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a><span class="nf">sanitize_proxy_for_log</span><span class="p">(</span><span class="n">uri</span><span class="p">)</span>
</span></code></pre></div>
<div class="doc doc-contents ">
<p>Sanitize a proxy URI for logs by redacting any embedded userinfo (username/password).</p>
<p><span class="doc-section-title">Examples:</span></p>
<ul>
<li>http://user:pass@host:8080 -&gt; http://REDACTED@host:8080</li>
<li>socks5h://user@host:1080 -&gt; socks5h://REDACTED@host:1080</li>
</ul>
<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-101">101</a></span>
<span class="normal"><a href="#__codelineno-0-102">102</a></span>
<span class="normal"><a href="#__codelineno-0-103">103</a></span>
<span class="normal"><a href="#__codelineno-0-104">104</a></span>
<span class="normal"><a href="#__codelineno-0-105">105</a></span>
<span class="normal"><a href="#__codelineno-0-106">106</a></span>
<span class="normal"><a href="#__codelineno-0-107">107</a></span>
<span class="normal"><a href="#__codelineno-0-108">108</a></span>
<span class="normal"><a href="#__codelineno-0-109">109</a></span>
<span class="normal"><a href="#__codelineno-0-110">110</a></span>
<span class="normal"><a href="#__codelineno-0-111">111</a></span>
<span class="normal"><a href="#__codelineno-0-112">112</a></span>
<span class="normal"><a href="#__codelineno-0-113">113</a></span>
<span class="normal"><a href="#__codelineno-0-114">114</a></span>
<span class="normal"><a href="#__codelineno-0-115">115</a></span>
<span class="normal"><a href="#__codelineno-0-116">116</a></span>
<span class="normal"><a href="#__codelineno-0-117">117</a></span>
<span class="normal"><a href="#__codelineno-0-118">118</a></span>
<span class="normal"><a href="#__codelineno-0-119">119</a></span>
<span class="normal"><a href="#__codelineno-0-120">120</a></span>
<span class="normal"><a href="#__codelineno-0-121">121</a></span>
<span class="normal"><a href="#__codelineno-0-122">122</a></span>
<span class="normal"><a href="#__codelineno-0-123">123</a></span>
<span class="normal"><a href="#__codelineno-0-124">124</a></span>
<span class="normal"><a href="#__codelineno-0-125">125</a></span>
<span class="normal"><a href="#__codelineno-0-126">126</a></span>
<span class="normal"><a href="#__codelineno-0-127">127</a></span>
<span class="normal"><a href="#__codelineno-0-128">128</a></span>
<span class="normal"><a href="#__codelineno-0-129">129</a></span>
<span class="normal"><a href="#__codelineno-0-130">130</a></span>
<span class="normal"><a href="#__codelineno-0-131">131</a></span>
<span class="normal"><a href="#__codelineno-0-132">132</a></span>
<span class="normal"><a href="#__codelineno-0-133">133</a></span>
<span class="normal"><a href="#__codelineno-0-134">134</a></span>
<span class="normal"><a href="#__codelineno-0-135">135</a></span>
<span class="normal"><a href="#__codelineno-0-136">136</a></span>
<span class="normal"><a href="#__codelineno-0-137">137</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-101"><a id="__codelineno-0-101" name="__codelineno-0-101"></a><span class="k">def</span><span class="w"> </span><span class="nf">sanitize_proxy_for_log</span><span class="p">(</span><span class="n">uri</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">]:</span>
</span><span id="__span-0-102"><a id="__codelineno-0-102" name="__codelineno-0-102"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
</span><span id="__span-0-103"><a id="__codelineno-0-103" name="__codelineno-0-103"></a><span class="sd"> Sanitize a proxy URI for logs by redacting any embedded userinfo (username/password).</span>
</span><span id="__span-0-104"><a id="__codelineno-0-104" name="__codelineno-0-104"></a>
</span><span id="__span-0-105"><a id="__codelineno-0-105" name="__codelineno-0-105"></a><span class="sd"> Examples:</span>
</span><span id="__span-0-106"><a id="__codelineno-0-106" name="__codelineno-0-106"></a><span class="sd"> - http://user:pass@host:8080 -&gt; http://REDACTED@host:8080</span>
</span><span id="__span-0-107"><a id="__codelineno-0-107" name="__codelineno-0-107"></a><span class="sd"> - socks5h://user@host:1080 -&gt; socks5h://REDACTED@host:1080</span>
</span><span id="__span-0-108"><a id="__codelineno-0-108" name="__codelineno-0-108"></a><span class="sd"> &quot;&quot;&quot;</span>
</span><span id="__span-0-109"><a id="__codelineno-0-109" name="__codelineno-0-109"></a> <span class="k">if</span> <span class="n">uri</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
</span><span id="__span-0-110"><a id="__codelineno-0-110" name="__codelineno-0-110"></a> <span class="k">return</span> <span class="kc">None</span>
</span><span id="__span-0-111"><a id="__codelineno-0-111" name="__codelineno-0-111"></a> <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">uri</span><span class="p">,</span> <span class="nb">str</span><span class="p">):</span>
</span><span id="__span-0-112"><a id="__codelineno-0-112" name="__codelineno-0-112"></a> <span class="k">return</span> <span class="nb">str</span><span class="p">(</span><span class="n">uri</span><span class="p">)</span>
</span><span id="__span-0-113"><a id="__codelineno-0-113" name="__codelineno-0-113"></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">uri</span><span class="p">:</span>
</span><span id="__span-0-114"><a id="__codelineno-0-114" name="__codelineno-0-114"></a> <span class="k">return</span> <span class="n">uri</span>
</span><span id="__span-0-115"><a id="__codelineno-0-115" name="__codelineno-0-115"></a>
</span><span id="__span-0-116"><a id="__codelineno-0-116" name="__codelineno-0-116"></a> <span class="k">try</span><span class="p">:</span>
</span><span id="__span-0-117"><a id="__codelineno-0-117" name="__codelineno-0-117"></a> <span class="n">parsed</span> <span class="o">=</span> <span class="n">urlparse</span><span class="p">(</span><span class="n">uri</span><span class="p">)</span>
</span><span id="__span-0-118"><a id="__codelineno-0-118" name="__codelineno-0-118"></a>
</span><span id="__span-0-119"><a id="__codelineno-0-119" name="__codelineno-0-119"></a> <span class="c1"># Handle schemeless proxies like &quot;user:pass@host:port&quot;</span>
</span><span id="__span-0-120"><a id="__codelineno-0-120" name="__codelineno-0-120"></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">parsed</span><span class="o">.</span><span class="n">scheme</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">parsed</span><span class="o">.</span><span class="n">netloc</span> <span class="ow">and</span> <span class="s2">&quot;@&quot;</span> <span class="ow">in</span> <span class="n">uri</span> <span class="ow">and</span> <span class="s2">&quot;://&quot;</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">uri</span><span class="p">:</span>
</span><span id="__span-0-121"><a id="__codelineno-0-121" name="__codelineno-0-121"></a> <span class="c1"># Parse as netloc using a dummy scheme, then strip scheme back out.</span>
</span><span id="__span-0-122"><a id="__codelineno-0-122" name="__codelineno-0-122"></a> <span class="n">dummy</span> <span class="o">=</span> <span class="n">urlparse</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;http://</span><span class="si">{</span><span class="n">uri</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
</span><span id="__span-0-123"><a id="__codelineno-0-123" name="__codelineno-0-123"></a> <span class="n">netloc</span> <span class="o">=</span> <span class="n">dummy</span><span class="o">.</span><span class="n">netloc</span>
</span><span id="__span-0-124"><a id="__codelineno-0-124" name="__codelineno-0-124"></a> <span class="k">if</span> <span class="s2">&quot;@&quot;</span> <span class="ow">in</span> <span class="n">netloc</span><span class="p">:</span>
</span><span id="__span-0-125"><a id="__codelineno-0-125" name="__codelineno-0-125"></a> <span class="n">netloc</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;REDACTED@</span><span class="si">{</span><span class="n">netloc</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;@&#39;</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">)[</span><span class="mi">1</span><span class="p">]</span><span class="si">}</span><span class="s2">&quot;</span>
</span><span id="__span-0-126"><a id="__codelineno-0-126" name="__codelineno-0-126"></a> <span class="c1"># urlparse(&quot;http://...&quot;) sets path to &quot;&quot; for typical netloc-only strings; keep it just in case.</span>
</span><span id="__span-0-127"><a id="__codelineno-0-127" name="__codelineno-0-127"></a> <span class="k">return</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">netloc</span><span class="si">}{</span><span class="n">dummy</span><span class="o">.</span><span class="n">path</span><span class="si">}</span><span class="s2">&quot;</span>
</span><span id="__span-0-128"><a id="__codelineno-0-128" name="__codelineno-0-128"></a>
</span><span id="__span-0-129"><a id="__codelineno-0-129" name="__codelineno-0-129"></a> <span class="n">netloc</span> <span class="o">=</span> <span class="n">parsed</span><span class="o">.</span><span class="n">netloc</span>
</span><span id="__span-0-130"><a id="__codelineno-0-130" name="__codelineno-0-130"></a> <span class="k">if</span> <span class="s2">&quot;@&quot;</span> <span class="ow">in</span> <span class="n">netloc</span><span class="p">:</span>
</span><span id="__span-0-131"><a id="__codelineno-0-131" name="__codelineno-0-131"></a> <span class="n">netloc</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;REDACTED@</span><span class="si">{</span><span class="n">netloc</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;@&#39;</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">)[</span><span class="mi">1</span><span class="p">]</span><span class="si">}</span><span class="s2">&quot;</span>
</span><span id="__span-0-132"><a id="__codelineno-0-132" name="__codelineno-0-132"></a>
</span><span id="__span-0-133"><a id="__codelineno-0-133" name="__codelineno-0-133"></a> <span class="k">return</span> <span class="n">urlunparse</span><span class="p">(</span><span class="n">parsed</span><span class="o">.</span><span class="n">_replace</span><span class="p">(</span><span class="n">netloc</span><span class="o">=</span><span class="n">netloc</span><span class="p">))</span>
</span><span id="__span-0-134"><a id="__codelineno-0-134" name="__codelineno-0-134"></a> <span class="k">except</span> <span class="ne">ValueError</span><span class="p">:</span>
</span><span id="__span-0-135"><a id="__codelineno-0-135" name="__codelineno-0-135"></a> <span class="k">if</span> <span class="s2">&quot;@&quot;</span> <span class="ow">in</span> <span class="n">uri</span><span class="p">:</span>
</span><span id="__span-0-136"><a id="__codelineno-0-136" name="__codelineno-0-136"></a> <span class="k">return</span> <span class="sa">f</span><span class="s2">&quot;REDACTED@</span><span class="si">{</span><span class="n">uri</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;@&#39;</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">)[</span><span class="mi">1</span><span class="p">]</span><span class="si">}</span><span class="s2">&quot;</span>
</span><span id="__span-0-137"><a id="__codelineno-0-137" name="__codelineno-0-137"></a> <span class="k">return</span> <span class="n">uri</span>
</span></code></pre></div></td></tr></table></div>
</details>
</div>
</div>
</div>
</div>
</div>
</article>
</div>
<script>var tabs=__md_get("__tabs");if(Array.isArray(tabs))e:for(var set of document.querySelectorAll(".tabbed-set")){var labels=set.querySelector(".tabbed-labels");for(var tab of tabs)for(var label of labels.getElementsByTagName("label"))if(label.innerText.trim()===tab){var input=document.getElementById(label.htmlFor);input.checked=!0;continue e}}</script>
<script>var target=document.getElementById(location.hash.slice(1));target&&target.name&&(target.checked=target.name.startsWith("__tabbed_"))</script>
</div>
<button type="button" class="md-top md-icon" data-md-component="top" hidden>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M13 20h-2V8l-5.5 5.5-1.42-1.42L12 4.16l7.92 7.92-1.42 1.42L13 8z"/></svg>
Back to top
</button>
</main>
<footer class="md-footer">
<nav class="md-footer__inner md-grid" aria-label="Footer" >
<a href="../../../dev/rest-api/errors/" class="md-footer__link md-footer__link--prev" aria-label="Previous: Error Responses">
<div class="md-footer__button md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11z"/></svg>
</div>
<div class="md-footer__title">
<span class="md-footer__direction">
Previous
</span>
<div class="md-ellipsis">
Error Responses
</div>
</div>
</a>
<a href="../config/" class="md-footer__link md-footer__link--next" aria-label="Next: Config">
<div class="md-footer__title">
<span class="md-footer__direction">
Next
</span>
<div class="md-ellipsis">
Config
</div>
</div>
<div class="md-footer__button md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M4 11v2h12l-5.5 5.5 1.42 1.42L19.84 12l-7.92-7.92L10.5 5.5 16 11z"/></svg>
</div>
</a>
</nav>
<div class="md-footer-meta md-typeset">
<div class="md-footer-meta__inner md-grid">
<div class="md-copyright">
Made with
<a href="https://squidfunk.github.io/mkdocs-material/" target="_blank" rel="noopener">
Material for MkDocs
</a>
</div>
</div>
</div>
</footer>
</div>
<div class="md-dialog" data-md-component="dialog">
<div class="md-dialog__inner md-typeset"></div>
</div>
<script id="__config" type="application/json">{"annotate": null, "base": "../../..", "features": ["content.code.annotate", "content.code.copy", "content.tabs.link", "content.tooltips", "navigation.footer", "navigation.indexes", "navigation.sections", "navigation.tabs", "navigation.top", "navigation.tracking", "search.highlight", "search.share", "search.suggest", "toc.follow"], "search": "../../../assets/javascripts/workers/search.2c215733.min.js", "tags": null, "translations": {"clipboard.copied": "Copied to clipboard", "clipboard.copy": "Copy to clipboard", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.placeholder": "Type to start searching", "search.result.term.missing": "Missing", "select.version": "Select version"}, "version": null}</script>
<script src="../../../assets/javascripts/bundle.d7400e89.min.js"></script>
</body>
</html>