Commit Graph
113 Commits
Author SHA1 Message Date
imSp4rky 4b6d15cc2a feat(dl)!: treat a missing -sl language as a warning
A missing -sl language now warns and continues, with or without --best-available. --require-subs counts a forced track only when selection keeps it, and a title with no track left is skipped instead of failing at mux.

BREAKING CHANGE: a missing -sl subtitle language no longer fails the run. Use --require-subs to fail on it.
2026-11-09 15:01:54 -07:00
imSp4rky b3d586a590 feat(api): carry the service catalogue on /api/dashboard/services
Rows now include the /api/services fields (help, cli_params, auth_methods, ...) and server_accounts. Both routes build the catalogue off the event loop, and an enum choice or a non-JSON list default no longer fails the whole route.
2026-11-03 18:27:49 -07:00
imSp4rky 87ccd6666c fix(api)!: key the health route and keep server internals from user keys
/api/health needs X-Secret-Key but stays outside the rate limit. Only the admin key gets load_errors from /api/services, default error details no longer name the exception class, and a prepare signal replaces aiohttp's Server banner on every response while the CDM routes keep their own.
2026-11-03 11:53:55 -07:00
imSp4rky b6429ecdfd feat(remote): match the server CDM to the client's DRM and read vaults first
A dual widevine/playready cdm entry now loads the device of the client's DRM system, for old clients too since they already send cdm_type. A new client hands a capped track to its own device for the track's DRM system, and raises the refusal only after its local vaults miss.
2026-11-03 10:51:29 -07:00
imSp4rky b710b5b0c9 feat(titles): add a sports output and folder template kind
A sport episode uses output_template.sports with a {date} in the template's separator style; the flag survives --remote, the REST API and export.
2026-11-03 08:43:05 -07:00
imSp4rky 842ece3802 fix(manifests): skip filtered dash periods after the main content and keep them over export
A manifest snapshot module now saves and restores DASH/ISM parser state for --remote and export/import, so an import keeps the service's period filter without fetching the manifest.
2026-11-02 20:41:27 -07:00
imSp4rky eeff83b820 fix(api): cast download job options with the dl click types
cast_dl_params feeds ctx.params to dl() and dl.result() as on the CLI. A string lang value now returns 400 instead of splitting into letters, and -r accepts HDR10+.
2026-11-02 20:30:40 -07:00
imSp4rky f6ce600d71 perf(api)!: cut per-request and per-tick event bus traffic
Session update events carry the new action as action_entry instead of the full log; access lines stay out of the log ring unless --debug. Job events build and redact their dict once, the progress interval matches the 0.5 s poll, and dashboard stats are serialized once.
2026-11-02 14:52:18 -07:00
imSp4rky 65c8e60a7a fix(api): check and cast download job service options like a session does
A bad value now gets 400 INVALID_PARAMETERS at submit and the worker casts each option; a flat dl key such as quality or lang no longer fills a service option of the same name.
2026-11-01 20:21:42 -07:00
imSp4rky 99f0c269be fix(api): refuse a non-public proxy host for a key without server_proxy
Closes the loopback and LAN route to the server's own forwarders, including backslash, percent-escape and *.localhost forms.
2026-11-01 20:04:06 -07:00
imSp4rky e509db618e fix(api): keep a pooled remote session to the api key that opened it
The pool key now includes the caller's API key and client_region, so a hit never skips the server_proxy and region checks that a fresh session runs.
2026-11-01 19:47:19 -07:00
imSp4rky e6a627118f feat(tracks): add a display-only note shown in --list and over --remote 2026-10-30 16:17:36 -06:00
imSp4rky 5206b3cab6 refactor(remote)!: send service options only in service_params
A service option named like a dl option (e.g. --profile) is no longer dropped or mixed with the dl value; the server casts nested values and keeps cli defaults nested.
2026-10-30 16:16:56 -06:00
imSp4rky bd64f3a8c4 fix(api): stop a service's sys.exit from killing the serve process
Catch SystemExit at service import, in the heartbeat task, the 5xx middleware, search, samples and chapters, and answer it as SERVICE_ERROR.
2026-10-29 11:23:53 -06:00
imSp4rky 7b927934e0 feat(remote)!: let server_cdm outrank a service's cdm entry and set it per service
server_cdm: true on a remote_services entry now licenses remote runs with the server CDM even when the service has its own cdm entry, which stays the local-run device and the fallback. A services.<TAG>.server_cdm replaces the server value for one service, per-service entries match the tag in any case, and the configured fallback logs at info.

