A licence that repeats vault keys no longer sends an empty InsertKeys, --cdm-only no longer logs "Cached N Keys to 0/0 Vaults", and a key two tracks both licensed counts once.
Remote sessions now carry -l/-vl/-al/-a/-fs under a nested dl_params, so services fetch the requested audio versions. Server-account tokens for non-default accounts move from default to the account name, so each account logs in once after upgrade.
A client with a local PlayReady device asked the server for a PlayReady licence on a service the server maps to a Widevine device. Both server_cdm routes now share one candidate list from one config lookup, report the system that licensed in drm_type, and the client adopts it.
A staged tag was only retried on the refresh tick or a job completion, so a service with steady remote sessions never swapped in. Session end, expiry and eviction now trigger a single-flight apply, the tick applies after the pull, and serve.services_staged_max_age swaps an overdue tag in even while busy.
RollingMerge takes the segment path and an append hook. ISM synthesises the init from segment 0 and converts PIFF per fragment; HLS qualifies only with one init, one key and no discontinuity. Both parsers check the merge reached every segment, and resume is decided per track.
Opt-in rolling merge for DASH video and audio: each contiguous segment is appended to the output as it lands, so the post-download "Merging" stage goes away. Decrypts the init segment eagerly when decrypt_segments is on, disables resume for the track, and skips subtitle tracks.
Build the failure context through the title's template builder with an empty MediaInfo, and blank season_episode, absolute and date in season mode. Document {part} and add a docs-to-code parity test.
Cache keys are now the path relative to the service cache dir without .json, so Cacher keys like session_web/<sha1> reach the remote session. The credential filter runs on every path segment, the suffix is appended rather than substituted, and both sides cap the map at 64 keys.
Map each KID to its fragments from the ciphertext moov/moof (tenc, seig, ISM duration clock) and decode up to three windows per KID that never cross into another KID, so a clear lead cannot hide a wrong key and only the failing KID is flagged. Decode every frame (wrong-key HEVC keyframes decode clean), re-judge mid-GOP starts on keyframes, time out every FFmpeg run, and refuse to store a flagged pair again in SQLite.
--acodec now lists its codecs in --help, --vcodec drops the duplicate entries, and the REST API derives its allowlists from the same types, so AC-4, DDP, VORB and sub_format "original" stop being rejected and H264 stops being silently dropped. Adds shell completion for --acodec and repairs MultipleChoice completion. Raises the click floor to 8.2.
Answered login prompts and uploaded cache now count as client auth; the client closes on exit and keeps the remote session alive during long downloads.
Regions in GEOBLOCK refuse the service and everything else is allowed. A hit stops the run with a region error instead of auto-proxying; the check also covers proxy exits and the remote-dl client region.
Manifest, licence and auth stay on --proxy; track, subtitle and attachment downloads use the second proxy. Also exposed as proxy_download on the REST download job with the same server_proxy gate. The download session now ignores HTTP(S)_PROXY and copies rnet cookies set by name.
The licence response lists KIDs a server vault supplied, the client proves them with the decode check, and a bad pair goes to the new session keys/bad route so the server flags its own row. Client vault keys go first over --remote, and the dashboard health warns when no SQLite vault can store flags.
Verify a vault-sourced key with an FFmpeg decode after decryption. On failure flag the KID:KEY locally with its source, restore the ciphertext, and retry through the remaining vaults and then the CDM.
Rules took only a scalar, so the documented list syntax raised LanguageTagError after the mux. Normalise every condition, treat an invalid tag as no match, guard the surrounding post-mux config reads, and let a rule match dual, multi and dubbed so a release can carry its own tag.
A dead proxy, or one that exits from this machine's IP, now fails with INVALID_PROXY instead of retrying every request; remote session create also builds the service off the event loop so a stuck check cannot block the server.
A service that picks its auth path in init could only check the server's cookies directory, so a client-sent jar was invisible and the service fell back to the wrong path. The ctx now carries cookies_supplied, and a malformed cookie blob answers 400 instead of 500.
The rebuild raised KIDNotFound for a header whose KID lives only in the manifest, the single-track route stripped the track's other headers, and the batch cache keyed on the first PSSH alone. Licensing failures now reach the client instead of only the server log.
extract_pssh_from_track returns the first PSSH only, so a track carrying one PlayReady object per header licensed fewer keys than the local path, which absorbs its siblings first. Relay batch licensing failures to the client too.
Only the first WRM header was read and licensed, so a manifest carrying several headers silently lost content keys. Collect KIDs from every header and license each distinct one until coverage is complete.
Batch and per-track remote licences read the vaults but never wrote back, so a --remote or import run kept nothing. Vault hits now replicate to the other vaults, and the server branch resolves keys under drm_lock like the local path.
Assert that an empty body of unknown length, a 206 with no complete length, and a 206 starting past the resume offset each fail instead of finalizing, and that every restart path spends an attempt.
Assert that verify, params, cert and auth reach a spawned child, and that a mounted adapter the child cannot reproduce falls back to the single-process path. Documents --download-processes in the CLI reference.
Assert that a probe is judged on the trailing tick, that a backoff is temporary and climbs back to the cap, and that a worker always finds its next segment staged. Documents adaptive-workers behaviour in the downloading guide.
Check a sequential download against the complete length whenever one is known, and settle the unknown-total case on the 416. An empty body of unknown length, a 206 with no complete length, and a 206 starting past the resume offset all passed the size checks before and were renamed into place. Four restart paths spent no attempt, so a host that always answered the same way cycled forever.
Handlers share one service instance, so a per-session lock keeps two requests out of it at once. Track threads merge and write job state under one lock, and the progress sink coalesces ticks that say the same thing.
One service needed session_id in its license call, which a near-duplicate of get_content_keys supplied behind a service-tag test. service_licence now passes each service only the arguments its own license function declares, so the duplicate and the branch are gone. The REST API license paths and the base PlayReady delegate get the same filtering, replacing their fixed argument set.
Two behaviour changes ride along: an empty license challenge now raises EmptyLicense for every service, not just the one, and a service that declares only challenge now receives a working call instead of a TypeError.
parse_channels rejected a three-figure layout, so a remote download crashed rebuilding the track from JSON. Add channel_total so --channels can compare either form.