Video Downloader
用户给出视频链接(可能附带名称、清晰度要求)时,用 scripts/download.sh 完成下载。
适用范围
只处理用户有权下载的内容:自有素材、已获授权的内容、平台允许离线保存的内容、用户自己录制或托管的流。
DRM 加密、付费墙、需要登录态或验证码/风控挑战才能拿到的内容不在本 skill 范围内 —— 遇到这些要停下来向用户说明,而不是尝试绕过。
主流程
先探测可用清晰度并把结果给用户看,再下载:
bash scripts/download.sh "<URL>" --list --probe
确认档位后下载(不传 -q 时选最高档):
bash scripts/download.sh "<URL>" -q 1080p -n "名称" -o ~/Downloads
关键约束
这些都是实际踩过的坑,不是理论风险:
- 防盗链站点需要 Referer + 浏览器 UA。缺了会一路 403,而且不少站点是整个域名都拦,连不存在的路径也返回 403,很容易误判成「链接失效」。Referer 必须取用户实际观看页的域名(换个域名实测无效),并且要用
-H传给 N_m3u8DL-RE,让它对 m3u8 和分片请求同时生效。判断是不是头的问题,用curl -o /dev/null -w '%{http_code}\n' -A '<UA>' -H 'Referer: <R>' <URL>对照一下。 - 日志路径。N_m3u8DL-RE 默认把日志写到二进制旁边的
<exe>/Logs,装在/usr/local/bin这类 root 所有的目录会报Access to the path ... is denied。脚本改写到<保存目录>/.logs/,也可以用--no-log。 - 非终端环境会崩。stdout 不是 TTY 时 Spectre.Console 的进度条会
Abort trap: 6,栈里出现ProgressRefreshThread。脚本检测到非终端会自动套script伪终端。 - 给 master.m3u8 必须带
--auto-select或-sv,否则会弹交互选择框,非交互环境下直接抛栈。 - 目录名不等于真实分辨率。
--probe会下首片用 ffprobe 实测。两个容易翻车的细节:分片后缀可能不是标准扩展名(例如.jpeg),ffmpeg 的 HLS demuxer 会拒绝直接读 m3u8,必须先落盘再交给 ffprobe;字节区间布局(fMP4 单文件 +#EXT-X-BYTERANGE)下「第一个分片」可能等于整个文件,必须按 range 取、并拼上#EXT-X-MAP初始化段。脚本里都已处理。 - 合并阶段会撞文件句柄上限。默认合并用的是 ffmpeg concat 协议(
-i concat:"a|b|c|..."),它会一次性打开全部分片,1700 多个分片在 macOS 默认上限(256)下必然报Too many open files,而且工具只会打印提示、不会自动换方式。脚本会在启动前把 soft limit 尽量抬到 hard limit;仍然失败时用--concat-demuxer(改走 concat demuxer,顺序打开,仍然输出 mp4)或--binary-merge(不走 ffmpeg,按字节拼接,输出后缀变成源分片格式如.ts)。 - 合并失败不会丢分片。分片保留在临时目录,用同一个
--save-name和--dir重跑会跳过已下载的分片、只重做合并,不会重新下载。 - macOS quarantine。浏览器下载的二进制带
com.apple.quarantine,Gatekeeper 会在启动阶段直接 SIGKILL,表现为退出码 137、零输出、完全看不出原因。xattr -d com.apple.quarantine <二进制>解决;用 curl 下载的不会带这个属性。
工具
- 二进制查找顺序:
--bin/N_M3U8DL_RE指定的路径 → PATH → 脚本自身目录 →~/bin→~/.local/bin。都没找到时从https://github.com/nilaoda/N_m3u8DL-RE/releases取对应平台的包放进~/bin。 - 依赖
curl;--probe需要ffprobe(brew install ffmpeg)。 --range 0-10可只下一部分分片,适合先小量验证再跑完整下载。