BREAKING CHANGE: with server_cdm: true, a per-service cdm entry no longer makes your own device license remote sessions; use dl --cdm or services.<TAG>.server_cdm: false.
2026-10-29 10:18:15 -06:00
imSp4rky d12a943d96 fix(api): show filename codec and range labels in codec_display and range_display 2026-10-28 15:34:52 -06:00
imSp4rky 9f86464826 fix(api): cache the health update check and fix a remote-session test fixture 2026-10-27 13:38:57 -06:00
imSp4rky 756c2ce2b5 feat(remote): reopen a lost remote session and resume at the current title 2026-10-27 13:24:31 -06:00
imSp4rky 9017ab95b7 feat(tracks): add Video.hdr10_base and forward s_lang over remote and REST
A DV track with an HDR10 base (profile 8.1) lists as DV+HDR10; dl_params now carry s_lang.
2026-10-27 13:06:48 -06:00
imSp4rky cc33600cc7 feat(tracks): add muxing.original_label to mark original-language tracks
Adds the label to audio, subtitle and embedded audio names unless the name already says it, and escapes track lines in the --list tree.
2026-10-24 22:51:35 -06:00
imSp4rky 80bda08f36 feat(tracks): add muxing.track_names none to leave unnamed tracks unnamed
A track the service gives no name keeps none (--list shows [VTT] | en); SDH, CC, Forced and Descriptive labels still apply.
2026-10-24 21:24:31 -06:00
imSp4rky ecf17baffe feat(tracks): add native track names with muxing.track_names
Set muxing.track_names to native to name an unnamed track in its own language (中文(繁體), Português (Portugal)) in place of English. The same script and region rules apply. --list, the muxed names and the REST API track_name follow the option. A test fixture resets the muxing options, so a local unshackle.yaml cannot change test results.
2026-10-24 12:43:50 -06:00
imSp4rky 1175035317 feat(tracks): name unnamed tracks by language and tag subtitle scripts
Unnamed tracks get the English language name (default region left out); subtitle tags gain the script their region implies (zh-TW -> zh-Hant-TW). Refs #169
2026-10-24 10:59:21 -06:00
imSp4rky 83514d12fe fix(core): cut user-facing errors and warnings to one line 2026-10-23 20:23:05 -06:00
imSp4rky cc4bf19706 fix(vaults): stop false bad-key flags from a failed decode check
Judge a vault KID only on a file whose KID map holds it, tell remote vaults of a bad pair only once another key replaces it, and let the server CDM unflag a pair it returns; the server never flags a CDM-licensed pair. Log FFmpeg stderr on a failed check and name the missing CDM when none is set.
2026-10-23 15:31:26 -06:00
imSp4rky eeaf16cd83 fix(remote): keep each session cookie's domain, path and secure flag
The client set server cookies with no domain and sent all of them to every host, so a CDN refused segment requests with 400 header too large. rnet sessions now send cookies too.
2026-10-23 09:42:01 -06:00
imSp4rky 5086dafff3 feat(api)!: add a server drain and never answer with a 5xx
POST/DELETE /api/dashboard/drain refuses new sessions and jobs (SERVER_DRAINING, 409) and warns open sessions. A CDN can replace a 5xx body, so server errors are now 422, retryable ones and the tunnel check 424, and a new middleware turns any 5xx into 422.

BREAKING CHANGE: INTERNAL_ERROR, DOWNLOAD_ERROR, WORKER_ERROR and the fallback return 422 instead of 500; NETWORK_ERROR and SERVICE_UNAVAILABLE return 424 instead of 503; /api/tunnel/check failures return 424 instead of 502.
2026-10-21 17:15:33 -06:00
imSp4rky 23614fd938 feat(remote): add --local-proxy to send server requests through the client
A reverse tunnel over the remote connection: the server's service traffic leaves through the client's own network. Only the client dials. Adds the tunnel-test command.
2026-10-21 17:09:37 -06:00
imSp4rky afaff8e070 feat(api): tag each error with a ref and count errors by service
Every structured error carries a short ref, appended to its message and logged with the request; /api/dashboard/status gains per-service error counts. Gzip now compresses in place.
2026-10-21 14:39:37 -06:00
imSp4rky 39ec591c48 fix(api)!: send service and DRM errors as 422, not 502
Cloudflare replaces an origin 502 body with its own page, so clients got "502: Bad gateway" in place of the error and resent each failed licence.

