Commit Graph
895 Commits
Author SHA1 Message Date
imSp4rky e3f4e52444 feat(serve): add --quiet mode and developer dashboard API
Headless serve with plain stderr logging; /api/dashboard/* (status, sessions, jobs, logs, SSE/poll events) behind a separate serve.dashboard.key.
2026-08-28 13:18:41 -06:00
imSp4rky c49fccf3b5 fix(remote): resolve service names against the remote server
Remote mode resolved names with the local alias table and built an empty stub for any unknown tag, so an unentitled service showed a blank help page. Resolve against the server's tags and aliases, and reject unknown names with the list the server does offer.
2026-08-28 10:54:21 -06:00
imSp4rky 3cb3613565 feat(remote): forward HLS segment filters to remote clients
Add POST /api/session/{id}/segment_filter: the server runs the service's OnSegmentFilter and returns only the unwanted segment URIs, so ads and bumpers are dropped over --remote-only without exposing service code.
2026-08-27 23:56:16 -06:00
imSp4rky e9ed05d4b2 feat(vaults): batch HTTP json vault writes with InsertKeys 2026-08-27 18:21:45 -06:00
imSp4rky 160ca063a6 feat(vaults): batch HTTP json vault writes with InsertKeys
Try one InsertKeys call per 500 content keys, falling back to per-key InsertKey only when the server answers 404; kv copy/sync chunk 500 for json mode.
2026-08-27 18:10:09 -06:00
imSp4rky 4ef577c1d1 fix(tracks): match resolutions per range and codec
An exact height match in one range denied the 16:9 canvas fallback to the others, so a cropped HDR10 or SDR track was dropped whenever an uncropped DV track matched the requested height. Also sweep the hybrid L5 temp files so a killed run cannot leave a stale RPU behind.
2026-08-27 14:32:36 -06:00
imSp4rky dcc1c8af18 feat(serve)!: gate the server's own proxies behind server_proxy
The server no longer spends its configured proxy providers on a remote client unless the API key sets server_proxy. It places the client by geolocating the connection address and asks for a proxy when that region does not match its own.
2026-08-27 12:43:53 -06:00
imSp4rky bbf2a96c10 fix(HTTP): simplify key retrieval condition in get_key method 2026-08-27 11:51:26 -06:00
imSp4rky 889b7110b7 feat(kv): show a progress bar while adding keys to a vault 2026-08-27 10:41:34 -06:00
imSp4rky 3aa275035b feat(serve): gate server_cdm per service and let clients follow it
serve.users.<key>.server_cdm accepts a list of service tags; retry re-attaches the job service and a bare string no longer fails open. An unset client server_cdm now follows the server's per-service /tracks flag.
2026-08-27 10:10:46 -06:00
imSp4rky 5128fef473 feat(serve): hot-reload service repos on a timer without a restart
Add serve.services_refresh_interval; refresh pulls the repos and re-imports only the changed services, staging any with active jobs until they finish. Report skipped/broken services in the log and on /api/services.
2026-08-26 23:14:23 -06:00
imSp4rky 4964869258 feat(services): add services_repo_force and compact refresh output
Force-reset repo clones on the automatic TTL refresh when enabled. Report refresh changes as one +/~/-/!TAG line per repo.
2026-08-26 22:15:39 -06:00
imSp4rky 97c939630c fix(remote): carry the full title and track state across the remote API
Services set the original language, track names, repack flags, editions and track.data inside get_tracks; the client dropped them so --remote muxed with no default audio and could not select "orig". Also round-trip Song titles, subtitle DRM, PlayReady PSSH, exact bitrate and path-only attachments.
2026-08-26 21:33:17 -06:00
imSp4rky 89f09f8e84 perf(drm): decrypt fMP4 segments during download with mp4decrypt
Opt-in decrypt_segments runs mp4decrypt --fragments-info per segment on a thread pool as segments land (DASH, single-init HLS), then decrypts the init alone; hides the post-download decrypt step with byte-identical output.
2026-08-26 16:27:55 -06:00
imSp4rky 8827ffd5cd fix(mux): give each parallel mux its own chapters temp file 2026-08-26 11:31:38 -06:00
imSp4rky b94f338619 docs(post-scripts): use post-script as the one term for hooks
Add the post-script row to the ste-writing terminology contract and
replace hook/postscript/post-download script across docs and docstrings.
2026-08-25 19:57:41 -06:00
imSp4rky a13081b14f feat(post-scripts): show a spinner while waiting for a script 2026-08-25 19:57:40 -06:00
imSp4rky 40cad41cc4 feat(post-scripts): add wait option to block until the script exits
Per-entry `wait: true` (default false) makes dispatch() wait for the script and log its exit code; a non-zero exit never fails the download.
2026-08-25 19:19:41 -06:00
imSp4rky 1543e4d22f perf(dl): push vault key writes to a background thread
Tracks stayed in LICENSING while a key found in a local vault was pushed to remote vaults under a global lock. Queue those writes on one worker, snapshot content_keys at submit, log writer failures, move --export out of the DRM lock, and join the queue before the run exits.
2026-08-24 20:29:44 -06:00
imSp4rky 65353af5c8 fix(proxies): resolve windscribevpn hostname prefixes and uk alias
Accept "us-central-111" style queries, match "us150"/"gb044" by trailing number (hosts use region words and "uk-"), alias uk->gb, fix server count.
2026-08-24 20:04:09 -06:00
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