Downie 3实战:HLS/DASH网页视频下载、分片合并与音画同步修复

发布时间:2026/10/23 19:02:35
Downie 3实战:HLS/DASH网页视频下载、分片合并与音画同步修复

简介:面向 macOS 用户的 Downie 3 应用包,定位于网页视频下载与本地化研究场景,适合需要保存 1080p、4K 等清晰度视频,或希望了解这类下载工具内部资源组织方式的读者。压缩包共 432 个文件,约 29.87MB,以 nib、strings、png、dylib、html、plist 等为主,分别对应界面布局、多语言文本、图标素材、动态库、帮助页面与配置信息,并含有 ffmpeg、rtmpdump 等组件相关文件。已有 483 人学习下载。其目录保留了较完整的应用资源结构,可用于查看菜单与窗口布局、多语言字符串、扩展与更新模块,以及下载引擎依赖的组织方式,为汉化适配、资源提取和同类工具结构分析提供参照。需注意,该包为编译后的应用资源,不包含可读源码。

1. 网页里那个视频,为什么“另存为”只得到一个几百 K 的文件

上个月又有人问我同一个问题:网页里放着一段课程回放,右键“存储为”,下来的却是个两百来 KB、后缀是 .m3u8 的文本文件,双击打不开,拖进播放器一片黑。这不是操作问题,是网页视频这套工具链本身的分发方式决定的——真正播放的内容根本不在那个<video>标签的src里。

Downie 3 就是冲这个场景做的 macOS 下载工具。它把页面加载过程中散落出去的媒体请求收集起来,认出哪些是视频流、哪些是音频流,再按索引把分片拉回本地拼成一份能直接播放、能拖进剪辑软件的完整文件,支持画质和音轨挑选、字幕抓取、批量队列。

适合谁:需要把网页里的教程、会议回放、素材留档,并且要求落地文件能离线播、能二次处理的人。如果你只是偶尔存一次、不介意画质和音轨混乱,浏览器自带的录制也能凑合;但要做归档和批量,后面几章的参数才真正省时间。

2. 拆开嗅探逻辑:网页视频的三种承载方式与合并链路

2.1 直链、HLS、DASH:先认脸再动手

很多翻车都出在没分清手上这条链接属于哪一类。三类流的下载难度差着量级,工具能不能处理,往往在点下“下载”之前就能判断出来。

类型页面特征你拿到的第一个东西主要难点
直链 MP4<video src="...mp4">直接可见一个完整的 .mp4基本没有,注意码率即可
HLS地址里出现.m3u8几 KB 的 UTF-8 播放列表分片多、可能多层嵌套、音视频分离
DASH地址里出现.mpd一份 XML 清单音轨视频轨分开下,必须合并

HLS 要分两层看。上层是 master playlist,里面用#EXT-X-STREAM-INF列出好几档码率,每档指向一个 media playlist;下层才是真正的播放列表,一串几秒长的.ts或者.m4s分片,每行前面带#EXTINF标时长。所谓“下载”,本质是把这些分片按顺序拉下来、按时间戳重新排好、再封装成一个文件。DASH 的思路类似,只是清单换成了 XML,音轨和视频轨几乎一定是分开的两条流,落地前必须 mux。

认脸的办法很土但有效:在浏览器的开发者工具里筛 Media 类型的请求,看最先出现的那个不是分片的请求,多半就是清单。清单文件通常只有几 KB,分片动辄几百 KB 到几 MB,大小一看就分得开。

2.2 Downie 3 的处理链路:监听、选变体、拉分片、封装

它的工作方式不是“解析网页源码找链接”,而是在一个内置的轻量浏览器视图里把页面真正加载一遍,同时监听所有出站的媒体请求。页面自己触发播放、加载清单的那一刻,请求就被截住了。这条路子对现在这种靠脚本动态拼接地址的页面更稳,但也带来一个副作用:页面不开始播,它就看不见——这一点在排查章节还会再提。

一次完整的下载大致走这么几步:

  1. 加载 URL,等页面发出媒体请求,按Content-Type归类(application/vnd.apple.mpegurl、application/dash+xml、video/mp2t、video/mp4等)。
  2. 命中清单后递归解析,把 master playlist 里所有码率变体列出来,交给界面让你选,或者按预设策略自动挑最高一档。
  3. 对选中的 media playlist 并发拉取分片,默认会开几路并行,这个并发数在偏好设置里可以调,网络差的时候降到 2~3 路反而更稳。
  4. 分片落地后按序拼接,读取每片的解码时间戳,重新生成一条连续的时间线,再做 demux + mux,封装成 MP4 或 MOV。
  5. 若开启后处理,再走一遍转码;不开就直接交付封装结果,速度快很多。

