2026 年 4 月 20 到 23 号,香港有一场 Web3 Festival。我本来是想去现场的。打开官网一看票价:一天通行证 199 美元,两天 299,四天 699。直接拜拜。
学生票是免费的。高兴了两秒,想起来学生卡一月份就到期了。学生时期彻底没了,只能改看线上直播,至少知道这几天大家都在聊什么、接下来会盯哪些方向。
看直播这件事,我很快就怂了。不是内容不好,是我盯不住。上学的时候三小时的课,注意力在线大概也就三十多分钟,剩下都在神游。直播更夸张:信息密度高、时间长、错过一段就很难补,论坛、分会场、圆桌还经常叠在一起。
所以我想换一种吃法:先把直播留下来,再转成文字,再丢给 AI 做全局总结。我自己只看重点,有疑问再追问。
这条链路后半段现在谁都会做。卡住我的是第一公里——视频从哪来。
卡住我的不是总结,是怎么把流抓下来
一开始我把问题想复杂了。视频号直播,听起来就像要写爬虫、抓包、装证书、挂代理。这些我都不熟。问了一圈 AI,得到的也多半是“用 mitmproxy 解密 HTTPS”“从 App 里抠播放地址”这种听着就劝退的方案。
我当时的判断很朴素:如果必须拆微信客户端、过证书校验,这件事大概率会烂在半路。活动只有四天,我没时间跟协议较劲。
于是换了个搜法。关键词就两个:微信直播、直播录屏。我要的不是“怎么破解微信”,而是“有没有人已经把直播留下来了”。
还试过几条更笨的路,很快就否了:
- 直接对着屏幕录。 文件巨大,风扇狂转,通知横幅、微信消息音都会进视频。四天活动这么干,硬盘和神经都会先炸。
- 找现成下载器。 点播或许有人做,直播这种会过期的 HLS 地址,几乎没有稳定可用的公开接口。
- Charles / 抓包。 就算能解开,也要一直盯着会话,直播一重连,地址就变。这不是我想要的“丢在后台跑”。
后来在知乎看到一个很巧的思路:微信视频号直播如何录屏。核心就一句话——微信投屏到电视,用的是标准 DLNA,不是私有加密通道。电视能收到直播流地址,那电脑也可以假装自己是一台电视。
对应的工具是 wechat-finder-dlna。作者把电脑伪装成局域网里的投屏设备,微信一点投屏,真实的 m3u8 地址就会送过来。不抓包,不装证书,不挂代理。微信这边看到的就是普通电视,没有“检测”可做。
这个思路一下子把问题从“对抗客户端”变成了“走官方投屏协议”。我决定先验证能不能拿到地址,再谈后面的 AI。
电脑假装是电视,地址就出来了
原理其实不神秘。微信视频号投屏走的是标准 UPnP/DLNA:设备在局域网里用 SSDP 组播喊一声“我是 MediaRenderer”,手机发现它之后,会发一个 SetAVTransportURI 的 SOAP 请求,把播放地址塞过来。后来这个工具还补了 AirPlay 和 Chromecast,三条协议一起听,兼容性更好,但对我来说 DLNA 已经够用。
第一次跑通大概是这样:
pip install wechat-finder-dlna
# 电脑开始在局域网里伪装成电视
wechat-finder-dlna
手机和电脑连同一个 WiFi,打开视频号直播,点投屏,列表里会出现这个设备。选中之后,终端里就会打出一条 m3u8 地址。工具也可以直接录:
wechat-finder-dlna --record live.mp4 --duration 01:00:00
底层还是把地址丢给本机 ffmpeg。我后面自己包的那层,本质上也是这件事,只是把“跑一次命令”变成了“能盯着、能停、能接着管”。
有几个坑是第一次就会碰到的,不写出来下次自己也会忘:
手机和电脑必须在同一局域网。 看起来像废话,但公司网、酒店网、开了 AP 隔离的路由器,组播过不去,投屏列表里就没有这台“电视”。我后来默认先检查:两边是不是同一个 SSID,路由器有没有开“无线隔离”。
它只能抓直播,不能抓回放。 点播、回放是另一套协议。我这次要的就是活动直播,所以刚好对上。如果以后想存视频号历史内容,这条路走不通。
地址会过期,流也会断。 m3u8 是切片清单,不是一个永远能下的 mp4。投屏拿到的 URL 带签名,过一会儿可能失效;直播中途重连,ffmpeg 也可能直接退出。所以“启动一次就不管了”是不成立的,必须能看见它还在不在写文件。
不要一上来就转码。 社区工具里有人用 -re 按实时速率读流,结果画面花、没声音。我后来固定用拷贝流:
ffmpeg -hide_banner -loglevel info -i "$STREAM_URL" -c copy -y "$OUTPUT"
-c copy 不重新编码,CPU 几乎不涨,画质也跟源一样。这就是我后面说“资源占用很少”的原因:Mac 只是在收 HLS 切片、往本地拼容器,不是在实时转码。
命令行第一次录出能播的 mp4 时,我是真觉得这事成了。然后活动还没开始,我就知道光靠这一条命令撑不住四天。
命令行能录,但撑不住一场活动
Web3 Festival 不是一个房间、一条流。主会场、分会场、圆桌经常并行。我不可能开四五个终端,每个里面挂一条 ffmpeg,再靠自己记得哪个 PID 对应哪场。
更烦的是这些“看起来很小”的操作问题:
Mac 会睡觉。 录直播最怕的不是 ffmpeg 挂,是电脑自己休眠。盖上盖、过了节能时间、插电策略一变,流就断了。所以后来在任务上加了可选的 caffeinate,录制期间禁止系统空闲休眠。这不是炫技,是被睡过去一次之后必须有的开关。
终端是黑盒。 ffmpeg 默认刷一堆 frame=、speed=、size=。你盯着看还行,一走开就不知道它是在正常收流,还是卡在重连,还是已经静默退出。我需要的是:文件还在变大吗、速度是不是 1x 附近、日志最后一行是什么、进程还活着吗。
停的方式会决定文件能不能播。 HLS 录成 mp4 时,索引信息往往在收尾阶段才写完整。直接强杀进程,文件可能打不开,或者只能播到一半。所以后来我把“停”和“杀”分成两个按钮:Stop 尽量让 ffmpeg 自己收尾,Kill 才是最后手段。Pause / Resume 则是给进程发暂停和继续,用来应付我临时要腾 CPU、或者确认一下目录空间的时候。
我已经有在跑的 ffmpeg 了。 做 App 之前,我已经用命令行先录过。GUI 如果不能把这些现成进程接管进来,那它就只是个启动器,不是管理器。所以后面有了 Attach by PID。
App 关掉,任务不能跟着消失。 四小时的会,我不可能一直把窗口开着。退出界面时,ffmpeg 应该继续在后台跑;下次打开,列表还在,PID 如果还活着,就重新接上监控。
这些需求凑在一起,已经不是一条 shell 别名能解决的了。我需要一个很小、但真正管进程的桌面工具。于是用 Xcode 很快搓了一个 macOS 应用:不重新发明拉流,只把本机 ffmpeg 管起来。代码在 Fang-zhixian/live-capture。
所以我做了个录制管理器,不是又写了个下载器
界面很土,就是一个任务列表。每条录制是一张卡片。我刻意没做成“输入 URL,然后祈祷”,因为我自己用的时候最需要的是状态,不是动画。打开现在还是这个样子:

新建任务时我真正在填什么
创建录制时可以配这些东西:
- 直播流 URL,也就是投屏截下来的
m3u8 - 保存目录
- 文件名前缀,避免主会场和分会场都叫
live.mp4 - 最长录制时长,防止我忘了停,磁盘被写满
- 要不要在录制时开
caffeinate
点 Add Recording 之后,App 调本机 ffmpeg 起进程。它不管微信,不管 DLNA,不管投屏。前面那一步仍然是:手机投屏 -> 拿到地址 -> 把地址贴进来。我没有把两段合成一个键,是因为投屏是一次性握手,录制是长时间挂机,两段失败模式完全不同。混在一起,出了问题你不知道是局域网组播没通,还是 ffmpeg 挂了。

每张卡片上那些字段,都是我被坑过之后才加上的
并行任务必须能一眼分开。卡片上会显示:
- 当前状态
- PID
- 保存路径
- 已写入大小
- 录制时长
- 处理速度
- 日志
- 上次刷新时间
这些不是为了看起来专业。HLS 最烦的一种死法是:进程还在,窗口也不报错,但文件大小不动了。有了“已写入大小 + 上次刷新时间”,我不用去猜。速度长期远低于 1x,多半是网络或源站在掉片;日志最后出现 Connection refused 或 403,就是地址过期了,该重新投屏拿一条新的 m3u8。
刷新不是一直狂打。一直 stat 文件、一直读 ffmpeg 输出,自己也会把风扇打起来。所以卡片上有 Refresh,也有轮询间隔。我要的是“过一会儿看一眼还活着”,不是再写一个监控系统。

