Commit Graph
1190 Commits
Author SHA1 Message Date
imSp4rky 1dba4a8f82 fix(core): decode subprocess output as UTF-8 with replacement
Strict UTF-8 decode of external tool output (ffmpeg/shaka/mp4decrypt) crashed reader threads on non-English Windows (cp950/Big5).
2026-07-07 09:23:05 -06:00
imSp4rky 5cd50544a8 fix(remote): harden serve API access control and input handling
Bind sessions and download jobs to the API key (not source IP), reject path-traversal cache keys, bound decompression of peer-supplied blobs, gate the CDM device before the vault fallback, and compare API keys in constant time.
2026-07-06 23:54:05 -06:00
imSp4rky 84d9b92530 docs: expand config reference and genericize service names 2026-07-06 22:50:38 -06:00
imSp4rky 2f8492ebaf feat(downloader): adaptive worker scaling, tail boost, session parity, resume fixes
Opt-in --adaptive-workers (AIMD scaling + tail range-split), request/rnet session parity, and fixes for resume poisoning, truncated-segment acceptance, 416 handling, and byte-range-slice corruption. Tests + docs.
2026-07-06 11:25:29 -06:00
CodeName393 774c1a4555 feat(core): add debug logging for rnet requests (#135)
- Implement request logging in RnetSession when debug_requests is enabled.
- Log requests with the actual HTTP version and size in urllib3 style.
2026-07-05 11:06:28 -06:00
imSp4rky 8bf5444ae9 refactor(core)!: bundle download_track args into DownloadContext
BREAKING CHANGE: HLS/DASH/ISM.download_track now take (track, ctx); external wrappers/monkeypatches must update to the new signature.
2026-07-04 11:38:19 -06:00
imSp4rky 52e04002e4 test(remote): add RemoteService method-contract tests 2026-07-03 21:26:47 -06:00
imSp4rky 878384b500 fix(remote): add missing get_clearkey_license to RemoteService 2026-07-03 20:50:21 -06:00
imSp4rky 1d8cec6d2b docs: restructure documentation into MkDocs Material site 2026-07-03 19:24:11 -06:00
imSp4rky b892e3ce70 ci(docs): deploy mkdocs without force-pushing 2026-07-02 10:56:30 -06:00
imSp4rky ef2e880c7f perf(downloader): cut per-segment overhead, bound stalled connections
Segment tmp-file+rename scheme, request timeouts, hedged tail requests, streamed ISM/DASH merges, rnet client knobs, curl_impersonate -> network.
2026-07-02 09:20:03 -06:00
imSp4rky 9835f45b1b fix(api): pass track-selection params to service context
Jobs ran with default [SDR] TrackRequest, breaking HYBRID/HDR downloads.
2026-07-01 23:18:53 -06:00
imSp4rky 5cdd0b3583 feat(api): expose choice values and multiple flag in service cli_params 2026-07-01 23:08:08 -06:00
imSp4rky 7fdd514e18 feat(api): add job retry/priority/clear, history, config and maintenance endpoints
Persistent job history (capped by serve.history_limit, stored under cache), profiles/config reads, maintenance + env-check endpoints, and 409 conflict code.
2026-07-01 22:42:48 -06:00
imSp4rky f69ebb4fba feat(api): report per-episode and per-track progress on download jobs
Adds title, current_title, incremental output_files, and track_progress to job status so clients can render live multi-episode progress.
2026-07-01 18:46:41 -06:00
imSp4rky f004fa7e42 fix(api): use PBKDF2 instead of SHA256 for cache-namespace hashing
Silences CodeQL py/weak-sensitive-data-hashing on the X-Secret-Key and per-job credential hashes; fixed salt keeps namespaces deterministic.
2026-06-30 21:08:29 -06:00
imSp4rky d4a58267d4 chore(release): bump version to 5.3.0 5.3.0 2026-06-30 20:51:17 -06:00
imSp4rky 96da1ac0b0 docs: fix inaccuracies in service-creation guide 2026-06-30 16:04:12 -06:00
imSp4rky 59f3cb4fbe feat(titles): add air_date for date-based episode naming
Optional Episode.air_date names daily/sports content by date instead of SxxExx (no template change). Presentation-only; `{year}` dropped only when it duplicates the date's year. Round-trips via export/import.
2026-06-30 15:45:57 -06:00
imSp4rky 987de239ee docs: add "Creating a Service" guide 2026-06-30 15:45:57 -06:00
imSp4rky 140c2a4b2f docs(readme): link Docs to docs.unshackle.dev, remove Wiki 2026-06-30 10:54:49 -06:00
imSp4rky 2f92ffe1a2 ci(docs): serve site from docs.unshackle.dev custom domain 2026-06-30 10:40:43 -06:00
imSp4rky ecbcdff314 docs: add MkDocs Material documentation site 2026-06-30 10:28:48 -06:00
imSp4rky 03bcfc0c45 perf(hls): rename single decrypted range instead of re-copying
Short-circuit merge() to os.replace() when joining one already-merged file with no init prefix; saves a full track-size copy, falls back to streamed copy across devices.
2026-06-29 09:55:08 -06:00
imSp4rky efb560f887 fix(hls): stream segment merges to avoid OOM on large tracks
Replace whole-file read_bytes() in merge()/discontinuity merge with shutil.copyfileobj (1MB buffer); fixes MemoryError on multi-GB tracks.
2026-06-29 09:31:38 -06:00
imSp4rky 39f5bc2a9e feat(proxies): add ProtonVPN TV login, drop cookie refresh
Self-sustaining TV-code auth; cookies are now access-only and re-exported on expiry.
2026-06-28 18:42:11 -06:00
imSp4rky f9ab349e9c perf(tracks): skip redundant DV/VUI bitstream passes
Expose DV via a plain elementary-stream demux instead of a dovi_tool RPU round-trip, and skip normalize_vui when the VUI already matches the target range. Both avoid a full bitstream pass; stale-VUI streams are still rewritten.
2026-06-28 15:40:19 -06:00
imSp4rky b6fe0ae4b8 fix(dl): apply per-service decryption tool override
Resolve config.decryption_map into config.decryption before decrypt so services honor mp4decrypt instead of defaulting to shaka.
2026-06-28 14:48:16 -06:00
CodeName393 a0feb51d5a fix(console): pause active live contexts during terminal input (#127)
When a service calls `request_input` (e.g., during OTP verification in the `authenticate` phase), the terminal's active `Live` or `status` spinner contexts (handled by `rich`) would continuously refresh and redraw in the background. This caused the input prompt to disappear or become hidden immediately after rendering, although keystrokes were still registered.

This commit resolves the issue by overriding `Console.input` in `ComfyConsole` to:
1. Temporarily pause (`stop()`) all active `Live` displays before requesting input.
2. Read the user input safely without interference from the refresh loop.
3. Resume (`start()`) all previously active displays in the reverse order afterwards.
2026-06-26 10:01:18 -06:00
sp4rk.y 2ed243aae4 fix(output): treat / and \ as folder separators on any OS
Split folder templates on both separators and format each segment separately so sanitize_filename never rewrites the divider; validate folder.* templates per-segment.
2026-06-25 16:03:27 -06:00
sp4rk.y 4539f63106 fix(env): only resolve Path items in directory lists
Raw string repo specs in directories.services crashed env info with AttributeError; strings are now passed through unchanged.
2026-06-25 14:00:48 -06:00
imSp4rky 5d4a27b8ca style: apply pre-commit auto-fixes (isort, whitespace, eof) 2026-06-25 11:06:55 -06:00
imSp4rky 06e0593da3 fix(drm): don't switch to a mismatched CDM type during licensing
Guard the CDM switch on the fetched CDM's actual DRM type and raise a clear error on mismatch instead of sending a mismatched challenge.
2026-06-25 11:05:18 -06:00
imSp4rky e96e9be143 feat(output): support nested directories in folder templates
Treat `/` in folder templates as a path separator (sanitize per segment) and let movies use a folder when a `movies` template is set.
2026-06-25 10:40:49 -06:00
imSp4rky 14c96371b9 feat(proxies): add Proton VPN proxy provider
Cookie-based ProtonVPN provider with country/city/server-number selection
2026-06-24 22:11:51 -06:00
imSp4rky 66638ead6b feat(services): load service plugins from git repos
Allow directories.services entries to be git repo specs (URL/owner-repo/ @branch) alongside local paths: clone + TTL-pull as cache, list-order priority with a duplicate-ignored summary, a refresh-services command that force-syncs and reports the per-service diff, and a dirty-clone guard that protects local edits on the automated path. Adds binaries.Git and a redact_paths config toggle.
2026-06-24 08:59:03 -06:00
imSp4rky 6294566823 fix(config): match per-service cdm keys case-insensitively
cdm lookups used the raw service key while decryption upper-cases its keys, so a case-mismatched cdm entry silently used the default. Add a shared ci_get helper, route cdm/decryption through resolvers, drop a redundant decryption mutation and dead downloader writes, and add a regression bench.
2026-06-22 16:50:59 -06:00
imSp4rky ce69e8a028 docs(config): make docs/ canonical, slim unshackle-example.yaml to a starter 2026-06-21 21:23:03 -06:00
imSp4rky 605c0e65cb feat(docs): add per-vault network timeout configuration for remote vaults 2026-06-21 20:57:17 -06:00
imSp4rky ecf0bf41ab feat(vaults): add configurable network timeout for remote vaults
Default 10s on API/HTTP vault requests, overridable per-vault (`timeout:`) or globally (`vault_timeout`); previously they could hang indefinitely on an unreachable host.
2026-06-21 20:39:37 -06:00
imSp4rky 3f5b5e0fe1 refactor(api): drop dead error codes, lock error contract harness
Remove 4 unused APIErrorCode members; strengthen test_errors.py to pin the full (status, code, retryable) contract before the PRD 05 collapse.
2026-06-21 14:13:44 -06:00
imSp4rky 2f86d782bf fix(api): annotate routes.py to pass strict mypy
Type cors_middleware and the service_data dict; annotations only, no behaviour change.
2026-06-21 13:58:23 -06:00
imSp4rky d4b0c81c63 refactor(api): collapse route registration into single ROUTES table
Derive both setup_routes and setup_swagger from one ROUTES table, and move the repeated trailing APIError->response block into an @api_handler decorator.
2026-06-21 13:47:23 -06:00
imSp4rky 9cb20693e0 refactor(api): use Event.wait and a shared to_enum helper
Replace InputBridge's poll loop with Event.wait(timeout) and collapse the three download_manager enum maps into one to_enum() helper. No behaviour change.
2026-06-21 13:31:08 -06:00
imSp4rky fb90cd87b0 refactor(api): dedup handler serializers, validation, and service setup
Collapse repeated serializer/validation/CDM/list-setup logic in handlers.py behind small helpers; output behaviour unchanged.
2026-06-21 13:23:22 -06:00
imSp4rky 8a9a1e1bdc refactor(api): remove dead code paths in serve/remote layer
Delete code paths that never executed in the serve/API/remote stack:

- BridgeCancelledError: raised but never caught; replace raises with RuntimeError and drop the class.
- InputBridge.error setter and _error field: written at the handler layer, never read (session.auth_error is the surfaced channel).
- cancel_event param and _check_cancel inner fn on _perform_download: the only caller always passed None (the live job.cancel_event is untouched).
- result_with_progress monkeypatch: its status pings were redundant with the file-polled progress_sink, which is now the sole path.
- session param on _resolve_manifest_data: unused in the body.

Reconcile SessionStore's hardcoded 600s auth-state TTL into a shared AUTH_INPUT_TIMEOUT constant referenced by both the InputBridge input timeout and the store, removing the magic number without changing the longer grace window.

Update input_bridge/session_store tests for the new channels and add an assertion that auth-state entries expire at the single rule.
2026-06-21 13:07:45 -06:00
AviDev 40eafce17b feat(api): expose active-track segment counts and transfer speed in job progress (#124)
The job progress already reports a weighted percentage, phase and track counts.
The per-track tee in build_job_progress_callables already tracks each track's
segment counts and sees the downloader's speed string, so also surface the
currently-downloading track's segments_done / segments_total and speed in the
emitted progress (and on the job + its to_dict). Lets a client show
"197/663 segments, 3.2 MB/s" instead of only a percentage.
2026-06-21 12:40:16 -06:00
AviDev 733cb02391 feat(api): expose title description, date and cover_url in serialize_title (#119)
Surface optional display metadata a service can provide: the synopsis
(title.description) and a release/air date or poster image URL stashed in
title.data ("date" / "cover_url"). Purely additive, all fields default to
null when the service does not set them, so existing clients are unaffected.
2026-06-21 12:38:27 -06:00
sk8ordi3 5b724b48f8 feat: add automatic Firefox cookie and localstorage extraction (#112)
* feat: add automatic Firefox cookie and localstorage extraction

* address security and consistency findings from PR review
2026-06-21 12:26:17 -06:00
imSp4rky a2f670b140 feat: support Python 3.14 and widen range to 3.11-3.14
Move the supported interpreter range to >=3.11,<3.15, dropping the EOL 3.10 floor and unblocking installs on 3.13/3.14.

- pyproject: requires-python ">=3.10,<3.13" -> ">=3.11,<3.15"
- update_checker: replace deprecated asyncio.get_event_loop() with asyncio.to_thread() (warns on 3.12+, slated for removal)
- test_compression: simplify _run() to plain asyncio.run()
- README: bump documented Python range to 3.11 - 3.14
- uv.lock: regenerate for the new interpreter floor
2026-06-20 15:25:42 -06:00