第 4 步是整条链路的胜负手。分片拼接不是简单地cat到一块,那样得到的文件时长和音画同步基本都会出问题。正规做法是让解复用器逐片读出 PTS/DTS,再让复用器按新时间线写容器头。这也是为什么有些工具下完的文件用播放器能播、拖进度条却乱跳——时间线没重建干净。

2.3 三个真正影响结果的开关

界面上的选项不少,但对成品质量有实质影响的就三个:

开关取值对结果的影响
画质策略最高 / 询问 / 上限锁定决定从 master playlist 里挑哪一档变体,锁定上限能避免误下 4K 撑爆硬盘
字幕处理自动抓取 / 外挂 srt / 内封抓的是页面自带的字幕轨,不是硬字幕,硬字幕只能靠画面 OCR,工具帮不上
后处理仅封装 / 转码仅封装几秒完成,画质无损;转码为了兼容某些老播放器,代价是时间和画质

我一般把画质策略设成“询问”,因为批量下载时自动挑最高经常下出一堆几百 MB 的 4K 文件,而实际用途只是拿来对字幕。硬盘和带宽都不便宜,尤其是要连续下几十期的时候。

3. 从安装到落地:一条链接走完提取、选流、命名

3.1 装到应用目录并确认包完整

从压缩包解出来的.app直接双击运行也能跑起来,但位置在下载目录里,之后用 Spotlight 找不到、系统更新也容易出岔子。标准做法是拖进/Applications。第一次打开如果被系统拦下,去“系统设置 → 隐私与安全性”里放行即可,别去关全局的 Gatekeeper。

装完先花十秒确认这个包没被二次打包过:

# 查看签名链,确认 Authority 一栏是完整的开发者签名而不是 ad-hoc codesign -dv --verbose=4 "/Applications/Downie 3.app" # 让系统评估这个可执行文件是否被允许运行 spctl -a -vvv -t exec "/Applications/Downie 3.app"

codesign -dv输出的Authority列表如果只有一行adhoc,说明这是重签过的包,功能可能残缺;正常应该是完整的证书链加上TeamIdentifier。spctl的预期输出是accepted加source=Notarized Developer ID,rejected就说明公证没过。这两条命令不解决任何功能问题,但能让你在花了半小时排查“为什么下不了”之前,先排除掉包本身有问题这种可能。

3.2 单条链接的完整操作

先在内置浏览器里把页面打开、让视频真正播起来几秒,再回主界面。顺序反了经常什么都抓不到。

  1. 复制页面 URL,粘进地址栏回车,等页面加载完。
  2. 点一下播放按钮,看到画面动起来就暂停,此时请求已经发出去了。
  3. 界面上会出现识别到的媒体条目,点开格式列表,能看到每一档变体的分辨率、编码、预估体积。
  4. 选一档,设定输出目录,开始。
  5. 进度到 100% 后不要立刻关窗口,等“处理中”这步走完——合并和封装是在这一步做的,提前关会得到一个只有视频轨没有音频轨的半成品。

第 3 步那个格式列表是整篇里最值得多看两眼的地方。同一页面经常同时挂着 1080p 的 H.264 和 4K 的 HEVC,前者兼容性好、体积小,后者清晰但对播放器和剪辑软件都有要求。列表里如果某一档的体积明显偏小(比如 4K 却只有 20 MB),那多半是只包含视频轨或者码率被压过,别贪那个分辨率。

3.3 批量与浏览器联动

一次要下十几期的时候,一条条粘是纯浪费时间。把 URL 一行一个写进文本文件,直接从菜单里导入列表,队列会自己跑。真正省事的做法是装浏览器扩展,在页面上点一下图标,当前页就直接丢进 Downie 的队列,连复制粘贴都省了。

批量跑的时候有两个细节:一是把并发下载数调到 2,别贪多,同时开五六个任务在多数家用带宽下总耗时反而更长;二是提前把输出目录设成一个独立的文件夹,别和已有的素材混在一起,后面归档脚本才好写。

3.4 输出目录与命名模板

命名模板支持插变量,常用的几个:

变量含义建议
标题页面标题必选,但注意标题里可能有/和:,模板会自动替换
日期下载日期加在开头,方便按时间排序
分辨率如 1080p同一内容下了多档时用来区分
序号队列中的位置批量时防止重名覆盖

我自己的模板是日期-标题-分辨率,落地后文件名形如2024-06-12-某课程第 3 讲-1080p.mp4。按日期开头的好处是访达里默认按名称排序就是时间顺序,找起来不用翻。

下载目录攒到几十个文件之后,手动分类就没意义了,挂个脚本按月归档:

