433 Commits

Author SHA1 Message Date
0a820e6552 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.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.
2026-03-02 22:35:48 +07:00
8748ce8a11 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`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`
2026-03-02 19:42:53 +07:00
3e45f3efe7 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`.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`.
2026-03-02 17:29:32 +07:00
fb14f412d4 update .gitignore 2026-03-02 02:59:45 +07:00
27048d56ee 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.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.
2026-03-02 02:59:33 +07:00
66ba78a928 Update payload challenge 2026-03-02 02:58:56 +07:00
7c84cf67e6 Merge remote-tracking branch 'origin/update-unshackle' 2026-02-28 22:08:39 +07:00
Andy
cee7d9a75f fix(n_m3u8dl_re): pass all content keys for DualKey DRM decryption 2026-02-15 13:37:49 -07:00
Andy
bf9087a1ce chore(release): bump version to 3.0.0
BREAKING CHANGE: PlayReady users without explicit playready_devices no longer get access to all devices by default.

Key changes:
- feat(drm): add MonaLisa DRM support to core infrastructure
- feat(cdm): add remote PlayReady CDM support via pyplayready RemoteCdm
- feat(serve): add PlayReady CDM support alongside Widevine
- feat(gluetun): Gluetun VPN integration and Windscribe support
- feat(audio): codec lists and split muxing
- feat(tracks): prioritize Atmos audio tracks over higher bitrate non-Atmos
- feat(video): detect interlaced scan type from MPD manifests
- feat(cdm): normalize CDM detection for local and remote implementations
- fix(serve)!: make PlayReady users config consistently a mapping
- 50+ additional bug fixes across HLS/DASH, proxies, subtitles, and more
2026-02-15 13:04:42 -07:00
Andy
23cc351f77 feat(tracks): prioritize Atmos audio tracks over higher bitrate non-Atmos 2026-02-15 12:08:27 -07:00
Andy
132d3549f9 fix(main): update copyright year dynamically in version display 2026-02-11 16:01:33 -07:00
Andy
3ee554401a feat(HLS): improve audio codec handling with error handling for codec extraction 2026-02-10 08:34:54 -07:00
Andy
29a697a8e7 fix(tracks): close temp session and improve path type error 2026-02-08 20:04:22 -07:00
Andy
c5b063391c fix(serve): default PlayReady access to none
Remove unreachable fallback to all devices; if a user has no explicit playready_devices configured, the PlayReady subapp receives an empty list (secure-by-default).
2026-02-08 20:00:39 -07:00
Andy
5fa0b33664 revert(monalisa): pass key via argv again
Reverts the env/stdin key passing change introduced in 6c83790, since ML-Worker builds in use expect the key as argv[1].
2026-02-08 19:51:22 -07:00
Andy
5650c2b591 fix(hls): remove no-op encryption_data reassignment 2026-02-08 10:43:49 -07:00
Andy
5f49663ea8 fix(monalisa): harden wasm calls and license handling
- Validate _monalisa_context_alloc return and cleanup on init failure
- Derive deterministic KID when DCID missing to avoid collisions
- Ensure stackRestore always runs via try/finally in _ccall
- Log base64 decode failures without leaking license contents
- Add bounds/alignment checks for i32 memory writes
2026-02-08 10:39:23 -07:00
Andy
6b8a8ba8a8 feat(cdm): normalize CDM detection for local and remote implementations
Add unshackle.core.cdm.detect helpers to classify CDMs consistently across local and remote backends.

- Add is_playready_cdm/is_widevine_cdm for DRM selection across pyplayready, pywidevine, and wrappers

- Add is_remote_cdm/is_local_cdm/cdm_location so services can branch on CDM execution location

- Switch core DASH/HLS parsing, track DRM selection, and dl CDM switching away from brittle isinstance/DecryptLabs-only checks

- Make unshackle.core.cdm import-light via lazy __getattr__ so optional CDM deps are only imported when needed
2026-02-08 00:37:53 -07:00
Andy
b9fb928292 fix(service): redact proxy credentials in logs
Proxy URIs may contain embedded userinfo (username/password). Add a small sanitizer helper and use it for proxy mapping and proxy selection logs to avoid leaking credentials.
2026-02-07 20:36:25 -07:00
Andy
984a8b9efa fix(proxies): harden surfshark and windscribe selection 2026-02-07 20:34:31 -07:00
Andy
71adee4ec6 fix(api): log PSSH extraction failures 2026-02-07 20:29:53 -07:00
Andy
ee8f7cb650 docs(config): clarify sdh_method uses subtitle-filter 2026-02-07 20:29:31 -07:00
Andy
d576174f62 fix(naming): keep technical tokens with scene_naming off
Title filenames now include resolution/service/WEB-DL/codecs/HDR tokens in both modes; scene_naming only changes the spacer ('.' vs ' ').

Also avoid overwriting muxed outputs by disambiguating on collision (append codec suffix when needed, then a numeric suffix).
2026-02-07 20:24:32 -07:00
Andy
425b3764f4 fix(titles): avoid None/double spaces in HDR tokens
Ensure dynamic-range tokens use safe fallback when not in DYNAMIC_RANGE_MAP and append exactly one space-separated token without trailing/double spaces.
2026-02-07 19:55:45 -07:00
Andy
29f0e4eee8 fix(config): normalize playready_remote remote_cdm keys 2026-02-07 19:47:21 -07:00
Andy
44ea9a90a7 fix(titles): remove trailing space from HDR dynamic range label 2026-02-07 19:46:35 -07:00
Andy
96411e5d7d fix(hls): keep range offset numeric and align MonaLisa licensing
- Parse init section byterange offset as int to avoid string arithmetic bugs

