Commit Graph
407 Commits
Author SHA1 Message Date
imSp4rky b10fd2d3a4 feat(tunnel): free finished tunnels at once and wait out 429s on --remote
A tunnel closed with code 1000 is freed without the 60s grace, a shared: true API key counts tunnels per X-Client-Id, and --remote waits out Retry-After and a full tunnel cap with a countdown; responses carry X-RateLimit-* headers.
2026-11-09 15:43:33 -07:00
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 6ca2503a5f perf: lazy-load services and proxy catalogues, faster namespace strip
load_xml strips namespaces without QName; services import on first use and proxy providers fetch their catalogue on first query; the font scan is skipped when no subtitle names a font and is cached per process.

Serve CPU -40% and track requests -28% on 20 MB manifests; CLI startup 2.7 s -> 1.2 s; --list 27-46% faster across six services tested.
2026-11-04 11:12:11 -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 893c81f428 fix(drm): key PIFF-first tracks by track ID and trust shaka's exit code
mp4decrypt copied a track whose first sinf has no tenc through encrypted; pass its key by track ID and retry with shaka on a passthrough. Shaka fails only on a non-zero exit now.
2026-11-03 17:05:26 -07:00
imSp4rky 5ffdda3883 fix(binaries): report a version for git ffmpeg builds
Dated builds (N-<rev>-g<hash>-YYYYMMDD, YYYY-MM-DD-git-<hash>, shallow-clone git-YYYY-MM-DD-<hash>) report YYYYMMDD; undated ones N-<rev>.
2026-11-03 14:13:28 -07:00
imSp4rky 72b9c51b49 fix(attachment): download through the track downloader with its retries
A failed attachment now gets the same retries and resume as a track before it stops the run; same-named attachments no longer share a temp file.
2026-11-03 13:53:33 -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 3027592e31 fix: drop null vault keys, cap snapshot restore size, isolate test globals
Vaults.add_keys and kv add skip null content keys instead of failing the batch; is_null_key moves to core.vault. A manifest snapshot restore has one 32 MiB inflate budget. Tests reset the speed limiter and config between runs.
2026-11-02 22:01:02 -07:00
imSp4rky c4677341c8 refactor(drm): resolve content keys in one licence path behind ServerKeySource
Drop null keys from every licence, server and export source, not only Widevine. dl now finds remote sessions and imports through ServerKeySource instead of private fields.
2026-11-02 21:13:23 -07:00
imSp4rky d8a4950b99 fix(import): keep only exported dash content periods on a re-fetch
The export writes mediaexport content_periods per manifest; an import that re-fetches the MPD (no saved snapshot) drops the periods a service filtered.
2026-11-02 20:58:49 -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 dc188b7276 fix(manifests): match dash representations across periods by shape, not id
Some packagers renumber AdaptationSet and Representation ids in every Period, so audio took video segments after the first Period. A match never crosses codec, size or language.
2026-11-02 17:50:35 -07:00
imSp4rky a4ba7767c5 test(manifests): add shaka packager ad-cue output to the corpus 2026-11-02 17:50:25 -07:00
imSp4rky c744e9a87b perf(proxies): cache expressvpn and proton catalogues across requests
A config reload clears the cache; a failed answer is never kept.
2026-11-02 17:11:58 -07:00
imSp4rky e685710fba refactor(api): register each route once and merge duplicated handler code
Swagger now owns route registration instead of adding a second dead copy of every route; add json_body, enqueue_job, serialize_tracks and client_credential, build the serve middleware list once, and scan the users once per request.
2026-11-02 15:06:52 -07:00
imSp4rky 47d9e3d3c9 perf(api): move blocking file and hash work off the event loop
Run session-tracks serialization, request cache IO, session cache dir removal (now outside the store lock), history reads and gzip over 1 MiB on worker threads; cache the per-key PBKDF2 namespace and key_id.
2026-11-02 14:59:04 -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 bb081046e2 perf(api): stop rebuilding proxy catalogues, vaults and cdms per request
Cache proxy provider catalogues (10 min), reuse vaults and CDMs across one batch licence call, and cache the health update check, /api/services entries and parsed service config.yaml.
2026-11-02 14:40:58 -07:00
imSp4rky e01204ac13 fix(binaries): kill the whole process tree when a version probe times out
dl's debug log takes tool versions from binary_version.
2026-11-02 13:49:18 -07:00
imSp4rky dd3862be8a feat(env): show tool versions in env check, paths with --verbose
binary_version moves to core/binaries and reads the version from the tool's own banner line; only mp4decrypt is run with no arguments.
2026-11-02 13:37:50 -07:00
imSp4rky 31328dc109 fix(drm): retry a licence call only for an argument the service rejects
A TypeError raised inside the service no longer sends the challenge again.
2026-11-02 09:01:42 -07:00
imSp4rky 1a7192380d fix(drm): keep the monalisa ciphertext when the decrypt tool fails
The tool writes to a temporary file through run_step, which gains a timeout that hides the command line. A missing tool now raises instead of skipping.
2026-11-01 21:26:36 -07:00
imSp4rky 397ac2c7cb fix(subtitle): convert wvtt cue times by the media timescale
Cue times were multiplied by the mdhd timescale instead of scaled to µs, so the pycaption path put cues hours out of sync for any timescale but 1000.
2026-11-01 21:05:42 -07:00
imSp4rky 93ca8ab9c0 fix(dl): read the drm's content keys again after a relicence replaces them
A licence that builds a new key dict left decrypt_verified on the old one, so a falsely flagged key stayed flagged and a replacement key went unchecked. Both relicence passes now share one step that clears the flag.
2026-11-01 20:41:38 -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 de9646dba2 fix(api): skip the local geoblock for a relayed tag not installed here 2026-11-01 20:06:09 -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 a58da3f5d3 fix(music): stop reading a kb/s bitrate as a hi-res sample rate
A lossy label such as "256 kb/s AAC" or "MP3 320 kb/s" no longer gets the per-track Hi-Res badge.
2026-11-01 18:14:03 -07:00
imSp4rky 67d3d4801f fix(remote): send a service's filtered dash periods so the client skips them too 2026-11-01 16:35:06 -07:00
imSp4rky 96c3840b82 fix(session): keep cookie paths so same-name cookies stay on their own path
RnetCookieAdapter stores cookies by domain, path and name and sends path, secure and a leading-dot domain to rnet. It also takes server-rotated values, and worker children and track sessions get the cookies with their paths.
2026-10-31 22:57:22 -06:00
imSp4rky 86f26c31d5 refactor(tracks): name and match resolutions by one standard-height rule
standard_resolution() replaces the aspect-ratio logic in naming and is shared by -q matching, export names and progress/hybrid labels, so 1920x1088, 1916x1076, portrait and DCI sizes get standard names.
2026-10-31 22:05:26 -06:00
imSp4rky d5a8ed2a39 fix(titles): name a dv profile 7 or 8 track with an unnamed pq base DV.HDR 2026-10-31 21:52:03 -06:00
imSp4rky 15e46d8bcc fix(titles): name a PQ video track without HDR10 metadata HDR 2026-10-31 21:42:11 -06:00
imSp4rky f9c1c3d390 feat(tracks): add subtitle.dedupe_codecs to keep one codec per subtitle variant 2026-10-31 16:35:01 -06:00
imSp4rky 65e807bf5f fix(subtitle): join cues that a segment boundary splits in stpp and wvtt
Share one append_cue join across DASH fTTML, ISM and fVTT parsing. Also map "geo-block" and "geolocation" errors to GEOFENCE in the API.
2026-10-31 15:59:12 -06:00
imSp4rky c6c0331007 refactor(dl): share the cache, vault and key-label steps in prepare_drm
take_cached_key, take_vault_key and add_key_label replace the code copied across the server-CDM, Widevine, PlayReady, ClearKey and MonaLisa branches.
2026-10-31 13:28:29 -06:00
imSp4rky b3c86413d5 fix(dl): take turns on licence requests so one licence serves every track
Tracks with different KID sets still query the vaults at the same time, but wait for one licence lock and check the key cache again before they licence.
2026-10-31 12:42:43 -06:00
imSp4rky f2747076a6 fix(tracks): retry ccextractor on the repackaged file 2026-10-31 12:21:19 -06:00
imSp4rky cbeff379fb fix(subtitle): place fragment-relative ISM TTML cues on the track timeline
Smooth Streaming TTML times cues from each fragment's start; a whole track stacked into the first fragment. Also stop rebase_ttml failing on a track with no cues.
2026-10-30 23:40:46 -06:00
imSp4rky 0c45195fe2 fix(subtitle): remove the DASH presentationTimeOffset from stpp and wvtt cues
STPP and WVTT cues sit on the media timeline, so they played late by the offset after the mux.
2026-10-30 23:22:47 -06:00
imSp4rky 97711e799c fix(manifests): decode audio channels by scheme in dash, hls and ism
DASH reads the AudioChannelConfiguration scheme (Dolby mask, CICP index incl. immersive layouts, channel count); HLS and ISM counts map 6/7/8 to 5.1/6.1/7.1.
2026-10-30 23:22:47 -06:00
imSp4rky 7898ff6dd6 refactor(types): bring mypy to zero errors across unshackle
Fix the bugs the type errors exposed (RnetSession.send body, HLS proxy session, title cache fallback, mux progress) and gate mypy in pre-commit, warn-only in CI.
2026-10-30 20:51:21 -06:00
imSp4rky b493c9cd52 fix(naming): tag HDR10+ from the track range when MediaInfo misses it 2026-10-30 17:28:50 -06:00
imSp4rky b0f96cdee9 fix(tracks): keep HDR colour metadata when muxing VP9
mkvmerge drops the MP4 vpcC/SmDm/CoLL boxes of VP9, so pass the colour codes and mastering display data from an ffprobe of the source.
2026-10-30 17:13:14 -06:00
imSp4rky e6a627118f feat(tracks): add a display-only note shown in --list and over --remote 2026-10-30 16:17:36 -06:00