#!/usr/bin/env bash set -euo pipefail # 下载落地目录与归档根目录,按实际路径改 SRC="$HOME/Movies/Downie" DST="$HOME/Movies/Archive" # 只处理成品文件,跳过处理中的临时文件 find "$SRC" -maxdepth 1 -type f \( -iname '*.mp4' -o -iname '*.mkv' -o -iname '*.mov' \) -print0 | while IFS= read -r -d '' f; do # 用文件修改时间生成 YYYY-MM 子目录 d=$(date -r "$f" +%Y-%m) mkdir -p "$DST/$d" # -n 防止同名覆盖,重名会自动加后缀 mv -n "$f" "$DST/$d/" done

-print0配read -d ''是为了扛住文件名里的空格和中文,这是 macOS 上跑批量脚本最容易踩的一脚。date -r取的是文件修改时间,不是创建时间,因为合并后的成品修改时间才是落地时间。mv -n保证重名时不覆盖,宁可多出一份也不丢文件。

4. 画质、音轨与容器:把“要不要 4K”变成可判断的参数

4.1 码率、编码、容器三件事别混

三个词经常被当成一件事说,实际各管一摊。容器是外壳(MP4、MOV、MKV),决定能装几条轨;编码是压缩方式(H.264、HEVC、AV1),决定解码开销和兼容性;码率是每秒塞多少数据,直接决定体积和画质上限。

分辨率H.264 常见码率HEVC 常见码率一小时约合体积(HEVC)
720p2~3 Mbps1.2~2 Mbps0.6~0.9 GB
1080p4~8 Mbps2.5~5 Mbps1.1~2.2 GB
2160p15~25 Mbps8~15 Mbps3.6~6.7 GB

同样是 1080p,4 Mbps 和 8 Mbps 在静止画面上几乎看不出差别,但一到快速运动的镜头,低码率那档就会出现明显的块状糊。判断办法不是看分辨率数字,是看格式列表里给出的码率,低于 3 Mbps 的 1080p 要心里有数。

容器这块,MP4 兼容性最好,剪辑软件、播放器、手机都能吃;MKV 能装更多轨但部分播放器不认。默认选 MP4 就够,除非你要保留多条音轨和字幕轨一起分发。

4.2 HLS 合并后的时间戳修正

分片拼出来的文件偶尔会出现音画不同步,或者进度条拖到某个位置就卡住。原因通常是分片之间的 PTS 不连续——有些站点为了防盗链会把时间戳重置,拼接时就产生了一段跳跃。这时候不用重下,重新封一遍就能救回来:

# 让 ffmpeg 重新生成缺失的时间戳,而不是沿用分片里的原始值 ffmpeg -fflags +genpts -i input.mp4 -c copy -movflags +faststart output.mp4

-fflags +genpts是关键,它让解复用器在遇到时间戳断层时按帧率补算,而不是直接照搬。-c copy表示不重新编码,所以整个过程只做读写,速度取决于硬盘,几分钟就能跑完一小时的片子。-movflags +faststart把索引挪到文件头,网页播放器可以边下边播,本地播放器拖进度条也会更跟手。

如果加了genpts还是不同步,那就是音频采样率和视频帧率对不上,得单独处理音轨,-af aresample=async=1让音频重采样对齐。这种修法会破坏音频的原始精度,只在确实救不回来的时候用。

4.3 字幕与音轨:外挂还是内封

抓下来的字幕默认是外挂 srt,改起来方便,但发给别人容易漏。要固化进文件的话,用 MP4 的mov_text格式内封:

# 把外挂字幕封进 MP4,不重新编码视频和音频 ffmpeg -i input.mp4 -i subtitle.srt \ -c:v copy -c:a copy -c:s mov_text \ -metadata:s:s:0 language=chi output.mp4

-c:v copy -c:a copy保证视频音频原样搬过去,只有字幕轨是新写的,秒级完成。-metadata:s:s:0给第一条字幕轨打语言标签,播放器才会在菜单里显示“中文”而不是“字幕 1”。MKV 容器用-c:s srt,兼容面更宽。

多音轨的情况类似,先ffprobe看清楚哪条是原声哪条是配音,再用-map 0:a:1指定保留哪一条。不定-map的话默认只留第一条,多音轨素材经常就这么静悄悄丢了一条。

5. 常见问题排查:五条现场记录与对应动作

5.1 链接粘进去一直停在“等待中”

现象:地址栏回车后页面能正常显示,但媒体条目始终不出现,或者只闪一下就没了。

