dynamicSegmentation把工作切得比连接数更细。
约四条连接对应四块工作,收尾阶段不会只剩一个工作单元。关闭后退回固定块大小 + 工作窃取。
默认开启
HTTP/RANGEKOTLIN JVM 17+无需界面
Kotlin/JVM 下载引擎把一次 HTTP 传输拆给 16 个工作单元,从磁盘上真实落下的字节续传,并拒绝在 Range 上撒谎的服务端。
进度条不是装饰。它的三段分别对应真实流程:探测、并行分片、校验。
1次探测
下载开始前先问一次:这个服务端认不认字节范围 Range?
16个分片
16 个分片同时进行;工作窃取会把剩余工作从慢连接手里拿走。
1次校验
先核对每一段实际返回的字节,再核对合并文件的预期总大小。
先确认服务端是否支持 Range。不支持就不假装支持,退回整条下载。
块数约为连接数的四倍,慢连接不会独占最后剩下那块工作。
实际返回的字节要和请求的 range 对上;合并后的文件还要和总大小对上。
| 机制 | 实际结果 |
|---|---|
| 分片并发下载 | 按 HTTP Range 并行下载分片,并复用连接(HTTP/2 多路复用 + keep-alive)。 |
| 动态分片 + 工作窃取 | 细粒度预分片 + 工作窃取:一条慢连接拖不垮整个传输,也消除了「最后一个分片单线程收尾」的长尾。 |
| 克制的自适应 | 只在遇到 429/503 或连续失败时才降低并发。普通抖动绝不改线程数 —— 不做 AIMD 来回震荡。 |
| 按真实进度续传 | 分片状态落盘;暂停/继续按磁盘上真实写完的字节接着下,而不是按记忆中的数字。 |
| 拒绝 Range 篡改 | 会核对服务端实际返回的字节是否就是请求的那段 Range —— 忽略 Range 直接回整文件的服务端会被识别出来,而不是把错位数据写进文件。 |
| 字节级完整性校验 | 合并完成后校验总大小;少了或多了都判为失败。 |
每一条都能在仓库里核对。其中两条存在的原因,是「看起来显然」的做法被实测否掉了。
下面五个控件使用引擎默认值。开关可以在页面里直接拨动,数字结论来自实测。
dynamicSegmentation把工作切得比连接数更细。
约四条连接对应四块工作,收尾阶段不会只剩一个工作单元。关闭后退回固定块大小 + 工作窃取。
默认开启
tailAssist把尾巴交给空闲的工作单元。
只在收尾阶段生效,每个分片最多拆两次;低于 2 MiB 不拆,16 MiB 的块最多变成四段。
默认开启
overlapMerge最后几个字节还在路上时先合并。
512 MB / 64 连接实测:11.08 s 降到 10.39 s,约 6%。与收尾托管同时开启时可能重复写,所以默认关闭。
默认关闭
bufferedSegmentWrite分片写入走缓冲流。
16 MB / 128 连接 / 64 KB 分片:直写 2576 ms、缓冲 2584 ms,0.3% 落在噪声里;不加它,续传进度更可靠。
默认关闭
trustAllCerts信任任何证书。
只给抓包调试用。它关掉证书校验,生产环境保持关闭。
默认关闭
| 能力 | 配置项 | 说明 |
|---|---|---|
| 全局限速 | globalSpeedLimitBytesPerSec | 0 = 不限速 |
| 线程数 | maxConnectionsPerTask | 1..256 |
| 并发任务数 | maxConcurrentTasks | 1..64 |
| 最大重试 | maxRetries | 0..50 |
| 动态分片 | dynamicSegmentation | true / false |
| 代理 | proxy | 直连 / 系统 / 手动(HTTP,SOCKS,鉴权) / PAC |
| DNS | dns | 系统 / 静态 hosts / DoH(url) |
| 忽略 SSL | trustAllCerts | 抓包调试用 |
| 主题 | — | 由上层应用负责;SDK 不涉及界面 |
SDK 有意不画界面:限速、队列与进度都是值,怎么呈现由上层应用决定。
可以只取引擎,也可以装配完整协议栈。依赖方向始终不会反转。
turbodl-core引擎 / 零插件依赖turbo-plugin-runtime生命周期 + 扩展点turbo-plugin-bootstrap一次调用完成装配turbo-plugin-hlsHLS 点播后端turbo-plugin-jsQuickJS 加载器turbo-plugin-parser分享链接解析turbodl-cli可脚本化命令行| 构件 | 作用 | 必需? |
|---|---|---|
| turbodl-core | 下载引擎本体 分片并发下载、断点续传、重试、限速、DNS/代理。可单独使用,不依赖插件框架。 | 必需 |
| turbo-plugin-runtime | 插件运行时内核 生命周期、清理(disposer)、事件总线、服务注册表、扩展点、版本握手、诊断。对任何具体协议一无所知。 | 可选 |
| turbo-plugin-bootstrap | 基础装配 一次调用装配基础插件(Kotlin 加载器 + HTTP 后端),并桥接引擎的事件流。 | 可选 |
| turbo-plugin-hls | HLS VOD 适配 解析 M3U8 清单、分片并发下载(分片级重试)、AES-128 解密、支持 EXT-X-BYTERANGE。直播/DRM/fMP4 清单会被明确拒绝,而不是产出一个损坏的文件。 | 可选 |
| turbo-plugin-js | JavaScript 插件加载器 加载用 JavaScript 写的 TurboDL 插件。内嵌 QuickJS —— 每个脚本一个 runtime 与 context —— 并给脚本一套稳定的 `host`/`plugin` ABI。 | 可选 |
| turbo-plugin-parser | 平台链接解析 把分享链接变成可下载请求:微博(MP4 + 图集)、小红书(无水印视频 + 原图)、Pixiv(每页原图)。不持有任何凭证 — 平台需要登录时返回 null,由宿主自己的会话处理接手。 | 可选 |
| turbodl-cli | 命令行工具 基于 SDK 的完整命令行工具:多线程、断点续传、批量、给脚本与 Agent 用的 NDJSON 输出。以 fat JAR 形式提供。 | 可选 |
失败即拒绝明确不支持
不支持的流会响亮地失败。另一种做法 —— 写下一个看起来正常、其实不对的文件 —— 正是这一节要避免的失败方式。
| 插件 | 明确拒绝 | 为什么 |
|---|---|---|
HLS VOD Backendbackend.hls | 直播清单(没有 `EXT-X-ENDLIST`)DRM / `SAMPLE-AES`fMP4 `EXT-X-MAP`不连续标记 | 明确拒绝:不支持的流直接失败,而不是产出一个看起来正常、其实不对的文件。 |
JavaScript Plugin Loaderloader.js | 注册 `DownloadBackend`(字节面留在 Kotlin 一侧)发布服务(服务是 Kotlin 对象图)`require` / npm / `fetch` —— 宿主 ABI 就是全部可用面`jar:` 与远程脚本源(目前只支持本地文件 / `inline:` / `data:`) | 脚本负责算 URL、请求头和签名,从不经手下载数据流。这条边界正是它不会变成带宽瓶颈的原因。 |
Platform Link Parserparser.platforms | 登录 — 需要会话的平台返回 null,由宿主自己的账号处理接手Pixiv 动图(ugoira):zip + 帧时长表需要图像处理Pixiv 小说需要签名的接口(抖音 / 快手 / B站):各自的签名算法仍留在宿主侧 | 它的结果类型不含任何路径:`DownloadRequest` 需要 `destination: File`,而解析发生在宿主决定目录之前。临时目录占位只在边界处补上,宿主仍然走自己的路径策略。 |
命令行可以每个事件打印一行 JSON。下面的面板和终端使用引擎同一批字段名。
每个字段都来自引擎事件流;SDK 自己不画任何界面。
{"type":"start","url":"https://example.com/image.iso","output":"/tmp/image.iso"}
{"type":"timing","stage":"metadata","t_ms":184,"probe_ms":96,"resume":""}
{"type":"progress","state":"downloading","downloaded":222732288,"total":358411469,"percent":62,"speed":19503514,"connections":16,"eta_ms":7020}
{"type":"completed","url":"https://example.com/image.iso","file":"/tmp/image.iso","bytes":358411469,"sha256":"0f3a…"}
{"type":"summary","total":1,"failed":0}java -jar turbodl-cli-all.jar <url> -o out.bin -c 16
java -jar turbodl-cli-all.jar <url> --json
java -jar turbodl-cli-all.jar --batch tasks.txt不需要。它是纯 Kotlin/JVM 库。Android 只是使用者之一,服务端或桌面工具同样可以用。唯一要求是 JVM 17+。
不必。turbodl-core 不依赖插件框架。需要 HTTP 之外的协议时,框架才有意义。
点播可以,通过官方插件:解析清单、分片并发、AES-128 解密。直播清单、DRM 与 fMP4 会被明确拒绝。
这个项目不提供。SDK 有意不画界面。提供的是引擎、插件框架与命令行工具。
每个文件都是 v0.4.1.0 Release 的附件:自包含 CLI JAR 与离线 Maven 包。目前还没有发布到 Maven Central。
会核对实际返回的字节与请求的那段。忽略 Range 的服务端会被识别,该分片判为失败,而不是写入错位数据。
把引擎加进构建,把字节交给运行时:
还没有发布到 Maven Central。官方支持的用法是 Release 页上的离线 Maven 包,下载页写了具体步骤。