/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.
A dual widevine/playready cdm entry now loads the device of the client's DRM system, for old clients too since they already send cdm_type. A new client hands a capped track to its own device for the track's DRM system, and raises the refusal only after its local vaults miss.
Vaults.add_keys and kv add skip null content keys instead of failing the batch; is_null_key moves to core.vault. A manifest snapshot restore has one 32 MiB inflate budget. Tests reset the speed limiter and config between runs.
Drop null keys from every licence, server and export source, not only Widevine. dl now finds remote sessions and imports through ServerKeySource instead of private fields.
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+.
Some packagers renumber AdaptationSet and Representation ids in every Period, so audio took video segments after the first Period. A match never crosses codec, size or language.
Use the service_name local in handle_single_server_cdm, assign service_data once in /api/services, and keep the TERMINAL_STATUSES comment on its constant.
Swagger now owns route registration instead of adding a second dead copy of every route; add json_body, enqueue_job, serialize_tracks and client_credential, build the serve middleware list once, and scan the users once per request.
Run session-tracks serialization, request cache IO, session cache dir removal (now outside the store lock), history reads and gzip over 1 MiB on worker threads; cache the per-key PBKDF2 namespace and key_id.
Session update events carry the new action as action_entry instead of the full log; access lines stay out of the log ring unless --debug. Job events build and redact their dict once, the progress interval matches the 0.5 s poll, and dashboard stats are serialized once.
Cache proxy provider catalogues (10 min), reuse vaults and CDMs across one batch licence call, and cache the health update check, /api/services entries and parsed service config.yaml.
The tool writes to a temporary file through run_step, which gains a timeout that hides the command line. A missing tool now raises instead of skipping.
A licence that builds a new key dict left decrypt_verified on the old one, so a falsely flagged key stayed flagged and a replacement key went unchecked. Both relicence passes now share one step that clears the flag.
A bad value now gets 400 INVALID_PARAMETERS at submit and the worker casts each option; a flat dl key such as quality or lang no longer fills a service option of the same name.
RnetCookieAdapter stores cookies by domain, path and name and sends path, secure and a leading-dot domain to rnet. It also takes server-rotated values, and worker children and track sessions get the cookies with their paths.
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.
Tracks with different KID sets still query the vaults at the same time, but wait for one licence lock and check the key cache again before they licence.
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.
DASH reads the AudioChannelConfiguration scheme (Dolby mask, CICP index incl. immersive layouts, channel count); HLS and ISM counts map 6/7/8 to 5.1/6.1/7.1.
Fix the bugs the type errors exposed (RnetSession.send body, HLS proxy session, title cache fallback, mux progress) and gate mypy in pre-commit, warn-only in CI.