原因:多数是页面在用户交互之后才发出媒体请求——播放按钮绑了脚本,不点就不请求。另一种情况是清单走了加密(#EXT-X-KEY带METHOD=AES-128),工具拿不到密钥就会静默放弃。

解决:先在内置浏览器里点播放,让画面动起来几秒再回主界面。如果播放正常但依然抓不到,去开发者工具里看一眼清单里有没有EXT-X-KEY行,有的话说明这条流是加密分发的,工具侧解决不了,别在这上面耗时间。

5.2 下载完成音画不同步

现象:画面和声音差半秒到两秒,越往后差得越多,拖进度条之后更明显。

原因:分片时间戳不连续,拼接时按原始 PTS 硬拼,误差累积。或者源流本身是变帧率的,合并后按固定帧率解释。

解决:先按 4.2 节那条命令重封一遍,八成能解决。仍然不行就用ffprobe看两条流的时长差:

# 分别输出视频流和音频流的时长,差值超过 0.2 秒基本就是拼接问题 ffprobe -v error -select_streams v:0 -show_entries stream=duration -of csv=p=0 input.mp4 ffprobe -v error -select_streams a:0 -show_entries stream=duration -of csv=p=0 input.mp4

两个数差得多,说明有一路分片丢了或者重复了,只能重下。

5.3 4K 下下来播放器黑屏

现象:文件体积对得上,播放器打开有声音没画面,或者干脆全黑。

原因:4K 那档多半是 HEVC 编码,老版本播放器、部分剪辑软件的解码器不认。另一种可能是选了只含视频轨的变体,音频在另一条流里没合并进来。

解决:先用ffprobe确认编码和轨道数,codec_name=hevc且只有一条流,就是播放器问题加音轨缺失的双重打击。换播放器能验证,要长期用还是转成 H.264:

# 转成 H.264 并保留原分辨率,crf 20 在画质和体积之间比较平衡 ffmpeg -i input.mp4 -c:v libx264 -crf 20 -preset medium -c:a aac -b:a 192k output.mp4

转码是纯 CPU 活,一小时 4K 素材在笔记本上跑小半天很正常,别指望快。

5.4 下下来的文件比预期小很多

现象:明明选了最高画质,落地文件只有几十 MB,画面糊得厉害。

原因:master playlist 里的“最高档”未必真的是最高,有些站点会把 4K 放在单独的清单里或者用不同的路径;也可能你选中的那档本身就是低码率预览流,真正的高码率要另外触发。

解决:回到格式列表,逐档对比码率而不是只看分辨率标签。列表里如果有两档都是 1080p,选码率高的那档。实在拿不准就先下一小段试看,确认清晰度再批量跑。

5.5 中断后重下从零开始

现象:网络抖了一下任务失败,重新开始进度条从 0 走,之前下的白费。

原因:部分站点的分片响应不带Content-Length,工具没法判断已下载的片段是否完整,只好整条重来。

解决:这类流直接交给 ffmpeg 去拉,它支持从断点续传分片:

# 直接对清单地址拉流,-c copy 不重新编码,断线后重跑会从已完成的片段继续 ffmpeg -protocol_whitelist file,http,https,tcp,tls \ -i "https://example.com/path/master.m3u8" \ -c copy -bsf:a aac_adtstoasc output.mp4

-protocol_whitelist是必须加的白名单,不声明的话 ffmpeg 会拒绝走网络协议。-bsf:a aac_adtstoasc处理的是 HLS 里 AAC 音频的 ADTS 头,不加的话封进 MP4 后部分播放器会没声音。这条命令不挑画质,拉的是清单里默认那一档,需要指定变体得先手动改清单内容。

6. 进阶:把下载接进归档流,顺手做一次校验

批量下载和归档这件事,真正省时间的不是工具本身,是下完之后那一步校验。我现在的习惯是每批跑完立刻做一次抽检:

# 一次性输出编码、分辨率、帧率、码率和轨道类型,异常值一眼能看出来 ffprobe -v error \ -show_entries stream=index,codec_type,codec_name,width,height,r_frame_rate,bit_rate \ -of csv=p=0 input.mp4

正常的输出应该能看到两行:一行video带分辨率和帧率,一行audio带码率。只有一行就说明有轨丢了,bit_rate是个离谱的小数字说明码率异常。这个检查十秒钟,比事后发现三十个文件全都没声音要划算得多。

清单文件跑批的做法也简单:把 URL 一行一个存成list.txt,配合 3.4 节的归档脚本,一条流水线就是“导入列表 → 队列跑完 → 归档脚本按月分目录 → ffprobe 抽检”。整个流程里唯一需要人盯着的是格式列表那一步,其余都能挂后台。

有个模板变量值得单独说:如果你经常下同一系列的内容,把序号变量放进文件名,配合归档脚本的月份目录,一年下来目录结构会非常干净,找某一期时不用回忆是哪天下的。

血泪教训是去年一次批量归档,图省事没做校验,等要剪的时候才发现其中十几期只有视频轨——那批源站把音频放在独立的 DASH 流里,工具选中的变体恰好只含视频。从那以后我每次批量跑完都强制走一遍 ffprobe 抽检,哪怕只有五个文件也照跑。希望帮到你。

本文还有配套的精品资源,点击获取