直播是一回事,点播是另一回事。这一篇先把点播源的三种主流形态(采集接口、网盘、磁力)说透,再回到播放列表本身——M3U/M3U8 的两个身份、它和 TXT 的分野,以及两者怎么互转。
直播是「大家同时看同一段,错过了就没了」。点播是「我想什么时候看就什么时候看」。这个区别听起来很日常,但落到技术上是天壤之别。
这个差别在实用上有一个很直接的后果:直播源的整理靠人工,点播源的整理靠接口。因为点播内容是结构化的(有片名、有演员、有分类、有剧集列表),所以可以做成类似数据库查询的接口;直播没有这种结构,只能一条条手动排。
国内影视聚合圈子里,点播源 90% 以上说的都是CMS 采集接口。
事情的起源是国内有大量做影视站的站长,他们用同一套开源建站程序(苹果 CMS,英文常写作 MacCMS)搭站。这套程序有个特点:它把「内容」和「页面」分开了——内容是数据库里的数据,页面是模板渲染出来的。于是就有了「采集」这个玩法:A 站把自己的数据库内容通过一个标准接口吐出来,B 站写个脚本去「采集」过来,变成自己的内容,省得自己录数据。
时间一长,这个接口格式就成了事实标准。它大概长这样:
# 拉分类列表
http://站点域名/api.php/provide/vod/?ac=list
# 拉某个分类下的内容,第 2 页
http://站点域名/api.php/provide/vod/?ac=detail&t=6&pg=2
# 也可以指定返回 XML 还是 JSON
http://站点域名/api.php/provide/vod/at/xml/
http://站点域名/api.php/provide/vod/at/json/
返回的是一大坨结构化数据:
{
"code": 1,
"page": 1, "pagecount": 428, "total": 4276,
"list": [
{
"vod_id": 10245,
"vod_name": "某部电影",
"vod_pic": "https://.../cover.jpg",
"vod_remarks": "更新至第12集",
"vod_play_from": "$$$线路一$$$线路二",
"vod_play_url": "第01集$http://...#第02集$http://..."
}
]
}
看到关键了吗?vod_play_from 和 vod_play_url 这两个字段里塞着真正的播放地址。一个影片可以挂好几条线路(线路一、线路二),每条线路下有一串剧集地址。TVBox 这类软件做的事,就是拿到这份数据后,把它渲染成「海报墙 + 剧集列表」的界面,你点哪一集,它就去放哪一个地址。
因为线路会挂。线路一可能是某个 CDN,线路二是另一个采集站转过来的,线路三是网盘。用户看线路一卡了,切线路二。这是这套生态里最朴素的容错机制,也是为什么一个「接口」背后往往站着好几十个内容源。
传统采集接口的痛点很明显:视频文件得有人存、有人给带宽,成本高,所以源站很容易关。于是从 2022 年前后开始,一股「网盘源」的风潮起来了。
思路是:视频文件本身就放在网盘上(阿里云盘、夸克、115 等),软件只做两件事——解析出网盘的直链,然后播放。
这么做的好处几乎一半都在成本上:网盘企业有巨大的存储和 CDN,用户自己上传的东西自己承担成本,站长只需要维护一份「哪个片子在哪个网盘哪个分享链接里」的索引表。一份索引几 MB,维护成本趋近于零。
坏处也很明显:网盘接口经常变,解析经常失效;网盘方会做风控,看的人多了直接限速;分享链接会被举报删除。所以网盘源的「寿命」通常比传统源更短,但重建速度也更快。
在 TVBox 的配置里,网盘类站点通常要靠 spider jar 里的专用类来处理,需要配合网盘账号的凭证才能用。这也是为什么很多网盘配置会要求你「登录阿里云盘」——它不是要你的账号做坏事,而是必须拿着你的授权才能向网盘要直链。不过,把账号凭证交给一个来路不明的配置,风险还是要自己掂量。
严格说这不是「点播源」,而是另一种取片方式:不做内容托管,只维护一份种子或磁力链接的索引,播放器边下边播。它不需要服务器带宽,但依赖有人做种,冷门资源基本下不动。在国内这几年的网络环境里体验并不好,所以使用范围有限,这里只提一句,不展开。
你会经常看到 TVBox 配置里有个 parses 字段。这不是内容源,是解析器。
作用场景是这样的:有些片源不是直接给你一个 mp4 地址,而是给你一个网页链接(比如某个视频网站的播放页)。播放器自己播不了网页,需要有人去那个网页里把真正的视频地址「解」出来。这个动作就是解析。
解析分两大类:一类是通用解析,靠一套规则去匹配各家视频网站的页面结构,从而提取出真实地址;另一类是所谓的 VIP 解析,指的是通过第三方服务,把需要会员才能看的内容解出可播放的地址——这一类的法律风险相当高,属于典型的侵权辅助,第 12 章会讲。
在配置里它大概长这样:
"parses": [
{
"name": "某解析",
"type": 1, // 1 一般表示通用解析,失败会自动换下一个
"url": "https://.../jx?url=",
"ext": { "flag": ["qq", "youku", "iqiyi"] } // 只对这几个站点生效
}
]
ext.flag 那一行是重点:它告诉软件「这个解析器只管某几个站点」。所以一个配置里往往要堆十几个解析器,各自负责一片。这也是为什么 parses 列表总是很长。
M3U 这个名字,全称是 MP3 URL。它是上世纪九十年代 Winamp 播放器搞出来的一个播放列表格式,本意就是「我要放这么一堆 MP3,文件路径写在这」。
它的格式简单到有点简陋:第一行必须是 #EXTM3U,然后每个条目一行元信息、一行地址。就这么个东西。
M3U8 里的「8」指的是 UTF-8 编码。因为 M3U 诞生的时候,大家还在用各种本地编码(中文 Windows 上是 GBK),一个列表里混了不同语言的节目名就乱了。后来为了统一,就有了强制用 UTF-8 编码的 M3U8。功能上跟 M3U 没区别,只是「这个文件里的中文不会再乱码」。
很多人以为 .m3u 和 .m3u8 是两种东西,其实绝大多数情况下它们只是编码不同。但有一个重要例外:当 m3u8 用来做 HLS 流媒体清单时,它的内容结构跟播放列表完全不是一回事。同一个后缀,两种身份。这个下面单独讲。
作为播放列表的 m3u,结构是这样的:
#EXTM3U
#EXTINF:-1 tvg-id="CCTV1.cn" tvg-name="CCTV-1" tvg-logo="https://.../cctv1.png" group-title="央视",CCTV-1 综合
http://server.example.com/cctv1.m3u8
#EXTINF:-1 tvg-id="CCTV2.cn" tvg-name="CCTV-2" tvg-logo="https://.../cctv2.png" group-title="央视",CCTV-2 财经
http://server.example.com/cctv2.m3u8
#EXTINF:-1 group-title="卫视",湖南卫视
http://server.example.com/hunan.m3u8
拆开看,其实就三个部分在循环:#EXTM3U 是文件头,#EXTINF 那一行是这个频道的身份证加名片,下一行的 URL 是它的地址。
tvg-id 管 EPG、tvg-logo 管台标、group-title 管分组、逗号后面管显示名。除了上面这几个,你偶尔还会碰到另外几个指令。
| 指令 | 作用 | 什么时候会用到 |
|---|---|---|
#EXTGRP:分组名 | 单独给下面的条目指定分组 | 不想把 group-title 塞在 EXTINF 里时用,VLC / Kodi 支持更好 |
#EXTVLCOPT:http-referrer=… | 指定请求头里的来源页 | 最常见的补救指令。源有防盗链时必须带,否则一律播不了 |
#EXTVLCOPT:http-user-agent=… | 伪造 UA | 源只认手机端 APP 的 UA 时用 |
#KODIPROP:… | 给 Kodi 指定解码器参数 | 碰到加密流时可能要配 |
#EXT-X-… | HLS 专用,见下节 | 那是另一种身份了 |
很多官方源的服务器会检查「你是不是从我的网站过来的」,检查依据就是 HTTP 请求头里的 Referer。你在浏览器里能播,因为浏览器自动带了这个头;你把地址复制到 VLC 里播不了,因为 VLC 不带。解决办法就是加一行 #EXTVLCOPT:http-referrer=http://官方站点域名/。
同理,有些源只允许特定播放器的 UA 访问,就要用 http-user-agent 伪装。这两招能救回相当一批「看起来已经死了的源」,值得记一下。
现在讲那个容易混淆的部分。当一个 m3u8 文件的内容不是「频道列表」,而是「一集视频被切成的小片段的清单」时,它就是在做 HLS(HTTP Live Streaming)的索引。
HLS 的思路特别朴素:把一整段视频切成一个个 6–10 秒的小文件,用普通 HTTP 一个个下载下来连续播放。因为普通 HTTP 文件谁都会发,所以 HLS 兼容性好到离谱——只要有网,几乎什么设备都能播。
这份清单里藏着判断直播还是点播的关键信息。
#EXT-X-ENDLIST,这是点播,所有片段一次列全了,播完就完。#EXT-X-ENDLIST,而且片段列表一直在变,这是直播,播放器每隔几秒要重新拉一次这个清单,看看有没有新增片段。#EXT-X-KEY:METHOD=AES-128,URI="…",这个流是加密的。播放器得先去拿密钥才能解。有些源故意加密防偷链,这就是为什么你复制出来的地址放到别的播放器里放不了。还有一种是主清单(master playlist)。它一个片段都不列,只列出「这份直播有几个画质档」,每个档对应一个子清单的地址:
#EXTM3U
#EXT-X-STREAM-INF:BANDWIDTH=5000000,RESOLUTION=1920x1080
1080p/index.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=1500000,RESOLUTION=1280x720
720p/index.m3u8
播放器会根据自己的网速和屏幕,自动挑一档。这就是为什么同一个源,你在电视上和手机上看,画质可能不一样。有时候你播 HLS 源发现画质很差,不一定是源差,可能是播放器选错了档——手动把子清单的地址填进去,往往能救回来。
m3u 是这一行里最通用的格式,通用到「支持 m3u」这句话几乎每个播放器都敢写在介绍里。但同样是丢进去一份 m3u,你看到的东西完全不是一回事:VLC 给你一个扁平列表,Kodi 给你一个带电视频道界面的节目单,PotPlayer 把它当成一批要排队播放的文件。格式没有变,是软件把这个格式理解成了什么。
所以挑播放器的时候,这句话要往下拆一层。第一档是当电视频道用——有频道号、能分组、认台标、接节目单、遥控器操作顺手,这一类软件管自己叫 IPTV 客户端,不叫播放器。第二档是当播放列表用——一次导入成列表,点着能播,剩下的都没有,也没有节目单。第三档是只认单条流——它能播 m3u8 那条地址,但你把一整份 m3u 丢给它,它是打不开的,或者干脆把文件内容当文本弹出来。最麻烦的正是第三档:它长得像能用,你也以为自己在用第二档。
| 播放器 | 平台 | 支持到哪一档 | 节目单 |
|---|---|---|---|
| Kodi(+ PVR 插件) | 全平台 | 频道级 | 支持 XMLTV |
| TiviMate | 安卓电视 / Fire TV | 频道级 | 强项,网格节目单 |
| OTT Navigator | 安卓 / 安卓电视 | 频道级 | 强项,能自动匹配台名 |
| Televizo | 安卓 / 安卓电视 | 频道级 | 支持 XMLTV |
| IPTV Smarters 类 | 全平台(含 Win / Mac) | 频道级 | 支持 |
| Perfect Player | 安卓 / Windows | 频道级 | 支持 XMLTV、JTV |
| MyIPTV Player | Windows(应用商店) | 频道级 | 支持 |
| GSE Smart IPTV | 苹果 / 安卓 | 频道级 | 支持 |
| Plex / Emby / Jellyfin | 服务端 + 各平台客户端 | 频道级(当调谐器接入) | 支持,配 XMLTV |
| VLC | 全平台 | 播放列表 + 单条流 | 不支持 |
| PotPlayer | Windows | 播放列表 | 不支持 |
| MPC-HC / MPC-BE / MPV / IINA | 桌面(Win / Linux / macOS) | 播放列表 | 不支持 |
| 手机通用播放器(MX 类) | 安卓 / 苹果 | 只认单条流 | 不支持 |
按设备挑更省事。电视盒子和安卓电视——想省心就选 IPTV Smarters 这一类,想要最接近有线电视那种节目单体验就选 TiviMate 或 OTT Navigator。电脑上只想确认一个源是死是活——VLC,这也是它最擅长的事(第 2 章讲验证可用性时用的就是它)。手机——安卓上 Televizo 界面最轻,苹果设备上能挑的不多,GSE 是少数几个还在认真维护的。家里有 NAS——Jellyfin 或 Emby 把 m3u 当「电视调谐器」接进去,一份源全家设备共用,电视上、手机上看到的是同一份节目单。
两个误解值得单独讲。一是把 m3u8 当成 m3u:前者是一条流的地址,后者是一份清单;一个软件能播前者,不代表它认得后者,所以你才会遇到「明明这两个台都能播,怎么导入列表就不行了」。二是想让浏览器担这个活:浏览器能播单条 HLS 流,但把它当电视客户端用,分类、节目单、频道号一概没有,翻台靠滚。
最后一条经验:不管最后用哪个播放器,先用 VLC 过一遍。VLC 能打开,说明地址和网络都没问题,剩下的毛病都在播放器的配置上;VLC 都打不开,那多半是源本身死了,换播放器也是白换。这个顺序能省掉大量「到底是源的问题还是软件的问题」的来回折腾。
先说清楚一件事:TXT 直播列表不是任何国际标准,它是国内电视盒子软件圈子里自己约定出来的一套写法。所以不同软件对它的支持程度不一样,遇到不认的地方只能自己试。
最基础的形态长这样:
央视频道,#genre#
CCTV-1 综合,http://服务器/cctv1.m3u8
CCTV-2 财经,http://服务器/cctv2.m3u8
卫视频道,#genre#
湖南卫视,http://服务器/hunan.m3u8
浙江卫视,http://服务器/zhejiang.m3u8
看出来了吧,TXT 里承担「分组」功能的是一行特殊的 组名,#genre#。它不指向任何地址,纯粹是个分隔符。前面那个名字也不固定,有人写 央视,#genre#,有人写 CCTV,#genre#,软件一般只要求格式对,不要求内容。
更简单的写法连分组都省了:
CCTV-1,http://服务器/cctv1.m3u8
CCTV-2,http://服务器/cctv2.m3u8
这就是 TXT 的全部规则了。简单到任何人打开记事本就能改。
这不是技术优劣之争,是历史原因。
M3U 是跟着国际播放器生态进来的——VLC 用它、Kodi 用它、后来做电视直播的 Tivimate 也用它。这些播放器都讲究标准化,所以 M3U 的字段被定义得很完整。
TXT 则是国内电视盒子软件的产物。早些年盒子软件开发者想要一个「用户自己能改」的直播列表格式,M3U 太长太啰嗦(一个频道要写两行、一堆属性),于是干脆自己定了套一行就搞定的写法。因为简单,很快就被整个圈子抄来抄去了。TXT 不是标准,但胜在人人都会写。
如果你用的是 TVBox / 影视仓这一系,只用 TXT 就够,因为它处理得快。但如果你想要台标、想要 EPG 节目单、想给特殊源加请求头,就必须上 M3U——TXT 干不了这些。
最省事的办法其实是:两者都留一份。同一个频道列表,导出成 m3u 给带台标需求的场景用,导出成 txt 给轻量播放器用。
转起来不难,规则是一一对应的:
# M3U → TXT:丢掉属性,只留「名字,地址」
#EXTINF:-1 tvg-logo="xxx",CCTV-1 综合 → CCTV-1 综合,http://...
http://...
# TXT → M3U:把名字挪到逗号后面,前面补上属性
CCTV-1 综合,http://... → #EXTINF:-1 group-title="央视",CCTV-1 综合
http://...
手工转几十条还能忍,上千条就别折腾了,写个脚本或者找现成的转换工具,十分钟的事。转的时候有两个细节注意一下:一是编码统一存成 UTF-8(不带 BOM 更保险,有些播放器不认 BOM);二是原 TXT 里的 #genre# 行要转成 group-title,别傻乎乎当成频道名一起转过去。