Commit Graph
875 Commits
Author SHA1 Message Date
imSp4rky e804d09f0a feat(dl): add --cdm to pin one CDM device for a run
Overrides the cdm config mapping (and its quality/DRM sub-entries) for the whole run; the REST API cdm field now flows through the same param.
2026-08-24 16:37:48 -06:00
imSp4rky 8c43250c9b feat(dl): add --no-attachments to skip cover art and subtitle fonts
Drops service attachments at track selection and skips the font attach pass; exposed as no_attachments in the REST dl params and documented.
2026-08-24 16:21:52 -06:00
imSp4rky 1f96a4bd78 fix(subtitle): keep WebVTT-only cue markup out of converted subtitles
Strip cue classes, <v>/<lang>/ruby and karaoke timestamps before conversion, decode entities for SRT/SSA/ASS, load pysubs2 as utf-8-sig, and route sdh_method: filter-subs through convert_before_strip instead of raising.
2026-08-24 15:55:06 -06:00
imSp4rky d4690e5c6b fix(downloader): bound requests after a cut and stop retry nesting
Request 4 MiB sub-ranges once a host cuts a body, skip the session's own urllib3 Retry inside download(), fail the ranged path at once on a 4xx, and cap resumes at 50 of 1 MiB each. Adds a deny fault profile.
2026-08-24 15:10:36 -06:00
imSp4rky e5e1ce14c6 fix(downloader): keep retrying while a cut connection makes progress
Reset the attempt budget when a resumed cut delivers bytes, close the stream in a finally, skip the ranged path for a finished file, and add a throttle-cut profile to fault_server.
2026-08-24 14:32:03 -06:00
imSp4rky d9d6115054 style(cli): align help output at column 5 and title the dl panel Services 2026-08-24 13:28:56 -06:00
imSp4rky 0a68cc2452 fix(services): match service aliases without case
Uppercase entries in ALIASES never resolved, because get_tag lowercased the input but not the alias. Match real tags first so a service's own tag cannot be taken by another service's alias.
2026-08-24 11:56:46 -06:00
imSp4rky 87cdb30229 docs(example): show drm_preference pinning for dual-PSSH manifests 2026-08-23 16:47:15 -06:00
imSp4rky 5cece9672a fix(dl): accept a clamped 206 and report audio-description-only titles
RFC 9110 clamps a range end past the resource to its last byte; the guard
rejected that valid response. The descriptive-audio filter also had no
emptiness check, so a title with only described audio failed with a
misleading missing-language error.
2026-08-23 16:32:30 -06:00
imSp4rky 1aa6315dc3 feat(drm): let a track pin the DRM system it licenses with
Adds Track.drm_preference so a service can pin a track to Widevine or
PlayReady when a manifest advertises both but only one will license it.
Honoured in DASH/HLS selection, the dl licence path and the remote/API
track round-trip. Also fixes quality-keyed CDM maps sending audio to the
default entry, and a licence callable binding the CDM before the swap.
2026-08-23 16:32:23 -06:00
imSp4rky d8739b3561 feat(dl): add --require-audio/--require-video and --warn-only alias
Gate a title on audio or video languages that must exist, independent of what -l/-al/-vl select. --require-subs joins the same gate: its --s-lang conflict and download-all side effect are gone, so -sl now decides what to keep. Requiring a language that is also excluded fails at parse time.
2026-08-23 12:24:45 -06:00
imSp4rky 2d005fcc1c fix(api): guard two more Windows errno 13 paths in the serve layer 2026-08-21 17:24:55 -06:00
imSp4rky 36add10e66 fix(api): survive Windows errno 13 on the job progress file 2026-08-21 17:20:15 -06:00
imSp4rky a4be2cd23a fix(music): remux songs into the container of their codec
A song skips the muxer, so the decrypted fragmented MP4 was the delivered file: its header states a length of zero and FLAC in an MP4 is not a FLAC stream, so playback stopped early and tagging failed.
2026-08-21 14:00:04 -06:00
imSp4rky 79cabc9a70 docs(dev): correct get_chapters guidance on markers at timestamp 0 2026-08-21 10:46:03 -06:00
imSp4rky 5cdba70760 docs: widen supported shaka-packager range to 2.6.1 or >= 3.10.0 2026-08-20 18:50:03 -06:00
imSp4rky aa42c6b805 test(core): cover session pool growth, DRM locks, playlist encoding, and hybrid L6 2026-08-20 13:59:00 -06:00
imSp4rky 6670b17d5b perf(hybrid): reuse DV-side files across resolutions, trim the RPU chain, fix L6 fallback
Extract the DV stream and RPU once per title, skip the Level 6 edit when the RPU already holds the values, sample cropdetect in parallel with fewer frames, and let inject-rpu write the per-resolution output directly. Fill Level 6 MaxCLL/MaxFALL from the base-layer SEI when the RPU says unknown: the ffprobe probe read stream side data that raw HEVC never carries, so it always returned the defaults. Read the L6 block from dovi_tool's JSON instead of the summary text, which rounded the mastering display minimum.
2026-08-20 13:44:50 -06:00
imSp4rky 3312c218df perf(dl): overlap hybrid builds with muxing, tag in the mux thread, preload DRM in parallel
Submit standalone mux tasks largest-first as soon as they are enqueued and build hybrid tracks while they run, each muxed from its own pool slot when ready; run mkvpropedit inside the mux thread instead of a serial pass at the end; load per-track DRM from a thread pool; decode m3u8 playlists as UTF-8 instead of letting requests run chardet over them.
2026-08-20 12:41:04 -06:00
imSp4rky 537a1dc973 perf(dl): parallelise mux, licensing, and vault lookups; size the shared pool
Grow the service session pool to downloads * workers before track downloads, run mkvmerge jobs concurrently (muxing.concurrency, default 4), lock DRM preparation per key set instead of globally, and query local vaults first then remote vaults together.
2026-08-20 11:24:12 -06:00
imSp4rky 8b10b793e2 docs: phase 2 of the prose style across docs and docstrings 2026-08-19 20:59:09 -06:00
imSp4rky 66971230c3 docs: apply simplified technical english across docs and docstrings. 2026-08-19 16:31:06 -06:00
imSp4rky 4177cb2267 fix(hls): keep ad-filtered segments out of DRM key state 2026-08-19 14:39:09 -06:00
imSp4rky 29d0828c33 style: clean up prose 2026-08-19 13:45:58 -06:00
imSp4rky 54adb82746 fix(vaults): look tables up by the name the vault stores
get_services() normalised table names through Services.get_tag() and then handed the result back as an identifier, so kv copy and sync skipped any table whose name differed in case or matched an alias. Yield stored names, and resolve tables case-insensitively.
2026-08-19 12:11:44 -06:00
imSp4rky c4c49ea672 fix(cli): work around rich-click's patched click classes 2026-08-19 10:39:41 -06:00
imSp4rky 4aa217c206 refactor(console): style env listings like the rich-click help screens 2026-08-18 23:13:48 -06:00
imSp4rky ca543b3a14 docs(services): add MUSIC_EXAMPLE reference service 2026-08-18 15:07:23 -06:00
imSp4rky 68c7d95173 refactor(music)!: make Song an ordinary Title on the generic path
Delete the dead grouped-download block, the planner, and the music service hooks; Song now flows through the one download loop, gets tagged via tag_file, and answers -w with {disc}x{track} keys.

