下载引擎
HTTP 分片、加速算法、协议差异。
每种下载协议由对应功能包的步骤实现。HTTP 和 FTP 共享分片/加速/续传机制,M3U8 和 BT 委托外部工具(N_m3u8DL-RE 和 libtorrent)。
源码:features/http_pack/task.py、features/ftp_pack/task.py。
HTTP 下载模式
下载前先做 Range 探测,结果决定下载模式:
| 探测结果 | 模式 | 行为 |
|---|---|---|
| 206 + content-range | 正常分片 | 文件等分为 N 段,多线程并行下载,断点续传 |
| 200 + content-length | 不支持 Range | 单线程,重试时从头下载(截断文件) |
| 200,无 content-length | 未知大小 | 单线程,重试时从当前位置继续 |
正常分片模式下,每个分片持有一个字节区间,通过 Range 头并行下载,定位写入同一个文件。分片完成后自动接管剩余量最大的分片的后半段,减少尾部等待。进度文件每秒保存所有分片的字节偏移,用于断点续传。
FTP 与 HTTP 共享分片机制,用 REST 命令代替 Range 头,用 SIZE 命令获取文件大小(不需要探测)。
Range 探测
解析器创建任务时做两阶段探测:
偏移探测
发送 bytes=1-1,请求文件的第二个字节。偏移 1 而非 0,是因为 bytes=0-0 无法区分"服务器支持 Range 并返回了第一个字节"和"服务器忽略了 Range 从头返回整个文件"。
206 响应的 content-range 头中可以提取文件总大小。
回退探测
偏移探测失败时(服务器返回 200),再试 bytes=0-0,兼容只接受从 0 开始的 Range 请求的服务器。
416 响应(Range 不满足)的 content-range 头也可以提取文件大小。
如果扩展的资源缓存中已经有了元数据(文件大小、Range 支持情况),解析器跳过探测直接使用缓存数据。步骤执行时还会做一次轻量级探测,但只为跟随重定向拿到最终 URL,不重新判断 Range 支持。
运行时降级:下载过程中服务器返回 200(CDN 切换、限速策略变更),引擎自动从多线程降级为单线程:截断文件、删除进度文件、从头重下。
自动加速
每秒采样一次速度。累积 5 个样本后检查稳定性(最大偏差 < 15%),不稳定则跳过。
记录基线
记录当前并行数和速度,拆分 4 个剩余量最大的分片。拆分按剩余字节数选目标(不是按速度),将后半段分给新的分片。剩余量太小时跳过。
加速是一次性的。服务器的带宽上限在单次下载中不会变。如果增加并行度没有提速,再试也不会有效果。