BREAKING CHANGE: SERVICE_ERROR and DRM_ERROR now return HTTP 422 instead of 502.
2026-10-21 11:43:33 -06:00
imSp4rky 5b9120a7f1 fix(api): refuse peer cache files that name types other than datetime
The server and the client both check a forwarded cache file before they write it, because Cacher decodes it with jsonpickle. The session-create cache write now runs off the event loop.
2026-10-20 19:48:13 -06:00
imSp4rky ef75ea7d7a feat(dl): add --local to override a remote: true service config 2026-10-19 14:25:03 -06:00
imSp4rky 3aaf9c4107 fix(services): route a service remote from services.<TAG>.dl.remote
Click picks the subcommand before the dl callback applies the service config, so Services.resolve_command now applies remote and server first. A REST API job routes from its request only.
2026-10-19 14:19:07 -06:00
imSp4rky 2cc5e44957 feat(search): add --remote to search through a remote server
The client sends its credentials, cookies and cache, but none for an anonymous-search service. The API relay uses the same path.
2026-10-18 13:23:04 -06:00
imSp4rky d7c6907329 feat(tracks): probe dv tracks for hdr10+ and list them as DV+HDR10P
A DV track that carries HDR10+ keeps its DV range and gets Video.hdr10plus, sent in the REST track JSON and to remote clients.
2026-10-18 11:43:44 -06:00
imSp4rky 35871f3a52 feat(hybrid): generate dolby vision from hdr10+ with --generate-dv
Builds per-scene L1 in unshackle (PQ mean, letterbox-aware) with a generate_dv_mode config (v29/v40/legacy); a failed hybrid no longer exits 0 with no video.
2026-10-17 16:40:14 -06:00
imSp4rky 14bd2f2c7e feat(api): relay services from remote servers with pooled sessions and login prompts 2026-10-16 19:03:56 -06:00
imSp4rky a4ce70a53c feat(tracks)!: match a language tag to the variant it means
A tag with a region (en-US, es-419) matches only that variant and reports a miss instead of taking another region. A bare tag takes the variant it means (pt -> pt-BR, es -> es-ES) and falls back to any variant only when that one is missing. `orig` prefers the title's own tag, `-sl orig` resolves, forced and SDH subtitles are picked from their own pools, and the track name no longer strips the region from the cached language.

BREAKING CHANGE: -l es-419 no longer selects es-ES, and language_priority, language_tags and muxing.default_language treat a regional tag as exact.
2026-10-15 12:26:39 -06:00
imSp4rky d41bb73d9e feat(remote): decrypt service-owned cbcs samples on the server
The client downloads the file and sends binary sample frames to a new samples route.
2026-10-14 11:03:14 -06:00
imSp4rky 4fbaf2a61a feat(api): forward exact_lang to the service context
The remote-dl client sends exact_lang in dl_params, and REST download jobs set it in the service ctx, so a service can skip the manifests of close-match languages.
2026-10-13 15:07:01 -06:00
imSp4rky ecdfb667c9 feat(dl): add --sample and --include-sample
--sample downloads only a time window of a title (default 120-180 s) and cuts the mux to it. --include-sample cuts a 60 s sample from a finished file. Both write to a Sample folder with a SAMPLE tag on the filename
2026-10-11 14:53:50 -06:00
imSp4rky 0a7c76561c feat(search): add ANONYMOUS_SEARCH to skip the login for a service
A service that sets the flag gets no cookie load, no authenticate() call and no cookie save on a search, on the CLI and in the REST search handler. /api/services reports it as anonymous_search.
2026-10-10 13:21:14 -06:00
imSp4rky 09cae2ec3f feat(serve): relay approval messages to jobs and proxy remote downloads
A REST job shows a wait_for_approval message as its notice field. search, list-titles and list-tracks fail at once on a login that needs the user. A remote client downloads through the --proxy it sends.
2026-10-07 11:15:16 -06:00
imSp4rky 5b0369e63a feat(service): add wait_for_approval and return the cache for a login with no prompt
A pair code shown in a log line never answers a prompt, so the server read that login as anonymous and kept the session cache.
2026-10-07 09:03:18 -06:00
imSp4rky 3fd69e8039 feat(serve): add --cdm-only for a CDM backend with no REST API
Mounts only the pywidevine and pyplayready routes plus /api/health and the dashboard; no session store, service refresh or Swagger.
2026-10-06 18:24:21 -06:00
imSp4rky eea4b41b70 feat(serve): log CDM calls for the dashboard
Add GET /api/dashboard/cdm-logs: one record per pywidevine/pyplayready call plus open sessions per device, with no key or licence material.
2026-10-06 14:58:08 -06:00
imSp4rky 3477d09cc2 feat(dl): add --audio-description-only and --forced-subs-only
Each keeps one kind of track inside its track type. A run of more than one title skips a title that has no such track. The REST API rejects a non-boolean value for a boolean dl param, and the DASH parser reads audio description from Role elements.
2026-10-06 12:45:52 -06:00
imSp4rky 1d2cb3a102 fix(dl): read the vaults first under --all-drm
A DRM system sends a challenge only for a KID with no content key. --cdm-only keeps one challenge per system for each set of KIDs.
2026-10-05 16:43:54 -06:00
imSp4rky ee38477b11 feat(dl): add --all-drm to license Widevine and PlayReady per track
Each DRM system sends one challenge per KID set in a run, also when a vault has the content keys. Needs a CDM for each system in the cdm config.
2026-10-05 15:22:01 -06:00
imSp4rky 9a1abd23b6 feat(remote): license with the client's device when the user picked one
A remote client that passes --cdm, has a cdm entry for the service that named the loaded device, or sets server_cdm: false now declines the server CDM at session create, and warns when the server keeps it. A service option listed in SERVER_DEVICE_OPTIONS keeps the server CDM.
2026-10-01 13:21:53 -06:00