Pause、Resume、Stop、Kill 我是按信号来理解的
四个按钮看起来重复,用过就知道不重复。
Pause / Resume 对应暂停和继续。适合中场休息、确认磁盘、临时把电脑拿去干别的。它不结束任务,PID 还在。
Stop 是正常结束。我会尽量走 ffmpeg 能处理的退出方式,让 mp4 把尾信息写完。活动一场结束,按这个。
Kill 是强制结束。进程卡住、Stop 没反应、CPU 被拖死时才用。我接受它可能留下一个不完整文件,总好过整个 App 被一个僵尸 ffmpeg 拖住。
这也是我后来坚持把 PID 展示出来的原因。信号是发给进程的。看不见 PID,出了问题还得自己去 ps aux | grep ffmpeg,那 GUI 就白做了。
Attach by PID:先有进程,后有界面
有一段时间工具还没做好,我已经用终端开录了。如果新 App 不能把这些进程收编进来,我就得停掉重录,活动直播没有重来一次的机会。
所以可以填一个已经在跑的 ffmpeg PID,用 Attach by PID 登记进列表。对这种外部任务,它会尽量认输出文件、读文件大小、轮询进程还在不在,并允许继续发暂停、恢复、停止、强杀。识别不了输出路径也没关系,至少能看见进程死活。这比“只能管自己拉起的子进程”实用得多。
持久化:关窗口不等于关录制
最后才做的是任务记录落地。规则很简单:
- 退出 App 不清空列表
- 下次打开恢复上一次的任务
- PID 还活着,就继续接监控
- 已经结束的任务先留着,直到我点清理
这里有一个很容易做错的点:把“界面进程”和“录制进程”绑死。如果 App 一退,ffmpeg 跟着被杀掉,那这个工具就只能在前台盯梢,没有意义。正确关系是:ffmpeg 是独立进程,App 只是控制面。重启之后用 PID 再 attach 回去就行。PID 被系统复用是小概率,所以还要核对:这个 PID 还是不是 ffmpeg、输出文件路径对不对。对不上就标成已结束,不要误杀别人的进程。
用下来到底怎样
这套东西没有我一开始幻想的那么“全自动”。每次开录仍然要:电脑上跑伪装电视 -> 手机投屏 -> 复制 m3u8 -> 在 App 里建任务。真正省下来的,是后面那几个小时我不用盯着。
实际效果和笔记里写的差不多:全程丢在后台跑,CPU 很低,风扇不怎么转。因为没有转码,录出来的画质就是源站的画质,够我后面做转写。多任务也能撑住——主会场一条,分会场再挂一条,卡片上各自更新大小和时长,不会混。
比较有用的一次,是我中途把 App 关了去干别的,过了很久回来,任务还在,PID 还活着,文件还在涨。如果那天只能靠终端窗口活着,我大概率已经把录制一起关掉了。
也有没解决干净的地方。流地址过期之后,它不能自己去微信里重新投屏。断了就是断了,我得再走一遍投屏拿新 URL。同一场活动如果切会场、切清晰度,也常常是一条新地址。所以它是“录制管理器”,不是“视频号爬虫”。我接受这个边界。边界清楚,反而比做一个会悄悄失败的全自动更可靠。
后半段还没做完,但方向已经清楚
到这里,我只走完了整条信息流的前半段:稳定地把直播变成磁盘上的视频文件。
后面还没接上。计划仍然是:
- 语音转文本。长视频会先按时间切开,不然一次丢给转写模型又慢又贵。
- 让 AI 按场次做结构化摘要:观点、争议、点名的项目/人、我可以跟的行动项。
- 只对我关心的段落再问。比如某条监管口径、某个技术选型,我再去对原始转写,而不是从头看四小时。
我刻意没在录制工具里塞转写。录制是 IO 和进程管理,转写是文件和模型。两件事的失败方式不同,混在一个按钮里,调试会很痛苦。现在的分工更干净:DLNA 负责拿到地址,ffmpeg 负责写成文件,App 负责让这个过程可控,AI 负责我没时间看的那部分。
如果以后再碰到类似的活动,我大概还是会这么干。不是因为这套方案有多高级,而是因为它把一个看起来像“要逆向微信”的问题,收成了三件我能掌控的小事:同一局域网、一条 m3u8、一个还活着的 ffmpeg。
录制管理器的代码和截图在 GitHub: Fang-zhixian/live-capture。