Files
unshackle/SERVICE_CONFIG/index.html
T
2026-07-02 15:20:50 +00:00

1916 lines
57 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="Configuration reference for unshackle">
<link rel="canonical" href="https://docs.unshackle.dev/SERVICE_CONFIG/">
<link rel="prev" href="../CREATING_A_SERVICE/">
<link rel="next" href="../DOWNLOAD_CONFIG/">
<link rel="icon" href="../assets/favicon.svg">
<meta name="generator" content="mkdocs-1.6.1, mkdocs-material-9.7.6">
<title>Service Integration & Auth - unshackle</title>
<link rel="stylesheet" href="../assets/stylesheets/main.484c7ddc.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>
<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="indigo" 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-integration-authentication-configuration" 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 Integration & Auth
</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="indigo" 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="indigo" 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">
GitHub
</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="../CREATING_A_SERVICE/" class="md-tabs__link">
Creating a Service
</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="../API/" class="md-tabs__link">
REST API
</a>
</li>
<li class="md-tabs__item">
<a href="../DEBUG_LOGGING/" class="md-tabs__link">
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">
GitHub
</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">
<a href="../CREATING_A_SERVICE/" class="md-nav__link">
<span class="md-ellipsis">
Creating a Service
</span>
</a>
</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_3" checked>
<label class="md-nav__link" for="__nav_3" id="__nav_3_label" tabindex="">
<span class="md-ellipsis">
Configuration
</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="true">
<label class="md-nav__title" for="__nav_3">
<span class="md-nav__icon md-icon"></span>
Configuration
</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 Integration & Auth
</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 Integration & Auth
</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-dict" class="md-nav__link">
<span class="md-ellipsis">
services (dict)
</span>
</a>
<nav class="md-nav" aria-label="services (dict)">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#per-service-configuration-overrides" class="md-nav__link">
<span class="md-ellipsis">
Per-Service Configuration Overrides
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#title_map-dict" class="md-nav__link">
<span class="md-ellipsis">
title_map (dict)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#service-class-conventions" class="md-nav__link">
<span class="md-ellipsis">
Service Class Conventions
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#credentials-dictstr-strlistdict" class="md-nav__link">
<span class="md-ellipsis">
credentials (dict[str, str|list|dict])
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#firefox_cookies-dict" class="md-nav__link">
<span class="md-ellipsis">
firefox_cookies (dict)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#tmdb_api_key-str" class="md-nav__link">
<span class="md-ellipsis">
tmdb_api_key (str)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#simkl_client_id-str" class="md-nav__link">
<span class="md-ellipsis">
simkl_client_id (str)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#ipinfo_api_key-str" class="md-nav__link">
<span class="md-ellipsis">
ipinfo_api_key (str)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#title_cache_enabled-bool" class="md-nav__link">
<span class="md-ellipsis">
title_cache_enabled (bool)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#title_cache_time-int" class="md-nav__link">
<span class="md-ellipsis">
title_cache_time (int)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#title_cache_max_retention-int" class="md-nav__link">
<span class="md-ellipsis">
title_cache_max_retention (int)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#debug-bool" class="md-nav__link">
<span class="md-ellipsis">
debug (bool)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#debug_keys-bool" class="md-nav__link">
<span class="md-ellipsis">
debug_keys (bool)
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../DOWNLOAD_CONFIG/" class="md-nav__link">
<span class="md-ellipsis">
Download & Processing
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../OUTPUT_CONFIG/" class="md-nav__link">
<span class="md-ellipsis">
Output & Naming
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../SUBTITLE_CONFIG/" class="md-nav__link">
<span class="md-ellipsis">
Subtitles
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../DRM_CONFIG/" class="md-nav__link">
<span class="md-ellipsis">
DRM & CDM
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../NETWORK_CONFIG/" class="md-nav__link">
<span class="md-ellipsis">
Network & Proxy
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../GLUETUN/" class="md-nav__link">
<span class="md-ellipsis">
Gluetun VPN
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../ADVANCED_CONFIG/" class="md-nav__link">
<span class="md-ellipsis">
Advanced & System
</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" >
<label class="md-nav__link" for="__nav_4" id="__nav_4_label" tabindex="0">
<span class="md-ellipsis">
REST API
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<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>
REST API
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../API/" class="md-nav__link">
<span class="md-ellipsis">
Overview
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../api/quick-start/" class="md-nav__link">
<span class="md-ellipsis">
Quick Start
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../api/authentication/" class="md-nav__link">
<span class="md-ellipsis">
Authentication
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../api/endpoints/" class="md-nav__link">
<span class="md-ellipsis">
Endpoints
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../api/endpoint-map/" class="md-nav__link">
<span class="md-ellipsis">
Endpoint Map
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../api/download-job-lifecycle/" class="md-nav__link">
<span class="md-ellipsis">
Download Job Lifecycle
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../api/remote-service-sessions/" class="md-nav__link">
<span class="md-ellipsis">
Remote Service Sessions
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../api/client-configuration/" class="md-nav__link">
<span class="md-ellipsis">
Client Configuration
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../api/error-responses/" class="md-nav__link">
<span class="md-ellipsis">
Error Responses
</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">
Reference
</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>
Reference
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../DEBUG_LOGGING/" class="md-nav__link">
<span class="md-ellipsis">
Debug Logging
</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-dict" class="md-nav__link">
<span class="md-ellipsis">
services (dict)
</span>
</a>
<nav class="md-nav" aria-label="services (dict)">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#per-service-configuration-overrides" class="md-nav__link">
<span class="md-ellipsis">
Per-Service Configuration Overrides
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#title_map-dict" class="md-nav__link">
<span class="md-ellipsis">
title_map (dict)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#service-class-conventions" class="md-nav__link">
<span class="md-ellipsis">
Service Class Conventions
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#credentials-dictstr-strlistdict" class="md-nav__link">
<span class="md-ellipsis">
credentials (dict[str, str|list|dict])
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#firefox_cookies-dict" class="md-nav__link">
<span class="md-ellipsis">
firefox_cookies (dict)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#tmdb_api_key-str" class="md-nav__link">
<span class="md-ellipsis">
tmdb_api_key (str)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#simkl_client_id-str" class="md-nav__link">
<span class="md-ellipsis">
simkl_client_id (str)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#ipinfo_api_key-str" class="md-nav__link">
<span class="md-ellipsis">
ipinfo_api_key (str)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#title_cache_enabled-bool" class="md-nav__link">
<span class="md-ellipsis">
title_cache_enabled (bool)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#title_cache_time-int" class="md-nav__link">
<span class="md-ellipsis">
title_cache_time (int)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#title_cache_max_retention-int" class="md-nav__link">
<span class="md-ellipsis">
title_cache_max_retention (int)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#debug-bool" class="md-nav__link">
<span class="md-ellipsis">
debug (bool)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#debug_keys-bool" class="md-nav__link">
<span class="md-ellipsis">
debug_keys (bool)
</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-integration-authentication-configuration">Service Integration &amp; Authentication Configuration<a class="headerlink" href="#service-integration-authentication-configuration" title="Permanent link">&para;</a></h1>
<p>This document covers service-specific configuration, authentication, and metadata integration options.</p>
<h2 id="services-dict">services (dict)<a class="headerlink" href="#services-dict" title="Permanent link">&para;</a></h2>
<p>Configuration data for each Service. The Service will have the data within this section merged into the per-service
<code>config.yaml</code> (located in the service's directory) before being provided to the Service class.</p>
<p>Think of this config to be used for more sensitive configuration data, like user or device-specific API keys, IDs,
device attributes, and so on. A per-service <code>config.yaml</code> file is typically shared and not meant to be modified,
so use this for any sensitive configuration data.</p>
<p>The Key is the Service Tag, but can take any arbitrary form for its value. It's expected to begin as either a list or
a dictionary.</p>
<p>For example,</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">EXAMPLE</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">client</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">auth_scheme</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">MESSO</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="c1"># ... more sensitive data</span>
</span></code></pre></div>
<h3 id="per-service-configuration-overrides">Per-Service Configuration Overrides<a class="headerlink" href="#per-service-configuration-overrides" title="Permanent link">&para;</a></h3>
<p>You can override many global configuration options on a per-service basis by nesting them under the
service tag in the <code>services</code> section. Supported override keys include: <code>dl</code>, <code>subtitle</code>, <code>muxing</code>,
<code>headers</code>, <code>proxy_map</code>, <code>title_map</code>, and more.</p>
<p>Overrides are merged with global config (not replaced) -- only specified keys are overridden, others
use global defaults.</p>
<p>Any <code>dl</code> command option can be overridden per service. Use the option name with dashes as underscores
(<code>--v-lang</code> -&gt; <code>v_lang</code>). <code>range</code> and <code>list</code> work as-is; their internal Python names (<code>range_</code>,
<code>list_</code>, suffixed to avoid the builtins) are also accepted.</p>
<p>Precedence (highest first):</p>
<ol>
<li>Explicit CLI arguments / environment variables (e.g. <code>--v-lang en</code>)</li>
<li>Per-service config (<code>services.&lt;TAG&gt;.dl</code>)</li>
<li>Global <code>dl:</code> config</li>
<li>Built-in option defaults</li>
</ol>
<p>For example,</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">services</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">RATE_LIMITED_SERVICE</span><span class="p">:</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">dl</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">downloads</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">2</span><span class="w"> </span><span class="c1"># Limit concurrent track downloads</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">workers</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">4</span><span class="w"> </span><span class="c1"># Reduce workers to avoid rate limits</span>
</span><span id="__span-1-6"><a id="__codelineno-1-6" name="__codelineno-1-6" href="#__codelineno-1-6"></a><span class="w"> </span><span class="nt">headers</span><span class="p">:</span>
</span><span id="__span-1-7"><a id="__codelineno-1-7" name="__codelineno-1-7" href="#__codelineno-1-7"></a><span class="w"> </span><span class="nt">User-Agent</span><span class="p">:</span><span class="w"> </span><span class="s">&quot;...&quot;</span><span class="w"> </span><span class="c1"># Service-specific UA override</span>
</span></code></pre></div>
<p>Note: unshackle uses a single unified <code>requests</code>-based downloader. The legacy <code>aria2c</code>,
<code>n_m3u8dl_re</code>, and <code>curl_impersonate</code> override sections have been removed.</p>
<h3 id="title_map-dict">title_map (dict)<a class="headerlink" href="#title_map-dict" title="Permanent link">&para;</a></h3>
<p>Rewrites service-provided titles before naming and output. Some services name a title differently
from how you want it stored, which can break library matching (e.g. a regional variant reusing the
international name). Keys are the exact title string the service returns; values are the desired
output title.</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">services</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">EXAMPLE</span><span class="p">:</span>
</span><span id="__span-2-3"><a id="__codelineno-2-3" name="__codelineno-2-3" href="#__codelineno-2-3"></a><span class="w"> </span><span class="nt">title_map</span><span class="p">:</span>
</span><span id="__span-2-4"><a id="__codelineno-2-4" name="__codelineno-2-4" href="#__codelineno-2-4"></a><span class="w"> </span><span class="nt">Service Title</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">Desired Title</span>
</span></code></pre></div>
<p>Episodes are matched on their show title, Movies and Songs on their name. The remap is applied
after the title cache (so edits take effect without a cache reset) and before any <code>--enrich</code>
override (so an explicit enrich still wins).</p>
<p>It applies on the local <code>dl</code> path, the <code>import</code> command, and the remote client (<code>dl --remote</code>).
For remote services the <strong>client's</strong> <code>title_map</code> is applied to the titles returned by the server,
so you can rename titles for services you don't have installed locally. The server sends raw
titles and does not remap, leaving the final name fully under the client's control.</p>
<h3 id="service-class-conventions">Service Class Conventions<a class="headerlink" href="#service-class-conventions" title="Permanent link">&para;</a></h3>
<p>Each service directory under <code>unshackle/services/</code> exports a class extending
<code>unshackle.core.service.Service</code>. The class name must match the directory name (the service tag).</p>
<p>Key class variables (defined on <code>Service</code> or by service-level idiom):</p>
<ul>
<li><code>ALIASES: tuple[str, ...]</code> — alternative tags accepted on the CLI. Empty by default.</li>
<li><code>GEOFENCE: tuple[str, ...]</code> — ISO country codes the service is available in. Empty == no geofence.</li>
<li><code>TITLE_RE: str</code> — regex (with named groups, e.g. <code>(?P&lt;id&gt;...)</code>, <code>(?P&lt;type&gt;...)</code>) used by the
service to parse the CLI title argument. Service-level idiom, not declared on the base class.</li>
<li><code>NO_SUBTITLES: bool</code> — service-level idiom indicating the service has no subtitle tracks.</li>
</ul>
<p><code>self.*</code> helpers available after <code>super().__init__(ctx)</code>:</p>
<ul>
<li><code>self.session</code> — pre-configured HTTP session (<code>requests.Session</code>, or <code>RnetSession</code> when TLS
impersonation is active). Cookies, headers, proxies pre-applied.</li>
<li><code>self.config</code> — merged service config (per-service <code>config.yaml</code> plus the <code>services.&lt;TAG&gt;</code> block
from <code>unshackle.yaml</code>).</li>
<li><code>self.log</code> — <code>logging.Logger</code> named for the service class.</li>
<li><code>self.cache</code> — generic <code>Cacher</code> for arbitrary key/value persistence.</li>
<li><code>self.title_cache</code> — specialized <code>TitleCacher</code> for title metadata.</li>
<li><code>self.track_request</code> — <code>TrackRequest</code> built from CLI flags. Fields: <code>codecs: list[Video.Codec]</code>,
<code>ranges: list[Video.Range]</code> (defaults to <code>[SDR]</code>), <code>best_available: bool</code>. Services may
read or rewrite these (e.g. force HEVC for HDR ranges).</li>
<li><code>self.credential</code> — set during <code>authenticate()</code>; <code>None</code> if cookies-only.</li>
<li><code>self.current_region</code> — lowercase ISO country code from proxy/geolocation, or <code>None</code>.</li>
<li><code>self.request_input(prompt: str) -&gt; str</code> — interactive prompt. Falls through to <code>input()</code>
locally; under <code>serve</code>, the attached <code>InputBridge</code> relays the prompt to the remote client.</li>
</ul>
<p>Driving CLI flags (parsed into <code>self.track_request</code>):</p>
<ul>
<li><code>-v</code> / <code>--vcodec</code> — comma-separated <code>Video.Codec</code> list (e.g. <code>H264,H265</code>).</li>
<li><code>-a</code> / <code>--acodec</code> — comma-separated audio codec list.</li>
<li><code>-r</code> / <code>--range</code> — comma-separated <code>Video.Range</code> list (<code>SDR</code>, <code>HDR10</code>, <code>HDR10+</code>, <code>DV</code>,
<code>HYBRID</code>). Defaults to <code>[SDR]</code>.</li>
<li><code>-q</code> / <code>--quality</code> — resolution list.</li>
<li><code>--vbitrate-range</code> / <code>--abitrate-range</code> — <code>MIN-MAX</code> kbps windows.</li>
</ul>
<hr />
<h2 id="credentials-dictstr-strlistdict">credentials (dict[str, str|list|dict])<a class="headerlink" href="#credentials-dictstr-strlistdict" title="Permanent link">&para;</a></h2>
<p>Specify login credentials to use for each Service, and optionally per-profile.</p>
<p>For example,</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">EXAMPLE</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">jane@example.tld:LoremIpsum100</span><span class="w"> </span><span class="c1"># directly</span>
</span><span id="__span-3-2"><a id="__codelineno-3-2" name="__codelineno-3-2" href="#__codelineno-3-2"></a><span class="nt">EXAMPLE2</span><span class="p">:</span><span class="w"> </span><span class="c1"># or per-profile, optionally with a default</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">default</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">jane@example.tld:LoremIpsum99</span><span class="w"> </span><span class="c1"># &lt;-- used by default if -p/--profile is not used</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">james</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">james@example.tld:TheFriend97</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">john</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">john@example.tld:LoremIpsum98</span>
</span><span id="__span-3-6"><a id="__codelineno-3-6" name="__codelineno-3-6" href="#__codelineno-3-6"></a><span class="nt">EXAMPLE3</span><span class="p">:</span><span class="w"> </span><span class="c1"># the `default` key is not necessary, but no credential will be used by default</span>
</span><span id="__span-3-7"><a id="__codelineno-3-7" name="__codelineno-3-7" href="#__codelineno-3-7"></a><span class="w"> </span><span class="nt">john</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">john@example.tld:SecretPassword123</span>
</span></code></pre></div>
<p>The value should be in string form, i.e. <code>john@example.tld:password123</code> or <code>john:password123</code>.
Any arbitrary values can be used on the left (username/password/phone) and right (password/secret).
You can also specify these in list form, i.e., <code>["john@example.tld", ":PasswordWithAColon"]</code>.</p>
<p>If you specify multiple credentials with keys like the <code>EXAMPLE2</code> and <code>EXAMPLE3</code> example above, then you should
use a <code>default</code> key or no credential will be loaded automatically unless you use <code>-p/--profile</code>. You
do not have to use a <code>default</code> key at all.</p>
<p>Please be aware that this information is sensitive and to keep it safe. Do not share your config.</p>
<hr />
<h2 id="firefox_cookies-dict">firefox_cookies (dict)<a class="headerlink" href="#firefox_cookies-dict" title="Permanent link">&para;</a></h2>
<p>Automatically extract cookies from your running Firefox installation instead of maintaining a
<code>cookies/&lt;SERVICE&gt;.txt</code> file. Configured as a top-level dict keyed by service tag; each value is
a settings dict for that service.</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">firefox_cookies</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">EXAMPLE</span><span class="p">:</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">hosts</span><span class="p">:</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="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">example.com</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="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">api.example.com</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="nt">local_storage</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"># optional, default false</span>
</span></code></pre></div>
<p><strong>Fields:</strong></p>
<ul>
<li><code>hosts</code> — list of host patterns to match against Firefox's cookie store. Each pattern must be at
least 3 characters. A pattern matches the exact host <strong>and</strong> any dot-suffix subdomain
(e.g. <code>example.com</code> also matches <code>sub.example.com</code> and <code>.example.com</code>).</li>
<li><code>local_storage</code> — when <code>true</code>, also harvest <code>localStorage</code> entries for the listed hosts from
Firefox's <code>webappsstore.sqlite</code>. Default: <code>false</code>.</li>
</ul>
<p>At download time unshackle picks the <strong>most recently modified</strong> valid Firefox profile (the one
whose <code>cookies.sqlite</code> has the latest mtime), copies the database to a restricted temporary
directory (<code>0700</code>), and reads cookies from it without touching the live profile. If extraction
returns no cookies or fails for any reason, it falls back silently to the normal file-based cookie
(<code>cookies/&lt;SERVICE&gt;.txt</code> or <code>cookies/&lt;SERVICE&gt;/&lt;profile&gt;.txt</code>).</p>
<p><strong>Notes:</strong></p>
<ul>
<li>Firefox must not have an exclusive write lock on the database at the moment of extraction (i.e.
Firefox may be open — the extractor copies both <code>cookies.sqlite</code> and its WAL file to capture any
unflushed writes).</li>
<li><code>local_storage: true</code> is only needed for services that store auth tokens in the browser's
localStorage rather than in HTTP cookies.</li>
<li>The feature is implemented in <code>core/utils/firefox_cookie_extractor.py</code>; the fallback logic lives
in <code>dl.get_cookie_jar</code> (<code>commands/dl.py</code>).</li>
</ul>
<hr />
<h2 id="tmdb_api_key-str">tmdb_api_key (str)<a class="headerlink" href="#tmdb_api_key-str" title="Permanent link">&para;</a></h2>
<p>API key for The Movie Database (TMDB). This is used for tagging downloaded files with TMDB,
IMDB and TVDB identifiers. Leave empty to disable automatic lookups.</p>
<p>To obtain a TMDB API key:</p>
<ol>
<li>Create an account at <a href="https://www.themoviedb.org/">https://www.themoviedb.org/</a></li>
<li>Go to <a href="https://www.themoviedb.org/settings/api">https://www.themoviedb.org/settings/api</a> to register for API access</li>
<li>Fill out the API application form with your project details</li>
<li>Once approved, you'll receive your API key</li>
</ol>
<p>For example,</p>
<div class="language-yaml highlight"><pre><span></span><code><span id="__span-5-1"><a id="__codelineno-5-1" name="__codelineno-5-1" href="#__codelineno-5-1"></a><span class="nt">tmdb_api_key</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">cf66bf18956kca5311ada3bebb84eb9a</span><span class="w"> </span><span class="c1"># Not a real key</span>
</span></code></pre></div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Keep your API key secure and do not share it publicly. This key is used by the <code>core/providers/tmdb.py</code> metadata provider to fetch metadata from TMDB for proper file tagging and ID enrichment.</p>
</div>
<hr />
<h2 id="simkl_client_id-str">simkl_client_id (str)<a class="headerlink" href="#simkl_client_id-str" title="Permanent link">&para;</a></h2>
<p>Client ID for SIMKL API integration. SIMKL is used as a metadata source for improved title matching and tagging,
especially when a TMDB API key is not configured.</p>
<p>To obtain a SIMKL Client ID:</p>
<ol>
<li>Create an account at <a href="https://simkl.com/">https://simkl.com/</a></li>
<li>Go to <a href="https://simkl.com/settings/developer/">https://simkl.com/settings/developer/</a></li>
<li>Register a new application to receive your Client ID</li>
</ol>
<p>For example,</p>
<div class="language-yaml highlight"><pre><span></span><code><span id="__span-6-1"><a id="__codelineno-6-1" name="__codelineno-6-1" href="#__codelineno-6-1"></a><span class="nt">simkl_client_id</span><span class="p">:</span><span class="w"> </span><span class="s">&quot;your_client_id_here&quot;</span>
</span></code></pre></div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>While optional, having a SIMKL Client ID improves metadata lookup reliability. SIMKL serves as an alternative or fallback metadata source to TMDB. This is used by the <code>core/providers/simkl.py</code> metadata provider.</p>
</div>
<hr />
<h2 id="ipinfo_api_key-str">ipinfo_api_key (str)<a class="headerlink" href="#ipinfo_api_key-str" title="Permanent link">&para;</a></h2>
<p>Optional API token for <a href="https://ipinfo.io">ipinfo.io</a>. When set, unshackle uses the free authenticated <strong>Lite</strong> endpoint (<code>https://api.ipinfo.io/lite/me</code>), which has substantially higher rate limits than the anonymous endpoint and returns richer fields (ASN, organization name, continent). Leave empty to use the anonymous ipinfo.io endpoint, with <a href="https://ip-api.in">ip-api.in</a> as a final fallback.</p>
<p>To obtain an ipinfo.io token:</p>
<ol>
<li>Sign up for a free account at <a href="https://ipinfo.io/signup">https://ipinfo.io/signup</a></li>
<li>Copy the token from your dashboard</li>
</ol>
<p>For example,</p>
<div class="language-yaml highlight"><pre><span></span><code><span id="__span-7-1"><a id="__codelineno-7-1" name="__codelineno-7-1" href="#__codelineno-7-1"></a><span class="nt">ipinfo_api_key</span><span class="p">:</span><span class="w"> </span><span class="s">&quot;12a3b45cd678ef&quot;</span><span class="w"> </span><span class="c1"># Not a real key</span>
</span></code></pre></div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>The token is only ever sent to <code>api.ipinfo.io</code> as a per-request <code>Authorization</code> header — it is never attached to your session for service requests. Used by <code>core/utils/ip_info.py</code> for region detection and proxy verification.</p>
</div>
<hr />
<h2 id="title_cache_enabled-bool">title_cache_enabled (bool)<a class="headerlink" href="#title_cache_enabled-bool" title="Permanent link">&para;</a></h2>
<p>Enable/disable caching of title metadata to reduce redundant API calls. Default: <code>true</code>.</p>
<hr />
<h2 id="title_cache_time-int">title_cache_time (int)<a class="headerlink" href="#title_cache_time-int" title="Permanent link">&para;</a></h2>
<p>Cache duration in seconds for title metadata. Default: <code>1800</code> (30 minutes).</p>
<hr />
<h2 id="title_cache_max_retention-int">title_cache_max_retention (int)<a class="headerlink" href="#title_cache_max_retention-int" title="Permanent link">&para;</a></h2>
<p>Maximum retention time in seconds for serving slightly stale cached title metadata when API calls fail.
Default: <code>86400</code> (24 hours). Effective retention is <code>min(title_cache_time + grace, title_cache_max_retention)</code>.</p>
<hr />
<h2 id="debug-bool">debug (bool)<a class="headerlink" href="#debug-bool" title="Permanent link">&para;</a></h2>
<p>Enable structured JSON debug logging for troubleshooting and service development. Default: <code>false</code>.</p>
<p>When enabled (via config or the <code>--debug</code> CLI flag):
- Creates JSON Lines (<code>.jsonl</code>) log files with complete debugging context
- Logs: session info, CLI params, service config, CDM details, authentication, titles, tracks metadata,
DRM operations, vault queries, errors with stack traces
- File location: <code>logs/unshackle_debug_{service}_{timestamp}.jsonl</code></p>
<hr />
<h2 id="debug_keys-bool">debug_keys (bool)<a class="headerlink" href="#debug_keys-bool" title="Permanent link">&para;</a></h2>
<p>Log decryption keys in debug logs. Default: <code>false</code>.</p>
<p>When <code>true</code>, actual content encryption keys (CEKs) are included in debug log output. Useful for
debugging key retrieval and decryption issues.</p>
<div class="admonition note">
<p class="admonition-title">Security note</p>
<p>Passwords, tokens, cookies, and session tokens are always redacted regardless
of this setting. Only content keys (<code>content_key</code>, <code>key</code> fields) are affected. Key IDs (<code>kid</code>),
key counts, and other metadata are always logged.</p>
</div>
<hr />
</article>
</div>
<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="../CREATING_A_SERVICE/" class="md-footer__link md-footer__link--prev" aria-label="Previous: Creating a Service">
<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">
Creating a Service
</div>
</div>
</a>
<a href="../DOWNLOAD_CONFIG/" 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.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.79ae519e.min.js"></script>
</body>
</html>