Commit Graph
1147 Commits
Author SHA1 Message Date
imSp4rky cb2ffdb55a fix(tunnel): accept fake-ip dns answers for --local-proxy host names
A TUN-mode VPN with fake-IP DNS answers names from 198.18.0.0/15 or 2001:2::/48, which the LAN guard refused, so every dial failed. Refused hosts now warn once.
2026-10-25 12:22:28 -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 7832c4dbe4 fix(cacher): treat an expiry within 1 µs of now as expired
datetime rounds the expiry to the microsecond, which can land past a coarse time.time() tick (15.6 ms on Windows) and flake test_zero_seconds_expires_now.
2026-10-24 21:22:35 -06:00
imSp4rky d0f9307506 perf(proxy): test the remote CDM hosts only after the walk finds service code 2026-10-24 17:57:48 -06:00
imSp4rky fdb5369534 fix(proxy): match a reloaded service class by name and dedup warnings per run
A hot service reload made instance_of miss the new class, so a run with no proxy got a false bypass warning.
2026-10-24 17:29:02 -06:00
imSp4rky 34e8e37fdc fix(services): clear service-repo bytecode with git pathspecs before a pull
Delete untracked __pycache__ before each pull and drop the global dont_write_bytecode, so service bytecode is cached again
2026-10-24 15:57:08 -06:00
Jon Gordon cd9785d406 fix(services): ignore tracked bytecode in the service-repo dirty check
Importing services rewrites upstream-committed __pycache__/*.pyc and was treated as local source edits, blocking refresh. Ignore bytecode and .DS_Store in the dirty check, restore those paths before pull, and disable bytecode writes while loading services.

Port of vinefeeder/TwinVine#18 (merged).
2026-10-24 13:57:04 -06:00
imSp4rky 866420ed67 fix(dash): treat a caption subtitle also marked SDH as SDH 2026-10-24 13:43:52 -06:00
imSp4rky 0de069f35a fix(console): count a virama conjunct as one cell
A Hindi conjunct such as न्द in हिन्दी drew the --list border one cell short.
2026-10-24 12:46:53 -06:00
imSp4rky bcef9ff87a fix(sample): stop a malformed sidx from hanging the download
pymp4 loops forever on a sidx that counts more references than it holds. Manifest errors in download threads now raise instead of sys.exit.
2026-10-24 12:46:19 -06:00
imSp4rky 1036528fa3 fix(mux): address embedded audio by the file's real mkvmerge track IDs
A TS file can hold its audio first, which put the audio name on the video.
2026-10-24 12:45:25 -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 dfc99783b5 fix(downloader): report spent segment retries in one line without the URL
The session message names the host, not the signed URL, and a segment that fails every attempt prints one line with no traceback. API job errors come from the exception.
2026-10-23 19:47:12 -06:00
imSp4rky d8663b0dad fix(tracks): flag every encrypted sample entry type after decrypt 2026-10-23 17:14:12 -06:00
imSp4rky 9f054269db fix(vaults): copy no vault key from a clear track
kid_windows returns an empty map for an MP4 with no encrypted sample entry or protecting senc, so the key check judges, flags and copies nothing for it.
2026-10-23 16:59:40 -06:00
imSp4rky 3345422790 fix(drm): load a bare PlayReady WRMHEADER from DASH, HLS and ISM manifests
PlayReady.from_pssh_b64 wraps a bare UTF-16LE WRMHEADER in a PlayReady Object and keeps that as pssh_b64. DASH and ISM log and skip a PlayReady entry they cannot parse.
2026-10-23 15:55:01 -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 af69e8aad4 feat(proxy): try bare --proxy providers in proxy_providers key order
Basic stays first and Control D last; the rest follow their config key order. Geofence and proxy_map lookups go through pick_proxy and skip a provider that fails.
2026-10-23 08:20:39 -06:00
imSp4rky 71f293161e fix(cfg): show only the duplicate-key warning, once 2026-10-22 20:43:40 -06:00
imSp4rky 3e9c26bd46 refactor(config): log the duplicate-key warning without the python warning prefix 2026-10-22 20:16:35 -06:00
imSp4rky 9dd97bcd25 feat(config): warn with the lines of a duplicate key in any config load 2026-10-22 20:12:59 -06:00
imSp4rky f83a594c91 fix(cfg): give the lines of each duplicate config key instead of crashing 2026-10-22 19:45:46 -06:00
imSp4rky 1ec236f61b feat(proxy): accept an @ selector as a server_map value
A value starting with - or @ applies to its region (fr: -datacamp); a value with @ after a server is a whole query (fr: fr-bod@195.86.24.103). A selector in --proxy still wins.
2026-10-22 14:03:25 -06:00
imSp4rky 4753fcd7bc feat(proxy): select a vpn server by network or ip with @
On NordVPN, Windscribe and Surfshark, `@<name>` keeps and `@-<name>` skips a hosting network; `@<ip>` and `@-<ip>` pick or skip one server. The connect line names the server, IP and network. Surfshark pins an IP through a loopback TLS port.
2026-10-22 13:53:30 -06:00
imSp4rky b2dc70ff56 docs(dev): align self.config description with the merge in dl 2026-10-22 11:04:51 -06:00
imSp4rky 0eaefcaa2b fix(proxy): name the reason when the Control D forwarder answers 502 2026-10-21 18:35:26 -06:00
imSp4rky a7e68b7d20 fix(tracks): keep a locked segment file from hiding the download error
On Windows a worker can still hold a .!dev file open when a track fails; cleanup now ignores that OSError and still stashes the segments.
2026-10-21 18:25:50 -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 e5c339934c fix(remote): send the typed --proxy to the server when it resolved to loopback
dl and search keep the typed --proxy value, so --proxy controld:ca --remote sends the server the Control D resolver, not this machine's forwarder. The Control D log names the location and masks the resolver ID in place of 127.0.0.1.
2026-10-21 11:03:10 -06:00
imSp4rky f5bd24b5e9 fix(import): take a missing title language from the exported tracks
A title with no language now takes the language of an original-language track, else a
video track, so an unlabelled MPD re-parses and -l orig works. A track that no longer
matches its manifest is dropped with a warning instead of failing at download.
2026-10-21 10:36:03 -06:00
imSp4rky 1b20b2bbf9 test(api): give the deep-nesting cache payload case a short id 2026-10-20 20:31:20 -06:00
imSp4rky 012bf45270 fix(hls): keep PlayReady session-data keys by matching the URN string 2026-10-20 20:05:03 -06:00
imSp4rky 96d6a4f1b2 fix(api): split global speed limit across job workers 2026-10-20 20:03:03 -06:00
imSp4rky 3ffc7a9735 fix(api): validate quality and bitrate params like dl and pass cdm_only to services
Reject bad quality, bitrate/range conflicts and malformed ranges with a 400, convert quality in the worker, and pass cdm_only into ctx.params.
2026-10-20 19:59:38 -06:00
imSp4rky 639d51c41b feat(api): apply services.<TAG>.dl as defaults for API download jobs 2026-10-20 19:57:03 -06:00
imSp4rky f2273b8e97 feat(dl): keep failed track segments across runs in a resume stash
Stash a failed or cancelled track's segments outside the task temp dir and restore them on the next download. Also drop a pre-sized data file with its .!dev control file.
2026-10-20 19:53:42 -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 08a2257be3 fix(api): parse client cookies with the dl cookie parser 2026-10-20 12:46:44 -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 4728ac593c fix(proton): update query parsing and server selection logic for improved accuracy 2026-10-18 19:18:58 -06:00
imSp4rky 1a8e633fdc feat(dash): flag dv profile 8 tracks from supplementalCodecs and use hdr10+dv as the hybrid 2026-10-18 17:18:11 -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