Add support for `{randomchar_N}` placeholders in Netflix Android `esn_map` values and generate those segments at runtime. Reuse a cached ESN only when it matches the derived template pattern, is Android-typed, and is not expired; otherwise regenerate and refresh the cache.
This keeps static ESN mappings working as before while enabling dynamic ESN templates (e.g., system_id `7110`) to avoid fixed identifiers and keep ESNs valid per template.
Update Netflix manifest request construction to better match current
Widevine-on-Chrome behavior by:
- setting top-level and param `clientVersion` to `9999999`
- sending `challenge` only for Chrome Widevine requests
- removing hardcoded device/platform fields from params
Also refresh Android TV ESN mappings in config by replacing ESN `7110`
and adding ESN `16401` for Hisense devices to improve request validity.
Add `UserAuthentication.UserIDToken()` to build MSL user auth payloads
for token-based Netflix authentication flows.
Extend MSL message handling to be more flexible by:
- allowing custom HTTP headers in `send_message()`
- adding `unwrap_result` to `send_message()`, `parse_message()`, and
`decrypt_payload_chunks()` so callers can receive either full payload
data or only `result`
Also lower key/KID and payload logging from `info` to `debug` to reduce
noisy and sensitive runtime logs while keeping diagnostics available.
Ensure episode downloads use a consistent non-scene layout when
`scene_naming` is disabled by:
- adding a sanitized series-title directory before season/episode folders
for sidecars, sample-based paths, and muxed outputs
- updating `Episode.get_filename()` to return `Season XX` for folder names
in non-scene mode
- generating non-scene episode file names as
`Title SXXEXX - Episode Name`
- adding token append helpers to avoid duplicate/empty naming tokens
This keeps output paths predictable across download stages and prevents
naming inconsistencies or duplicated suffixes.fix(dl): normalize non-scene episode folder/file naming
Ensure episode downloads use a consistent non-scene layout when
`scene_naming` is disabled by:
- adding a sanitized series-title directory before season/episode folders
for sidecars, sample-based paths, and muxed outputs
- updating `Episode.get_filename()` to return `Season XX` for folder names
in non-scene mode
- generating non-scene episode file names as
`Title SXXEXX - Episode Name`
- adding token append helpers to avoid duplicate/empty naming tokens
This keeps output paths predictable across download stages and prevents
naming inconsistencies or duplicated suffixes.
Add dedicated non-scene filename sanitization for movies to produce cleaner, filesystem-safe names when `scene_naming` is disabled. The new logic:
- optionally transliterates unicode based on `unicode_filenames`
- removes combining marks/diacritics and disallowed punctuation
- normalizes separators and extra whitespace
Also update movie name construction to explicitly format `Name (Year)` and append a trailing ` -` for non-scene naming before metadata tokens, improving readability and consistency.
Update default config values in `unshackle.yaml` to match non-scene/local usage:
- disable `scene_naming` by default
- comment out default `tag`
- change downloads directory to `Downloads`feat(movie): improve non-scene filename sanitization
Add dedicated non-scene filename sanitization for movies to produce cleaner, filesystem-safe names when `scene_naming` is disabled. The new logic:
- optionally transliterates unicode based on `unicode_filenames`
- removes combining marks/diacritics and disallowed punctuation
- normalizes separators and extra whitespace
Also update movie name construction to explicitly format `Name (Year)` and append a trailing ` -` for non-scene naming before metadata tokens, improving readability and consistency.
Update default config values in `unshackle.yaml` to match non-scene/local usage:
- disable `scene_naming` by default
- comment out default `tag`
- change downloads directory to `Downloads`
Handle Netflix ESN cache values more defensively to avoid key/type errors and
stale reuse by validating cache shape, cache expiry, and device type before
reusing values. Also log the final ESN safely when cache data is not a dict.
Alias `pywidevine.Cdm` to `WidevineCDM` and use it in DRM system detection so
Widevine instances are identified correctly.
Also include related config updates: add ESN map entry for system ID `12063`,
ignore `binaries/`, and refresh local runtime defaults in `unshackle.yaml`.fix(netflix): harden ESN cache checks and Widevine type test
Handle Netflix ESN cache values more defensively to avoid key/type errors and
stale reuse by validating cache shape, cache expiry, and device type before
reusing values. Also log the final ESN safely when cache data is not a dict.
Alias `pywidevine.Cdm` to `WidevineCDM` and use it in DRM system detection so
Widevine instances are identified correctly.
Also include related config updates: add ESN map entry for system ID `12063`,
ignore `binaries/`, and refresh local runtime defaults in `unshackle.yaml`.
Refine QC manifest profile selection so `l40` profiles are filtered out
only when the user requests **only** 720p, instead of whenever 720 is
included. This prevents unintended profile narrowing for mixed-quality
requests and default quality runs.
Also bump the Netflix client `platform` version from `138.0.0.0` to
`145.0.0.0` to keep manifest requests aligned with current expectations.fix(netflix): scope 720p QC filter to explicit 720 requests
Refine QC manifest profile selection so `l40` profiles are filtered out
only when the user requests **only** 720p, instead of whenever 720 is
included. This prevents unintended profile narrowing for mixed-quality
requests and default quality runs.
Also bump the Netflix client `platform` version from `138.0.0.0` to
`145.0.0.0` to keep manifest requests aligned with current expectations.