- Wrap MonaLisa licensing in the same progress + error handling flow as Widevine/PlayReady
2026-02-07 19:44:23 -07:00
Andy
d404f213b1 fix(dl): avoid selecting all variants when multiple audio codecs requested
When --a-lang is specific (not best/all) and multiple codecs are requested via -a/--acodec, select only the best-bitrate track per codec per language (plus descriptive if --audio-description).

Blame: regression introduced by 939ca25 (fix(dl): keep descriptive and standard audio for requested langs).
2026-02-07 19:37:48 -07:00
Andy
6c83790834 fix(monalisa): avoid leaking secrets and add worker safety
- Pass ML-Worker key via env/stdin instead of argv to reduce exposure in process listings/logs.

- Add a hard timeout to the ML-Worker subprocess call and convert timeouts into DecryptionFailed errors.

- Make ticket bytes decoding defensive: try UTF-8, fall back to ASCII (base64), otherwise raise a descriptive ValueError.
2026-02-07 19:24:15 -07:00
Andy
a04f1ad4db fix(gluetun): stop leaking proxy/vpn secrets to process list
- Switch docker run to use a temporary --env-file instead of per-var -e flags\n- Ensure temp env file is always removed (best-effort overwrite + unlink)\n- Tighten _is_container_running to exact-name matching via anchored docker filter\n- Close requests.Session used for IP verification to release connections\n- Redact more secret-like env keys in debug logs\n
2026-02-07 19:22:13 -07:00
Andy
774b9ba96c fix(dl): preserve proxy_query selector (not resolved URI) 2026-02-07 19:09:29 -07:00
Andy
0b9a3a75f8 fix(serve)!: make PlayReady users config consistently a mapping
Ensure playready_config['users'] and API-only config always use a dict, even under --no-key, to avoid type mismatches.

Also stop implicitly granting PlayReady access by defaulting per-user 'playready_devices' to all devices; missing 'playready_devices' now defaults to an empty list and logs a warning including the user key.

BREAKING CHANGE: users without an explicit 'playready_devices' list no longer get access to all PlayReady devices by default.
2026-02-07 19:06:22 -07:00
Andy
c7d4a68cbf fix(aria2c): warn on config mismatch and wait for RPC ready
When ensure_started() is called while aria2c is already running, it now compares the requested proxy/max_workers against the values the process was started with and logs a warning if they differ (since the running process cannot be reconfigured in-place). Startup no longer uses a fixed sleep; instead it probes the JSON-RPC endpoint with a bounded retry loop (aria2.getVersion) and only proceeds once RPC is responsive, terminating the subprocess and raising on timeout.
2026-02-07 19:04:39 -07:00
Andy
4bc2e93d09 fix(dl): support snake_case keys for RemoteCdm
Use safe get() fallbacks for RemoteCdm config keys and default security_level to 3000 to avoid KeyError when snake_case is used.
2026-02-07 19:00:12 -07:00
Andy
de41395a45 fix(dl): invert audio codec suffixing when splitting 2026-02-07 18:56:30 -07:00
Andy
e50dd3f2bc Merge branch 'dev' of https://github.com/unshackle-dl/unshackle into dev
# Conflicts:
#	CHANGELOG.md
2026-02-07 18:47:23 -07:00
Andy
6f3aafebc5 docs(changelog): update cliff config and regenerate changelog
merge commit filtering, deduplication, granular chore parsing, and regenerate CHANGELOG.md using git-cliff.
2026-02-07 18:46:43 -07:00
Andy
a66234190c docs(changelog): complete 2.4.0 notes 2026-02-07 18:05:03 -07:00
Andy
62aa85c666 chore(release): bump version to 2.4.0 2026-02-07 14:52:54 -07:00
Andy
03c309303c fix(downloader): restore requests progress for single-url downloads 2026-02-06 23:34:15 -07:00
Andy
ace89760e7 fix(hls): finalize n_m3u8dl_re outputs
- Add a small helper to move N_m3u8DL-RE final outputs into the expected temp path (preserve actual suffix) and keep subtitle codec consistent with the produced file.
- Skip generic HLS segment merging when N_m3u8DL-RE is in use to avoid mixing in sidecar files and reduce Windows file-lock issues.
- Harden segmented WebVTT merging to avoid IndexError when caption segment indexes exceed the provided duration list.
2026-02-06 16:17:06 -07:00
Andy
3eede98376 Merge branch 'fix/hybrid-temp-cleanup' 2026-02-06 11:16:44 -07:00
Andy
57918cd2a3 fix(dl): always clean up hybrid temp hevc outputs 2026-02-06 11:15:05 -07:00
Sp5rky
001d15e651 Merge pull request #75 from CodeName393/Remove-hybrid-havc-temp-file
Remove hybrid havc temp file
2026-02-06 11:14:45 -07:00
Andy
2308644374 chore(api): remove remote services 2026-02-06 10:46:39 -07:00
CodeName393
8f0b9eafd7 Remove hybrid havc temp file
Add a hybrid track to the track processing list to fix the problem that the hybrid-processed hevc file remains in the temp folder.
2026-02-06 17:53:48 +09:00
Andy
939ca25c5b fix(dl): keep descriptive and standard audio for requested langs
When --audio-description is set, keep standard selections and include descriptive tracks for requested languages, including --a-lang with orig and best selection paths.

Fixes #72
2026-02-05 12:57:52 -07:00
Sp5rky
58903c7b14 Merge pull request #70 from CodeName393/Missing-HLS-Curl-Session-Processing
Fix Missing HLS Curl Session Processing
2026-02-05 12:43:27 -07:00
CodeName393
3fa4a81a39 Fix Missing HLS Curl Session Processing 2026-02-05 19:25:51 +09:00
Andy
b16610ac63 fix(progress): bind per-track bars and force terminal completion 2026-02-04 12:55:02 -07:00