BREAKING CHANGE: GROUP_AUDIO_DOWNLOADS, get_music_track_options and get_music_collection_label are gone. A music service returns one Audio track per quality and lets the framework choose.
2026-08-18 15:05:30 -06:00
imSp4rky a4a385e5aa test(post-scripts): compare paths via Path so music hook tests pass on windows 2026-08-18 08:30:32 -06:00
imSp4rky 89acfab279 feat(dl): run user post-download scripts with metadata variables
New post_scripts config and repeatable --postscript flag run a command per output, season/album folder, or run, substituting filename-template variables into pre-tokenized argv. The REST API rejects hook commands.

Closes #150
2026-08-18 08:26:14 -06:00
imSp4rky 511f96d8db docs: strip non-essential comments, fold key facts into docstrings 2026-08-16 23:32:02 -06:00
imSp4rky 66bcbe9377 test(core): skip download integration tests when ffprobe is absent 2026-08-16 22:32:33 -06:00
imSp4rky 30b9cb06af Merge branch 'feat/downloader-speed' into dev 2026-08-16 22:19:35 -06:00
imSp4rky 42718cbd99 fix(titles): drop folder {year?} when it repeats the dated season label
Dated episodes turn the season folder into the air year, so a folder template's {year?} rendered the same year twice (Title.2025.2025).
2026-08-16 22:01:12 -06:00
imSp4rky 619c86cd10 feat(downloader): resume failed downloads from completed segments across runs
Fingerprint-gated reuse of atomically-published segment files (DASH/ISM/HLS) behind a continue_downloads config option and one-off dl --continue-downloads flag.
2026-08-16 19:38:06 -06:00
imSp4rky dd9dafef91 fix(downloader): harden ranged reads, teardown and multiprocess sessions
Validates the 206 range end, bounds the DASH collapse, and preserves cookie domains and pool size in spawned children.
2026-08-16 17:07:28 -06:00
imSp4rky 7f73d9c469 fix(downloader): validate Content-Range before placing 206 bytes
A 206 was trusted from its status alone, so a server answering a different range than requested silently corrupted output.
2026-08-16 14:23:39 -06:00
imSp4rky e3c1ce3511 refactor(tests): drop leading underscores from test helper functions
Completes the core underscore sweep for the test files this branch added; make_ctx/make_track/seg_urls avoid shadowing locals.
2026-08-16 12:52:36 -06:00
imSp4rky d52d24d933 fix(api): pass adaptive_workers and download_processes to dl.result
Both became required parameters of dl.result() when adaptive worker scaling
landed, but the API path calls it directly and never supplied them, so every
API-initiated download raised TypeError. Defaults match the click options.
2026-08-16 12:43:52 -06:00
imSp4rky ee9d3edfe3 Merge branch 'dev' into feat/downloader-speed
# Conflicts:
#	unshackle/core/api/download_manager.py
#	unshackle/core/downloaders/requests.py
#	unshackle/core/manifests/dash.py
#	unshackle/core/session.py
#	unshackle/core/utils/webvtt.py
2026-08-16 12:43:01 -06:00
imSp4rky 1af77d395d fix(downloaders): submit segments in a window so progress can drain
Submitting every segment up front convoyed on ThreadPoolExecutor's process-global lock, starving the event drain so per-track progress bars only advanced once the download had finished.
2026-08-16 11:06:17 -06:00
imSp4rky 21d5f1c5e1 refactor(core)!: drop leading underscores from internal definitions
Renames 314 defs and 41 module/class-level constants. Keeps 11 names underscored where the stripped form collides in scope, plus 5.5.0 shims for the three symbols external service repos call.
2026-08-15 22:07:41 -06:00
imSp4rky db4f0b39f9 refactor(console): route interactive prompts through a themed helper
Adds prompt_user() and uses it for local, remote, and Proton VPN input. Replaces click.prompt on the remote auth path, which ignored the theme and overlapped active Live displays. Remote auth now exits on EOF instead of POSTing an empty answer and spinning the poll loop.
2026-08-15 18:13:05 -06:00
imSp4rky a6cb0231d5 chore: bump dev version to 5.5.0 2026-08-15 16:00:14 -06:00
imSp4rky 0576d9d03c chore(release): 5.4.0 5.4.0 2026-08-15 15:54:07 -06:00
imSp4rky 9a2f7a6661 fix(kv): search remote vaults that cannot list their tables
Probe locally installed service tags in parallel when a vault has no table listing, and report every vault holding the KID instead of the first hit.
2026-08-15 15:09:42 -06:00
imSp4rky e1fbd11678 fix(dash): resolve representations by adaptation set, not id alone
Representation ids are only unique within an AdaptationSet, so re-finding a track by id could download a sibling set's stream (audio description in place of dialog). Applies to download_track and extract_dash.
2026-08-15 14:26:45 -06:00
imSp4rky 415a195957 test(serve): strip ANSI from CLI output before asserting error message 2026-08-13 16:33:08 -06:00
imSp4rky db9ec3e334 feat(cli): add named color themes and rich-formatted help
Render all click help through rich-click, themed by a new `theme` config key (9 palettes + aliases, previewable via `unshackle env theme`), and show service docstrings in local and remote `dl <TAG> -h`.
2026-08-13 16:25:14 -06:00