Each season's episodes continue from the previous season's last episode (S02E05 after a four-episode S01); also on the REST API. A --remote get_tracks refresh no longer resets season, number and part.
--generate-dv now takes an HDR10 base and measures L1 with FFmpeg when there is no usable HDR10+ metadata. -r HDR10 or -r HDR10P with the flag runs as a hybrid of that base alone, --sample shifts the DV RPU to match the base, and the REST API accepts generate_dv with any range.
The client dials the server's targets through the proxy (http/https CONNECT or SOCKS5, with login), with the same target checks and no direct fallback. tunnel-test takes --proxy too.
A tunnel closed with code 1000 is freed without the 60s grace, a shared: true API key counts tunnels per X-Client-Id, and --remote waits out Retry-After and a full tunnel cap with a countdown; responses carry X-RateLimit-* headers.
A missing -sl language now warns and continues, with or without --best-available. --require-subs counts a forced track only when selection keeps it, and a title with no track left is skipped instead of failing at mux.
BREAKING CHANGE: a missing -sl subtitle language no longer fails the run. Use --require-subs to fail on it.
load_xml strips namespaces without QName; services import on first use and proxy providers fetch their catalogue on first query; the font scan is skipped when no subtitle names a font and is cached per process.
Serve CPU -40% and track requests -28% on 20 MB manifests; CLI startup 2.7 s -> 1.2 s; --list 27-46% faster across six services tested.
/api/health needs X-Secret-Key but stays outside the rate limit. Only the admin key gets load_errors from /api/services, default error details no longer name the exception class, and a prepare signal replaces aiohttp's Server banner on every response while the CDM routes keep their own.
The export writes mediaexport content_periods per manifest; an import that re-fetches the MPD (no saved snapshot) drops the periods a service filtered.
A manifest snapshot module now saves and restores DASH/ISM parser state for --remote and export/import, so an import keeps the service's period filter without fetching the manifest.
cast_dl_params feeds ctx.params to dl() and dl.result() as on the CLI. A string lang value now returns 400 instead of splitting into letters, and -r accepts HDR10+.
standard_resolution() replaces the aspect-ratio logic in naming and is shared by -q matching, export names and progress/hybrid labels, so 1920x1088, 1916x1076, portrait and DCI sizes get standard names.
Smooth Streaming TTML times cues from each fragment's start; a whole track stacked into the first fragment. Also stop rebase_ttml failing on a track with no cues.
A kv vault argument can be the path to an SQLite vault file. With -s, kv copy reads the VAULT_TAG table and the plain-tag table into the VAULT_TAG table.
A VPN's synthetic DNS answer (fake-IP 198.18.0.0/15, 192.0.0.69) now works for a host name. An IP from the server, in any numeric form, must be public; dials to the client itself are closed.
Fix DASH SegmentTimeline negative @r and Pattern, TTML sidecar sets with no contentType, HLS CHANNELS identifiers and Dolby channel masks; test against 408 public DASH/HLS/ISM manifests.
A TUN-mode VPN with fake-IP DNS answers names from 198.18.0.0/15 or 2001:2::/48, which the LAN guard refused, so every dial failed. Refused hosts now warn once.
Set muxing.track_names to native to name an unnamed track in its own language (中文(繁體), Português (Portugal)) in place of English. The same script and region rules apply. --list, the muxed names and the REST API track_name follow the option. A test fixture resets the muxing options, so a local unshackle.yaml cannot change test results.
Unnamed tracks get the English language name (default region left out); subtitle tags gain the script their region implies (zh-TW -> zh-Hant-TW). Refs #169
The session message names the host, not the signed URL, and a segment that fails every attempt prints one line with no traceback. API job errors come from the exception.
kid_windows returns an empty map for an MP4 with no encrypted sample entry or protecting senc, so the key check judges, flags and copies nothing for it.
Judge a vault KID only on a file whose KID map holds it, tell remote vaults of a bad pair only once another key replaces it, and let the server CDM unflag a pair it returns; the server never flags a CDM-licensed pair. Log FFmpeg stderr on a failed check and name the missing CDM when none is set.
Basic stays first and Control D last; the rest follow their config key order. Geofence and proxy_map lookups go through pick_proxy and skip a provider that fails.
A value starting with - or @ applies to its region (fr: -datacamp); a value with @ after a server is a whole query (fr: fr-bod@195.86.24.103). A selector in --proxy still wins.
On NordVPN, Windscribe and Surfshark, `@<name>` keeps and `@-<name>` skips a hosting network; `@<ip>` and `@-<ip>` pick or skip one server. The connect line names the server, IP and network. Surfshark pins an IP through a loopback TLS port.
A reverse tunnel over the remote connection: the server's service traffic leaves through the client's own network. Only the client dials. Adds the tunnel-test command.
dl and search keep the typed --proxy value, so --proxy controld:ca --remote sends the server the Control D resolver, not this machine's forwarder. The Control D log names the location and masks the resolver ID in place of 127.0.0.1.
Relabel HEVC HDR10 tracks whose first fragment carries ST 2094-40 SEI as HDR10P, for dl, the REST API and remote sessions. Config key hdr10plus_probe (default true).
Builds per-scene L1 in unshackle (PQ mean, letterbox-aware) with a generate_dv_mode config (v29/v40/legacy); a failed hybrid no longer exits 0 with no video.