Files
unshackle/reference/configuration/services/index.html
T
2026-11-02 03:09:21 +00:00

2619 lines
81 KiB
HTML

<!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/configuration/services/">
<link rel="prev" href="../directories/">
<link rel="next" href="../download/">
<link rel="icon" href="../../../assets/favicon.svg">
<meta name="generator" content="mkdocs-1.6.1, mkdocs-material-9.8.0">
<title>Services & Authentication - unshackle</title>
<link rel="stylesheet" href="../../../assets/stylesheets/main.57a0d79d.min.css">
<link rel="stylesheet" href="../../../assets/stylesheets/palette.fb2fffe2.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">
<link rel="stylesheet" href="../../../assets/extra.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="#services-auth" 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">
Services & Authentication
</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 md-tabs__item--active">
<a href="../" 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">
<a href="../../api/service/" 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--active md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_4" checked>
<div class="md-nav__link md-nav__container">
<a href="../" class="md-nav__link ">
<span class="md-ellipsis">
Configuration
</span>
</a>
<label class="md-nav__link " for="__nav_4" id="__nav_4_label" tabindex="">
<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="true">
<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="../directories/" class="md-nav__link">
<span class="md-ellipsis">
Directories
</span>
</a>
</li>
<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">
Services & Authentication
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<a href="./" class="md-nav__link md-nav__link--active">
<span class="md-ellipsis">
Services & Authentication
</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="#services" class="md-nav__link">
<span class="md-ellipsis">
services
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#credentials" class="md-nav__link">
<span class="md-ellipsis">
credentials
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#firefox_cookies" class="md-nav__link">
<span class="md-ellipsis">
firefox_cookies
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#remote_services" class="md-nav__link">
<span class="md-ellipsis">
remote_services
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#serve" class="md-nav__link">
<span class="md-ellipsis">
serve
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../download/" class="md-nav__link">
<span class="md-ellipsis">
Download & Processing
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../output/" class="md-nav__link">
<span class="md-ellipsis">
Output & Naming
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../drm/" class="md-nav__link">
<span class="md-ellipsis">
DRM & CDM
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../network/" class="md-nav__link">
<span class="md-ellipsis">
Network & Proxy
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../vaults/" class="md-nav__link">
<span class="md-ellipsis">
Key Vaults
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../post-scripts/" class="md-nav__link">
<span class="md-ellipsis">
Post-Scripts
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../misc/" class="md-nav__link">
<span class="md-ellipsis">
Other Settings
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../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/dashboard/" class="md-nav__link">
<span class="md-ellipsis">
Dashboard
</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--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_6" >
<label class="md-nav__link" for="__nav_6" id="__nav_6_label" tabindex="0">
<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="false">
<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">
<a href="../../api/service/" class="md-nav__link">
<span class="md-ellipsis">
Service
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../api/config/" class="md-nav__link">
<span class="md-ellipsis">
Config
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../api/tracks/" class="md-nav__link">
<span class="md-ellipsis">
Tracks
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../api/titles/" class="md-nav__link">
<span class="md-ellipsis">
Titles
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../api/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="#services" class="md-nav__link">
<span class="md-ellipsis">
services
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#credentials" class="md-nav__link">
<span class="md-ellipsis">
credentials
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#firefox_cookies" class="md-nav__link">
<span class="md-ellipsis">
firefox_cookies
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#remote_services" class="md-nav__link">
<span class="md-ellipsis">
remote_services
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#serve" class="md-nav__link">
<span class="md-ellipsis">
serve
</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="services-auth">Services &amp; authentication<a class="headerlink" href="#services-auth" title="Permanent link">&para;</a></h1>
<h2 id="services"><code>services</code><a class="headerlink" href="#services" title="Permanent link">&para;</a></h2>
<ul>
<li><strong>Type:</strong> <code>dict</code> keyed by service tag &nbsp;·&nbsp; <strong>Default:</strong> <code>{}</code></li>
</ul>
<p>Per-service configuration, keyed by the canonical service tag (for example <code>EXAMPLE1</code>, <code>EXAMPLE2</code>,
<code>EXAMPLE3</code>). unshackle reads several well-known sub-keys out of each service's block:</p>
<ul>
<li><strong><code>proxy_map</code></strong>: remaps the region query you passed to <code>-p/--proxy</code> for this service.
A config key is that query, or <code>"provider:query"</code> when the flag also named a proxy provider. The value is
the query asked of the proxy provider instead. It has no effect when you give <code>-p</code> a full proxy URL.</li>
<li><strong><code>title_map</code></strong>: an exact-match rename map applied to fetched titles (source name →
desired name), so a service that names a title differently from your library still matches.</li>
<li><strong><code>dl</code></strong>: per-service download defaults, using the same keys as the global
<a href="../download/#dl"><code>dl</code></a> block. Set <code>remote: true</code> to send the <code>dl</code> and <code>search</code> runs of that
service to a <a href="#remote_services">remote server</a> without <code>--remote</code>. Add <code>server</code> to select one of
several servers. On the command line, <code>--local</code> and <code>--server</code> override these keys. A REST API job ignores both keys.
A REST API job takes the other keys that it accepts as download parameters as its defaults,
above the <code>serve</code> defaults and below the values that the request sends.
See <a href="../../../dev/rest-api/remote-sessions/#making-a-service-remote-by-default">making a service remote by default</a>.</li>
</ul>
<p>Individual services may read any additional keys they define. unshackle hands the merged result
(the service's own <code>config.yaml</code> with this block layered on top) to the service as <code>self.config</code>.</p>
<p>User- or device-specific values (API keys, account IDs, device attributes) belong in this block
rather than in the service's own <code>config.yaml</code>, which holds shared defaults. See
<a href="../../../dev/creating-a-service/">creating a service</a>.</p>
<div class="language-yaml highlight"><pre><span></span><code><span id="__span-0-1"><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a><span class="nt">services</span><span class="p">:</span>
</span><span id="__span-0-2"><a id="__codelineno-0-2" name="__codelineno-0-2" href="#__codelineno-0-2"></a><span class="w"> </span><span class="nt">EXAMPLE1</span><span class="p">:</span>
</span><span id="__span-0-3"><a id="__codelineno-0-3" name="__codelineno-0-3" href="#__codelineno-0-3"></a><span class="w"> </span><span class="nt">proxy_map</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="w"> </span><span class="nt">us</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">us-nyc</span>
</span><span id="__span-0-5"><a id="__codelineno-0-5" name="__codelineno-0-5" href="#__codelineno-0-5"></a><span class="w"> </span><span class="s">"nordvpn:ca"</span><span class="p p-Indicator">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">ca-toronto</span>
</span><span id="__span-0-6"><a id="__codelineno-0-6" name="__codelineno-0-6" href="#__codelineno-0-6"></a><span class="w"> </span><span class="nt">title_map</span><span class="p">:</span>
</span><span id="__span-0-7"><a id="__codelineno-0-7" name="__codelineno-0-7" href="#__codelineno-0-7"></a><span class="w"> </span><span class="s">"My</span><span class="nv"> </span><span class="s">Show:</span><span class="nv"> </span><span class="s">The</span><span class="nv"> </span><span class="s">Movie"</span><span class="p p-Indicator">:</span><span class="w"> </span><span class="s">"My</span><span class="nv"> </span><span class="s">Show</span><span class="nv"> </span><span class="s">Presents</span><span class="nv"> </span><span class="s">The</span><span class="nv"> </span><span class="s">Movie"</span>
</span></code></pre></div>
<h2 id="credentials"><code>credentials</code><a class="headerlink" href="#credentials" title="Permanent link">&para;</a></h2>
<ul>
<li><strong>Type:</strong> <code>dict</code> keyed by service tag &nbsp;·&nbsp; <strong>Default:</strong> <code>{}</code></li>
</ul>
<p>Per-service login credentials. Each value is a <code>username:password[:extra]</code> string, the same
data as a <code>[username, password]</code> (or <code>[username, password, extra]</code>) list, or a dict of profile
name to either of those. With the dict form, <code>-p/--profile</code> selects the entry, and unshackle
uses the <code>default</code> config key when you give no profile, or when the named profile is missing.
unshackle parses these into <code>Credential</code> objects. It also uses the credential's SHA-1 as an
account hash for cache keys.</p>
<div class="language-yaml highlight"><pre><span></span><code><span id="__span-1-1"><a id="__codelineno-1-1" name="__codelineno-1-1" href="#__codelineno-1-1"></a><span class="nt">credentials</span><span class="p">:</span>
</span><span id="__span-1-2"><a id="__codelineno-1-2" name="__codelineno-1-2" href="#__codelineno-1-2"></a><span class="w"> </span><span class="nt">EXAMPLE2</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">user@example.com:hunter2</span>
</span><span id="__span-1-3"><a id="__codelineno-1-3" name="__codelineno-1-3" href="#__codelineno-1-3"></a><span class="w"> </span><span class="nt">EXAMPLE1</span><span class="p">:</span>
</span><span id="__span-1-4"><a id="__codelineno-1-4" name="__codelineno-1-4" href="#__codelineno-1-4"></a><span class="w"> </span><span class="nt">default</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">primary@example.com:pw1</span>
</span><span id="__span-1-5"><a id="__codelineno-1-5" name="__codelineno-1-5" href="#__codelineno-1-5"></a><span class="w"> </span><span class="nt">second</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">secondary@example.com:pw2</span>
</span></code></pre></div>
<div class="admonition tip">
<p class="admonition-title">Cookies vs credentials</p>
<p>unshackle stores cookies as files under <a href="../directories/"><code>directories.cookies</code></a>, not in this config key.
A service's <code>authenticate()</code> accepts cookies, credentials, or both.</p>
</div>
<h2 id="firefox_cookies"><code>firefox_cookies</code><a class="headerlink" href="#firefox_cookies" title="Permanent link">&para;</a></h2>
<ul>
<li><strong>Type:</strong> <code>dict</code> keyed by service tag &nbsp;·&nbsp; <strong>Default:</strong> <code>{}</code></li>
</ul>
<p>Settings for extracting cookies directly from a local Firefox profile. A service block must give
<code>hosts</code>, a list of cookie hostnames. unshackle ignores an entry shorter than 3 characters, to
prevent a broad match dumping most of the profile. With an optional <code>local_storage</code> boolean,
unshackle also pulls matching entries from <code>webappsstore.sqlite</code>, which only services that keep
auth tokens in localStorage rather than in HTTP cookies need. Extraction is read-only.</p>
<div class="admonition note">
<p class="admonition-title">Firefox does not need to be closed</p>
<p>The extractor copies <strong>both</strong> <code>cookies.sqlite</code> <strong>and</strong> its WAL file into a <code>0700</code> temp
directory, so the copy holds the writes Firefox has not yet flushed to the main DB. Extraction
fails only if Firefox holds an exclusive write lock at the instant of the copy. The live
profile is not modified.</p>
</div>
<div class="admonition warning">
<p class="admonition-title">Extraction falls back silently to file cookies</p>
<p>If extraction yields no cookies or fails for <strong>any</strong> reason, unshackle silently falls back
to the normal file-based cookie path (<code>cookies/&lt;SERVICE&gt;.txt</code> or
<code>cookies/&lt;SERVICE&gt;/&lt;profile&gt;.txt</code>), with no error reported.</p>
</div>
<h2 id="remote_services"><code>remote_services</code><a class="headerlink" href="#remote_services" title="Permanent link">&para;</a></h2>
<ul>
<li><strong>Type:</strong> <code>dict</code> &nbsp;·&nbsp; <strong>Default:</strong> <code>{}</code></li>
</ul>
<p>Definitions of remote unshackle service servers, used by the <code>--remote</code> mode. Each entry is
named by you (pick it with <code>--server</code>, or do not write that flag when you configure only one) and gives
the server's <code>url</code> (required), an optional <code>api_key</code>, an optional <code>auth_headers</code> list, an
optional <code>server_cdm</code> boolean, an optional <code>timeout</code> in seconds, and an optional <code>services</code> sub-dict of per-service local
overrides such as <code>title_map</code>, keyed by service tag in any case. A <code>server_cdm</code> in a <code>services</code> entry replaces the <code>server_cdm</code> of
the server entry for that service.</p>
<p>Leave <code>server_cdm</code> unset and the client follows the server: it uses the server CDM for each
service the API key has it on, and the local CDM for the others. <code>true</code> asks for the server CDM
and falls back to the local CDM when the server refuses; <code>false</code> always uses the local CDM.
<code>dl --cdm &lt;name&gt;</code> on a remote run has the same effect as <code>false</code> for that run: the device you
name licenses the remote session, and it takes priority over <code>server_cdm: true</code>. When
<code>server_cdm</code> is unset, a <a href="../drm/#cdm"><code>cdm</code></a> entry for the service has the same effect for that
service when it names the device that unshackle loaded. The <code>default</code> entry does not count.
With <code>server_cdm: true</code>, the server CDM licenses the remote session, and the device of the entry
licenses only when the server refuses. Thus the entry applies to local runs and the server CDM
applies to remote runs:</p>
<div class="language-yaml highlight"><pre><span></span><code><span id="__span-2-1"><a id="__codelineno-2-1" name="__codelineno-2-1" href="#__codelineno-2-1"></a><span class="nt">cdm</span><span class="p">:</span>
</span><span id="__span-2-2"><a id="__codelineno-2-2" name="__codelineno-2-2" href="#__codelineno-2-2"></a><span class="w"> </span><span class="nt">EXAMPLE1</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">my_device</span><span class="w"> </span><span class="c1"># local runs of EXAMPLE1</span>
</span><span id="__span-2-3"><a id="__codelineno-2-3" name="__codelineno-2-3" href="#__codelineno-2-3"></a>
</span><span id="__span-2-4"><a id="__codelineno-2-4" name="__codelineno-2-4" href="#__codelineno-2-4"></a><span class="nt">remote_services</span><span class="p">:</span>
</span><span id="__span-2-5"><a id="__codelineno-2-5" name="__codelineno-2-5" href="#__codelineno-2-5"></a><span class="w"> </span><span class="nt">my_server</span><span class="p">:</span>
</span><span id="__span-2-6"><a id="__codelineno-2-6" name="__codelineno-2-6" href="#__codelineno-2-6"></a><span class="w"> </span><span class="nt">url</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">https://example.com</span>
</span><span id="__span-2-7"><a id="__codelineno-2-7" name="__codelineno-2-7" href="#__codelineno-2-7"></a><span class="w"> </span><span class="nt">server_cdm</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">true</span><span class="w"> </span><span class="c1"># remote runs of EXAMPLE1 use the server CDM</span>
</span><span id="__span-2-8"><a id="__codelineno-2-8" name="__codelineno-2-8" href="#__codelineno-2-8"></a><span class="w"> </span><span class="nt">services</span><span class="p">:</span>
</span><span id="__span-2-9"><a id="__codelineno-2-9" name="__codelineno-2-9" href="#__codelineno-2-9"></a><span class="w"> </span><span class="nt">EXAMPLE2</span><span class="p">:</span>
</span><span id="__span-2-10"><a id="__codelineno-2-10" name="__codelineno-2-10" href="#__codelineno-2-10"></a><span class="w"> </span><span class="nt">server_cdm</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">false</span><span class="w"> </span><span class="c1"># remote runs of EXAMPLE2 use your own device</span>
</span></code></pre></div>
<p>When the server refuses the server CDM for a service whose <code>cdm</code> entry loaded the device,
unshackle logs the fallback to that device as info, not as a warning.</p>
<p>The server has the last word. When it keeps the server CDM for a remote session that your
device was to license, unshackle shows a warning. This occurs with a server that does not read
your choice, and with a service option that runs the remote session on the server's device.</p>
<p><code>auth_headers</code> lists extra header names to send the API key in, tried before the defaults
<code>X-Secret-Key</code> and <code>X-Api-Key</code>, which unshackle always appends as fallbacks. It sends the
first name. If the server answers <code>401</code>, it retries the same request with the next name, and
keeps the one that works for the rest of the HTTP session. Names you give keep your spelling and
are not repeated in the fallbacks, so unshackle tries
<code>auth_headers: ["Authorization", "x-secret-key"]</code> as <code>Authorization</code>, <code>x-secret-key</code>, <code>X-Api-Key</code>.</p>
<p><code>timeout</code> is the time in seconds that the client waits for data from the server. The
default is <code>120</code>. The server sends a heartbeat every 30 seconds while it gets titles, tracks
or licences, so a slow service does not cause a timeout. Increase <code>timeout</code> only when the
server runs an older version that sends no heartbeat. Give a number of seconds. With a
value below 30 the client can time out before the first heartbeat. <code>0</code> means the default.</p>
<p>In <code>--remote</code> mode unshackle turns the server's service list into synthetic CLI
commands that operate against it, falling back to the tags in that <code>services</code> sub-dict when
unshackle cannot fetch the list. Each synthetic command carries the server-side service's options and
documentation, so <code>unshackle dl --remote &lt;TAG&gt; -h</code> shows the same help text as it does on the
server. Service names resolve against the server's tags and aliases, not your local services.
If the server does not offer a name to your API key, unshackle rejects the name and lists the
tags it does offer. See <a href="../../../dev/rest-api/remote-sessions/">remote sessions</a> for the
full setup.</p>
<h2 id="serve"><code>serve</code><a class="headerlink" href="#serve" title="Permanent link">&para;</a></h2>
<ul>
<li><strong>Type:</strong> <code>dict</code> &nbsp;·&nbsp; <strong>Default:</strong> <code>{}</code></li>
</ul>
<p>Configuration for the <code>serve</code> command (the built-in REST API server). The full server guide
is the <a href="../../../dev/rest-api/">REST API</a> section. These are the config keys.</p>
<table>
<thead>
<tr>
<th>Sub-key</th>
<th>Type</th>
<th>Default</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>api_secret</code></td>
<td>str</td>
<td><em>(unset)</em></td>
<td>Master secret the server accepts in the <code>X-Secret-Key</code> header. Required unless you start the server with <code>--no-key</code>.</td>
</tr>
<tr>
<td><code>users</code></td>
<td>dict</td>
<td><code>{}</code></td>
<td>Per-user API keys and their allowlists (see below).</td>
</tr>
<tr>
<td><code>tiers</code></td>
<td>dict</td>
<td><code>{}</code></td>
<td>Named settings that <code>users</code> entries reference by name (see below).</td>
</tr>
<tr>
<td><code>services</code></td>
<td>list</td>
<td><em>(unset)</em></td>
<td>Global service allowlist. Omit to allow all.</td>
</tr>
<tr>
<td><code>remote_only</code></td>
<td>bool</td>
<td><code>false</code></td>
<td>Expose only the remote service session endpoints (health, services, search, session) and disable the rest of the REST API.</td>
</tr>
<tr>
<td><code>dashboard</code></td>
<td>dict</td>
<td><em>(unset)</em></td>
<td>Developer dashboard: <code>key</code> is the API key for the read-only <code>/api/dashboard/</code> endpoints (status, remote sessions, remote session logs, jobs, keys, services, health, logs, SSE events). Unset leaves those routes unregistered. See <a href="../../../dev/rest-api/dashboard/">dashboard endpoints</a>.</td>
</tr>
<tr>
<td><code>session_ttl</code></td>
<td>int (s)</td>
<td><code>300</code></td>
<td>Seconds a remote session can stay idle before it expires. A remote client sends keep-alive requests to its remote session during a download, so the remote session does not expire during a long download.</td>
</tr>
<tr>
<td><code>max_sessions</code></td>
<td>int or null</td>
<td><code>100</code></td>
<td>Maximum concurrent remote sessions; at the cap the server evicts the oldest. Set it to <code>null</code> or <code>0</code> for no limit, which is also what <code>/api/dashboard/status</code> then reports, so a dashboard can tell "no cap" from a cap that happens to sit at the default.</td>
</tr>
<tr>
<td><code>history_limit</code></td>
<td>int</td>
<td><code>100</code></td>
<td>How many finished jobs to retain in history.</td>
</tr>
<tr>
<td><code>compression_level</code></td>
<td>int</td>
<td><code>1</code></td>
<td>gzip level for responses.</td>
</tr>
<tr>
<td><code>services_refresh_interval</code></td>
<td>int (s)</td>
<td><code>0</code></td>
<td>How often the server pulls the git-backed service repositories in <code>directories.services</code> and hot-reloads the services that changed. <code>0</code> turns it off. A service with a running or queued job, or a live remote session, is staged and swaps to the new code as soon as its last job and session finish.</td>
</tr>
<tr>
<td><code>services_staged_max_age</code></td>
<td>int (s)</td>
<td><code>0</code></td>
<td>How long a staged service waits for its jobs and sessions before the server swaps it in anyway. <code>0</code> waits forever. Set it on a server whose popular services never have a quiet moment. A session that is live at the swap keeps the old code until it ends; a running job keeps its old code too.</td>
</tr>
<tr>
<td><code>global_speed_limit</code></td>
<td>str</td>
<td><em>(unlimited)</em></td>
<td>Server-wide download speed cap, e.g. <code>10M</code>, <code>1.5G</code> or plain bytes/sec (same format as <code>speed_limit</code>). Each download job gets an equal share: the cap divided by the number of download job slots (2 by default, see <a href="../../../dev/rest-api/job-lifecycle/">job lifecycle</a>). A job that runs alone still gets only its share. The server ignores per-job speed limits while it is set.</td>
</tr>
<tr>
<td><code>cdm_overrides</code></td>
<td>list or bool</td>
<td><em>(unset)</em></td>
<td>Allowed per-request CDM overrides: a list of permitted device names, or <code>true</code> for any. Unset rejects every override.</td>
</tr>
<tr>
<td><code>allow_job_credentials</code></td>
<td>bool</td>
<td><code>false</code></td>
<td>Permit clients to supply credentials per job.</td>
</tr>
<tr>
<td><code>server_accounts</code></td>
<td>dict</td>
<td><code>{}</code></td>
<td>Services whose remote sessions use the server's own <code>credentials</code> and cookie files instead of the client's (see below).</td>
</tr>
<tr>
<td><code>devices</code></td>
<td>list</td>
<td><em>(auto)</em></td>
<td>Widevine devices offered; auto-filled from <code>directories.wvds</code>.</td>
</tr>
<tr>
<td><code>playready_devices</code></td>
<td>list</td>
<td><em>(auto)</em></td>
<td>PlayReady devices; auto-filled from <code>directories.prds</code>.</td>
</tr>
</tbody>
</table>
<p>Each entry under <code>users</code> uses that user's API key as its name, and can set its own <code>services</code>,
<code>devices</code>, and <code>playready_devices</code> allowlists, narrowing the global ones, plus an optional
<code>username</code> used as the log label for that API key (defaults to a truncated form of the API key).
A user with no <code>playready_devices</code> config key gets no PlayReady access at all, not the global
list.</p>
<div class="admonition info">
<p class="admonition-title">Reload <code>serve</code> settings without a restart</p>
<p>Send <code>SIGHUP</code> to a running server (<code>systemctl reload</code> with
<code>ExecReload=kill -HUP $MAINPID</code> in the unit) after you edit the file. The server reads
the whole file again, globs the device directories again, and swaps in the new <code>users</code>,
<code>tiers</code>, <code>services</code> and device lists in one step. Open CDM sessions and remote sessions
continue; an API key you removed gets <code>401</code> on its next request. A file that does not parse
or validate keeps the running settings and logs the reason. A change to <code>remote_only</code>,
<code>services_refresh_interval</code>, the first PlayReady device, or any command-line flag needs
a restart, and the log says so. A new <code>global_speed_limit</code> applies to jobs that start after the
reload; running jobs keep their share. Windows has no <code>SIGHUP</code>: restart the server there.</p>
</div>
<p><code>server_cdm</code> decides whether the server runs the CDM licensing for that API key. Set it to
<code>true</code> to enable every service, or to a list of service tags to enable only those. It is <code>false</code>
unless the entry sets it. For a service the API key does not cover, the server tells a remote
client configured with <code>server_cdm: true</code> to license with its own local CDM instead, and a
client that asks anyway gets a <code>FORBIDDEN</code> error. Because a download job always licenses with the server's CDM,
an API key without <code>server_cdm</code> for that service also cannot submit or retry <code>/api/download</code>
jobs. Keys that have no <code>users</code> entry, such as <code>api_secret</code>, keep server CDM access.</p>
<p>A remote client that picks its own device licenses the remote session with that device. It picks
with <code>dl --cdm</code>, with <code>server_cdm: false</code> in its <code>remote_services</code> entry or in the <code>services</code>
entry for the service, or with a <code>cdm</code> entry for the service when <code>server_cdm</code> is unset. The server CDM makes no licence for that remote session, with or without
a limit. A service option that runs the remote session on the server's device, such as a
server-identity flag, keeps the server CDM.</p>
<p><code>server_cdm_max_height</code> limits the live licences the server's device makes for that API key.
Set it to a height in pixels for every service, or to a map of service tag to height with an
optional <code>default</code> entry. A service the map does not name or sets to <code>null</code> gets the <code>default</code>, and
with no <code>default</code> it has no limit. The server compares the limit with the lowest <code>-q</code> that selects
the track: the track height, or the 16:9 height from the width when that is lower. The server reads
the remote client's <code>-q</code> when the remote session starts:</p>
<ul>
<li>With no <code>-q</code>, or a <code>-q</code> at or below the limit, the server CDM licenses the remote session. The server
refuses a live licence for a video track taller than the limit, and the client licenses that
track with its own local CDM.</li>
<li>With a <code>-q</code> above the limit, the client's own local CDM licenses every track of the remote session.
The service sees the DRM system and security level of the client's device. A client with no
local CDM gets a <code>SERVER_CDM_CAPPED</code> error.</li>
<li>A download job must pass a <code>quality</code> at or below the limit, and must not set <code>best_available</code> or
a <code>HYBRID</code> range. <code>HYBRID</code> can keep the lowest Dolby Vision track, at any quality. A job with
no <code>quality</code>, with a higher one, with <code>best_available</code>, or with <code>HYBRID</code> gets a <code>SERVER_CDM_CAPPED</code>
error. The server checks the values the job runs with, after it applies the service defaults
and the <code>serve:</code> download defaults.</li>
</ul>
<p>The limit protects the server's device, not the content keys. For a Widevine track, a server vault
still supplies a content key at every height. A PlayReady track never reads the vault, so above
the limit it always goes to the client's device. A licence for a lower track can carry the
content key of a higher track when the service shares one content key between them. With server
accounts enabled, a client that reports a stronger device than it holds makes the server's
account request those manifests; the licence server still refuses its challenge.</p>
<p><code>server_vault</code> lets a remote session that the client's own device licenses take content keys
from the server vault. Set it to <code>true</code> for every service, or to a list of service tags. It is
<code>false</code> unless the entry sets it, and <code>server_cdm</code> for a service implies it. The server looks up
every KID of the track in its vault and makes no live licence. A track that the vault does not
hold goes back to the client's device. When the service runs the remote session on the server's
own device (a service option, such as a server-identity flag), the client's own vaults, and the
server vault with this grant, are the only source, and a missing content key stops the download.</p>
<p><code>admin</code> is a boolean that lets the API key run the maintenance endpoints (clear-cache, clear-temp, refresh-services). It is <code>false</code> unless the entry sets it. Keys that have no <code>users</code> entry, such as <code>api_secret</code>, keep that access.</p>
<p>A <code>tier</code> names an entry under <code>serve.tiers</code>, which holds the settings that several API keys
share. Today a tier carries <code>rate_limit</code>, the requests per hour that API key may make; an API
key can also set its own <code>rate_limit</code>, which wins over its tier's. An API key with neither has
no limit. Going over the limit answers <code>429</code> with a <code>Retry-After</code> header. The server keeps a
fixed window rather than a sliding one: it opens on the first request and resets an hour
later. A <code>tier</code> that names no entry under <code>serve.tiers</code>, or a <code>rate_limit</code> that is not a
positive whole number, stops the server at startup, because the alternative is an API key that
silently gets no limit. The rate limit never applies to the dashboard key, and never to
<code>/api/health</code>.</p>
<p><code>server_accounts</code> lists, per service, the accounts the server lends to remote sessions. A remote
session for a listed service ignores the credentials, cookies, and cache the client sends and
uses one of the server's own profiles from <code>credentials</code>. For a service that is not listed the
server never uses its own accounts: a client that sends nothing authenticates with nothing.</p>
<div class="language-yaml highlight"><pre><span></span><code><span id="__span-3-1"><a id="__codelineno-3-1" name="__codelineno-3-1" href="#__codelineno-3-1"></a><span class="nt">credentials</span><span class="p">:</span>
</span><span id="__span-3-2"><a id="__codelineno-3-2" name="__codelineno-3-2" href="#__codelineno-3-2"></a><span class="w"> </span><span class="nt">EXAMPLE1</span><span class="p">:</span>
</span><span id="__span-3-3"><a id="__codelineno-3-3" name="__codelineno-3-3" href="#__codelineno-3-3"></a><span class="w"> </span><span class="nt">ca_main</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">user1@example.com:pw1</span>
</span><span id="__span-3-4"><a id="__codelineno-3-4" name="__codelineno-3-4" href="#__codelineno-3-4"></a><span class="w"> </span><span class="nt">eu_box</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">user2@example.com:pw2</span>
</span><span id="__span-3-5"><a id="__codelineno-3-5" name="__codelineno-3-5" href="#__codelineno-3-5"></a><span class="w"> </span><span class="nt">shared</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">user3@example.com:pw3</span>
</span><span id="__span-3-6"><a id="__codelineno-3-6" name="__codelineno-3-6" href="#__codelineno-3-6"></a>
</span><span id="__span-3-7"><a id="__codelineno-3-7" name="__codelineno-3-7" href="#__codelineno-3-7"></a><span class="nt">serve</span><span class="p">:</span>
</span><span id="__span-3-8"><a id="__codelineno-3-8" name="__codelineno-3-8" href="#__codelineno-3-8"></a><span class="w"> </span><span class="nt">server_accounts</span><span class="p">:</span>
</span><span id="__span-3-9"><a id="__codelineno-3-9" name="__codelineno-3-9" href="#__codelineno-3-9"></a><span class="w"> </span><span class="nt">EXAMPLE1</span><span class="p">:</span>
</span><span id="__span-3-10"><a id="__codelineno-3-10" name="__codelineno-3-10" href="#__codelineno-3-10"></a><span class="w"> </span><span class="nt">ca_main</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">ca</span><span class="w"> </span><span class="c1"># one country</span>
</span><span id="__span-3-11"><a id="__codelineno-3-11" name="__codelineno-3-11" href="#__codelineno-3-11"></a><span class="w"> </span><span class="nt">eu_box</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">[</span><span class="nv">gb</span><span class="p p-Indicator">,</span><span class="w"> </span><span class="nv">fr</span><span class="p p-Indicator">,</span><span class="w"> </span><span class="nv">de</span><span class="p p-Indicator">]</span><span class="w"> </span><span class="c1"># a list of countries</span>
</span><span id="__span-3-12"><a id="__codelineno-3-12" name="__codelineno-3-12" href="#__codelineno-3-12"></a><span class="w"> </span><span class="nt">shared</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">global</span><span class="w"> </span><span class="c1"># any region</span>
</span><span id="__span-3-13"><a id="__codelineno-3-13" name="__codelineno-3-13" href="#__codelineno-3-13"></a><span class="w"> </span><span class="nt">EXAMPLE2</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">true</span><span class="w"> </span><span class="c1"># every profile (or the single credential), any region</span>
</span></code></pre></div>
<p>Each entry under a service names a profile from <code>credentials</code>, or a cookie file
<code>cookies/&lt;TAG&gt;/&lt;profile&gt;.txt</code> for a service that has no credentials. Its value is the region or
regions that account works in: a two-letter country code, a list of them, or <code>global</code>. Quote
<code>no</code> (Norway), because YAML reads the bare word as <code>false</code>.</p>
<p>The region of a remote session is the country the client asked for with <code>--proxy</code> (<code>ca</code>, <code>ca1</code>,
<code>provider:ca</code>), the server's own region with <code>--no-proxy</code>, or the client's own region otherwise.
A full proxy URI carries no country, so with one only a <code>global</code> account matches. The server
picks the profiles that cover that region (or are <code>global</code>) and rotates through them
round-robin, one account per remote session. With no matching account it rejects the remote
session. These services ignore the client's <code>-p/--profile</code>.</p>
<p>Cookies come only from the profile's own file (<code>cookies/EXAMPLE1/ca_main.txt</code>; the server does
not read a bare <code>cookies/EXAMPLE1.txt</code>), and each account keeps its own persistent cache under
<code>cache/_accounts/EXAMPLE1/&lt;profile&gt;/</code>, so refreshed tokens survive the remote session but never
cross accounts. <code>serve</code> refuses to start when a listed profile has neither an entry under
<code>credentials</code> nor a cookie file.
<code>/api/search</code>, <code>/api/list-titles</code> and <code>/api/list-tracks</code> use the same pool, matched on the
client's reported region, and return <code>FORBIDDEN</code> to an API key without the opt-in. Rotation is
per process and does not track which accounts are in use, so concurrent remote sessions can
share one account.</p>
<p>A <code>users</code> entry opts in to those accounts with <code>server_accounts: true</code> (every listed service)
or a list of service tags. It is off unless set: an API key without it authenticates with the
credentials the client sends, as for any other service, and <code>/api/services</code> does not advertise
the server's accounts to it. API keys with no <code>users</code> entry, such as <code>api_secret</code>, keep access.</p>
<p><code>server_proxy</code> decides whether that API key may use the proxy providers the server has
configured. There is no implicit access: only the boolean <code>true</code> on the API key's <code>users</code> entry
grants it, and an API key without a <code>users</code> entry has no access either. Without the opt-in the
server never spends its own proxy subscriptions on a remote client: not to resolve a country code
in <code>proxy</code>, not to match the client's region, and not for a service geofence. This applies to
remote sessions, search, title lists, and <code>/api/download</code> jobs alike. Such a client must send a
full proxy URI, or <code>no_proxy</code> to accept the server's own connection. Set <code>server_proxy: true</code>
to let that API key send a country code or a <code>provider:country</code> value, and to let the server
pick a proxy for the client's region and for a service geofence. The client reports its own
region; a client that reports none is not blocked.</p>
<p>Without <code>server_proxy</code>, the server refuses a proxy URI whose host is not a public address:
loopback, private, link-local and other special-purpose addresses, and <code>localhost</code>. This also
applies to a server on a LAN, so a client proxy on that LAN needs <code>server_proxy</code> or an admin key.
The server checks the proxy values the job uses, including a <code>proxy</code> default from the server's
own config.</p>
<div class="language-yaml highlight"><pre><span></span><code><span id="__span-4-1"><a id="__codelineno-4-1" name="__codelineno-4-1" href="#__codelineno-4-1"></a><span class="nt">serve</span><span class="p">:</span>
</span><span id="__span-4-2"><a id="__codelineno-4-2" name="__codelineno-4-2" href="#__codelineno-4-2"></a><span class="w"> </span><span class="nt">api_secret</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">change-me</span>
</span><span id="__span-4-3"><a id="__codelineno-4-3" name="__codelineno-4-3" href="#__codelineno-4-3"></a><span class="w"> </span><span class="nt">remote_only</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">true</span>
</span><span id="__span-4-4"><a id="__codelineno-4-4" name="__codelineno-4-4" href="#__codelineno-4-4"></a><span class="w"> </span><span class="nt">services</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">[</span><span class="nv">EXAMPLE1</span><span class="p p-Indicator">,</span><span class="w"> </span><span class="nv">EXAMPLE2</span><span class="p p-Indicator">]</span>
</span><span id="__span-4-5"><a id="__codelineno-4-5" name="__codelineno-4-5" href="#__codelineno-4-5"></a><span class="w"> </span><span class="nt">services_refresh_interval</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">3600</span><span class="w"> </span><span class="c1"># pull the service repositories hourly and reload what changed</span>
</span><span id="__span-4-6"><a id="__codelineno-4-6" name="__codelineno-4-6" href="#__codelineno-4-6"></a><span class="w"> </span><span class="c1"># server-wide download defaults (same keys as the `dl:` block)</span>
</span><span id="__span-4-7"><a id="__codelineno-4-7" name="__codelineno-4-7" href="#__codelineno-4-7"></a><span class="w"> </span><span class="nt">downloads</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">3</span>
</span><span id="__span-4-8"><a id="__codelineno-4-8" name="__codelineno-4-8" href="#__codelineno-4-8"></a><span class="w"> </span><span class="nt">best_available</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">true</span>
</span><span id="__span-4-9"><a id="__codelineno-4-9" name="__codelineno-4-9" href="#__codelineno-4-9"></a><span class="w"> </span><span class="nt">tiers</span><span class="p">:</span>
</span><span id="__span-4-10"><a id="__codelineno-4-10" name="__codelineno-4-10" href="#__codelineno-4-10"></a><span class="w"> </span><span class="nt">bot</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">{</span><span class="nt"> rate_limit</span><span class="p">:</span><span class="w"> </span><span class="nv">600</span><span class="w"> </span><span class="p p-Indicator">}</span><span class="w"> </span><span class="c1"># requests per hour, for every key on this tier</span>
</span><span id="__span-4-11"><a id="__codelineno-4-11" name="__codelineno-4-11" href="#__codelineno-4-11"></a><span class="w"> </span><span class="nt">users</span><span class="p">:</span>
</span><span id="__span-4-12"><a id="__codelineno-4-12" name="__codelineno-4-12" href="#__codelineno-4-12"></a><span class="w"> </span><span class="nt">a1b2c3d4</span><span class="p">:</span><span class="w"> </span><span class="c1"># this user's API key</span>
</span><span id="__span-4-13"><a id="__codelineno-4-13" name="__codelineno-4-13" href="#__codelineno-4-13"></a><span class="w"> </span><span class="nt">services</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">[</span><span class="nv">EXAMPLE1</span><span class="p p-Indicator">]</span><span class="w"> </span><span class="c1"># may only use EXAMPLE1</span>
</span><span id="__span-4-14"><a id="__codelineno-4-14" name="__codelineno-4-14" href="#__codelineno-4-14"></a><span class="w"> </span><span class="nt">tier</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">bot</span><span class="w"> </span><span class="c1"># 600 requests/hour; 429 with Retry-After once over</span>
</span><span id="__span-4-15"><a id="__codelineno-4-15" name="__codelineno-4-15" href="#__codelineno-4-15"></a><span class="w"> </span><span class="nt">e5f6a7b8</span><span class="p">:</span>
</span><span id="__span-4-16"><a id="__codelineno-4-16" name="__codelineno-4-16" href="#__codelineno-4-16"></a><span class="w"> </span><span class="nt">server_cdm</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">true</span><span class="w"> </span><span class="c1"># this key may have the server do the licensing</span>
</span><span id="__span-4-17"><a id="__codelineno-4-17" name="__codelineno-4-17" href="#__codelineno-4-17"></a><span class="w"> </span><span class="nt">server_cdm_max_height</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">1080</span><span class="w"> </span><span class="c1"># above 1080p the client licenses with its own device</span>
</span><span id="__span-4-18"><a id="__codelineno-4-18" name="__codelineno-4-18" href="#__codelineno-4-18"></a><span class="w"> </span><span class="nt">c9d0e1f2</span><span class="p">:</span>
</span><span id="__span-4-19"><a id="__codelineno-4-19" name="__codelineno-4-19" href="#__codelineno-4-19"></a><span class="w"> </span><span class="nt">services</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">[</span><span class="nv">EXAMPLE1</span><span class="p p-Indicator">,</span><span class="w"> </span><span class="nv">EXAMPLE2</span><span class="p p-Indicator">]</span>
</span><span id="__span-4-20"><a id="__codelineno-4-20" name="__codelineno-4-20" href="#__codelineno-4-20"></a><span class="w"> </span><span class="nt">server_cdm</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">[</span><span class="nv">EXAMPLE1</span><span class="p p-Indicator">]</span><span class="w"> </span><span class="c1"># the server licenses only EXAMPLE1; EXAMPLE2 needs a local CDM</span>
</span><span id="__span-4-21"><a id="__codelineno-4-21" name="__codelineno-4-21" href="#__codelineno-4-21"></a><span class="w"> </span><span class="nt">server_accounts</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">[</span><span class="nv">EXAMPLE1</span><span class="p p-Indicator">]</span><span class="w"> </span><span class="c1"># may authenticate EXAMPLE1 with one of the server's own accounts</span>
</span><span id="__span-4-22"><a id="__codelineno-4-22" name="__codelineno-4-22" href="#__codelineno-4-22"></a><span class="w"> </span><span class="nt">server_proxy</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">true</span><span class="w"> </span><span class="c1"># this key may also use the server's proxy providers</span>
</span><span id="__span-4-23"><a id="__codelineno-4-23" name="__codelineno-4-23" href="#__codelineno-4-23"></a><span class="w"> </span><span class="nt">f3a4b5c6</span><span class="p">:</span>
</span><span id="__span-4-24"><a id="__codelineno-4-24" name="__codelineno-4-24" href="#__codelineno-4-24"></a><span class="w"> </span><span class="nt">services</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">[</span><span class="nv">EXAMPLE1</span><span class="p p-Indicator">]</span>
</span><span id="__span-4-25"><a id="__codelineno-4-25" name="__codelineno-4-25" href="#__codelineno-4-25"></a><span class="w"> </span><span class="nt">server_vault</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">[</span><span class="nv">EXAMPLE1</span><span class="p p-Indicator">]</span><span class="w"> </span><span class="c1"># the client's device licenses; the server vault still serves keys</span>
</span></code></pre></div>
<div class="admonition note">
<p class="admonition-title"><code>dl</code> keys inside <code>serve</code></p>
<p>Most <a href="../download/#dl"><code>dl</code></a> flag keys (<code>downloads</code>, <code>workers</code>, <code>best_available</code>, and so on)
can be set directly inside <code>serve</code>, where they apply to every request the server handles.
The server recognises a fixed subset of download parameters, so a few CLI-only flags are
ignored here.</p>
</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="../directories/" class="md-footer__link md-footer__link--prev" aria-label="Previous: Directories">
<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">
Directories
</div>
</div>
</a>
<a href="../download/" class="md-footer__link md-footer__link--next" aria-label="Next: Download &amp; Processing">
<div class="md-footer__title">
<span class="md-footer__direction">
Next
</span>
<div class="md-ellipsis">
Download & Processing
</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.a7633da7.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.c21346df.min.js"></script>
</body>
</html>