这篇文章要解决什么
很多人第一次研究 yt-dlp 时会卡在两个点:
- 它“怎么知道去哪下载”(分辨率/音轨/链接从哪里来)?
- “分片”到底是什么(为什么看着有很多链接/很多请求)?
这篇用尽量通俗的方式把整条链路串起来。
1. yt-dlp 本质上在做什么
可以把 yt-dlp 想成一条固定流程的“下载编排器”:
- 拿到播放器的播放配置(Player JSON)
- 从里头挑选可用的音视频格式(format / itag)
- 取出对应格式的下载入口(url 或 manifest)
- 下载阶段按协议把数据取回来(Range 分块,或清单里的 seg 分片)
- 若音视频分离,则用 FFmpeg 合并成最终文件
2. Player JSON 是什么(最关键的“菜单”)
Player JSON 来自:
- 网页里常见的
ytInitialPlayerResponse - 或接口
youtubei/v1/player
它不等于视频文件本身,而是“这条视频怎么播”的说明书,常见包含:
playabilityStatus:能不能播(有时需要登录/风控)videoDetails:标题、时长等streamingData:真正决定你能下载什么、下载入口在哪里formats:一些合并流(音视频在一起)adaptiveFormats:一些分离流(视频-only / 音频-only)- 可能还有
hlsManifestUrl/dashManifestUrl:清单入口
3. streamingData 里的 url:你看到的链接是什么
在 streamingData.formats / streamingData.adaptiveFormats 里看到的 url,通常是某个 itag 对应的媒体下载入口(例如 googlevideo.com/videoplayback?...)。
注意它的性质:
- 它是“可下载入口”,不是“裸打开就能看”的公开网页
- 往往带有时效参数/签名/会话绑定等,因此直接复制到浏览器地址栏常常会失败
- 正确用法是:让 yt-dlp/播放器按它的下载协议去请求并获取数据
4. “分片”到底是什么(两种最常见情况)
情况 A:直链模式(同一条 url + 多次 Range 请求)
很多时候 JSON 里只给你“一个底链 url + 文件大小”,下载器会对同一个 url 发多次请求:
Range: bytes=start-end
所以你在 Network 面板里看到很多 videoplayback?...&rn=1,2,3...,通常对应的不是“JSON 里预先给了几百条不同 URL”,而是“下载阶段按字节范围多次取数”。
情况 B:清单模式(m3u8/mpd 清单 → seg 分片)
如果拿到的是 HLS/DASH 清单入口(例如 hlsManifestUrl),流程通常是:
- 下载清单(主清单 m3u8)
- 找到某个画质对应的 variant/media 清单
- 从清单里得到大量
seg.ts(或 dash 的 segment 列表) - 按顺序下载分片并封装/合成
你之前打开的那种超长 .../playlist/index.m3u8,就是清单的一层。
5. 最终怎么变成一个“完整视频文件”
常见有两类结果:
- 选了合流格式(
formats里那种)
下载完成通常就是最终 mp4/webm 文件。 - 选了分离格式组合(例如
313 + 140:视频-only + 音频-only)
yt-dlp 会分别下载视频轨和音频轨,然后用 FFmpeg 合并成一个容器文件。
一句话总结
yt-dlp 的核心是:
先用 Player JSON/streamingData 找到“怎么选格式、下载入口在哪” → 再按协议(Range 或清单分片)把字节取回来 → 必要时用 FFmpeg 合并。
(补充方便理解:多数情况下“分片”本质仍是同一个媒体文件/同一底链(同一底链=同一个主要媒体入口/底 URL,通常只是分块相关参数如 rn/Range 在变化),不是换成完全不同的文件;只是客户端通过不同请求参数(例如 Range 区间,或 HLS/DASH 清单列出的不同片段 URL)去取不同部分。你在浏览器 Network 里看到的 rn=1/2/3...,通常就对应播放器对同一底链连续取“下一段字节”(有时也可能包含重试),因此最终会被拼成可播放的内容。)
评论区