本帖最后由 yhzc2023 于 2024-6-13 20:23 编辑
介绍m3u8格式
M3U8是一种用于播放视频流的文件格式,它被广泛应用于互联网视频流媒体服务。简单来说,m3u8文件是一种文本文件,里面列出了视频的各个部分(通常是.ts文件)的地址。播放器通过读取m3u8文件,按顺序播放这些视频片段,从而实现流畅的视频播放。
m3u8文件的结构
一个典型的m3u8文件包含如下内容:
#EXTM3U
:文件的标识符,表示这是一个m3u8文件。
#EXTINF:<duration>,<title>
:每个视频片段的时长(以秒为单位)和可选的标题。(重点关注)
.ts文件路径
:视频片段的具体文件路径。(重点关注)
#EXT-X-VERSION:<n>
:播放列表文件的版本号。
#EXT-X-TARGETDURATION:<s>
:播放列表中最长媒体段的时长(以秒为单位)。
#EXT-X-MEDIA-SEQUENCE:<number>
:播放列表中第一个媒体段的序列号。
#EXT-X-DISCONTINUITY
:指示播放列表中的不连续点,通常用于不同编码的片段之间的过渡。(重点关注)
#EXT-X-KEY
:指定用于解密媒体段的密钥。
#EXT-X-ENDLIST
:指示播放列表的结束。
例子:
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:10
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:10.0,
segment0.ts
#EXTINF:10.0,
segment1.ts
#EXT-X-DISCONTINUITY
#EXTINF:10.0,
segment2.ts
#EXT-X-ENDLIST
在这个例子中,播放器会依次播放 segment0.ts
,segment1.ts
和 segment2.ts
这三个视频片段,每个片段的播放时长为10秒。#EXT-X-DISCONTINUITY
指示播放器在播放 segment1.ts
和 segment2.ts
之间有一个不连续点,通常用于处理不同编码或不同来源的片段之间的过渡。
脚本实现原理
目的是去除m3u8视频中的广告段。通过hook xhr或者fetch获取m3u8文件,然后解析m3u8文件,删除那些不需要的广告片段,然后重新生成一个干净的m3u8文件。由于大部分视频网站为了不修改视频源文件,是不会将广告视频和普通视频整合成一个新的视频。这样通常会在m3u8文件里表现出普通视频片段和广告片段的文件名称不一致。脚本的工作原理是基于普通视频片段和广告片段的文件名称不一致。如果广告片段和普通视频片段的文件名称遵循相同的命名规则,本脚本将无法有效区分和删除广告片段。因此,适用此脚本的前提是广告片段的文件名称与普通视频片段的文件名称有明显的区别。
![1.png](data/attachment/forum/202406/13/201417zn7de4kcoacua0r0.png)
代码实现
以下是实现去除m3u8视频广告的JavaScript代码:
let lines = file.split('\n');
let processed_lines = [];
let index = 0;
let name_len;
let pre_name;
let next_name;
for (let line of lines) {
if (line.endsWith('.ts')) {
if (!next_name) {
pre_name = line.split('.ts')[0];
name_len = pre_name.length;
index++;
const str_index = String(index);
next_name = `${pre_name.substring(0, name_len - str_index.length)}${str_index}.ts`;
} else {
if (next_name != line) {
processed_lines.pop();
if (processed_lines[processed_lines.length - 1] == '#EXT-X-DISCONTINUITY') {
processed_lines.pop();
}
log(`删除${line}`);
continue;
} else {
index++;
const str_index = String(index);
next_name = `${pre_name.substring(0, name_len - str_index.length)}${str_index}.ts`;
}
}
}
processed_lines.push(line);
}
let processed_file = processed_lines.join('\n');
return processed_file;
详细解释
- 文件拆分: 首先,将m3u8文件的内容按行拆分成数组
lines
。
- 初始化变量: 初始化一些变量用于处理文件行,如
processed_lines
、index
、name_len
、pre_name
和 next_name
。
- 处理每一行:
- 如果行以
.ts
结尾,表示这是一个视频片段。
- 检查是否有
next_name
:
- 如果没有,初始化
pre_name
和 name_len
,并生成 next_name
。
- 如果有,比较
next_name
和当前行:
- 如果不同,移除最后一行
processed_lines
(最后一行是#EXTINF
标识),并检查是否有 #EXT-X-DISCONTINUITY
,如有则一并移除,并记录日志。
- 如果相同,更新
index
和 next_name
。
- 生成新的m3u8文件: 将处理后的行重新组合成字符串
processed_file
并返回。
关于 #EXT-X-DISCONTINUITY
#EXT-X-DISCONTINUITY
标签用于指示播放列表中的不连续点,通常出现在不同编码或不同来源的片段之间。它告知播放器在播放这些片段时需要处理潜在的编码变化或其他不连续性,上面代码不删除的话,会可能连续出现两个#EXT-X-DISCONTINUITY
标识,这样会导致播放到这位置的时候卡顿。
在本脚本中,当删除一个广告片段时,如果它前面紧挨着 #EXT-X-DISCONTINUITY
标签,这意味着原来这个标签是用来处理广告段的过渡。由于广告段被移除,这个标签就没有存在的必要了,因此脚本会将它一并删除,确保生成的m3u8文件的连续性和完整性。
注意
上面的代码修改代码不是一个通用的去除广告代码。m3u8格式是大同小异,里面视频的名称格式可能会不一样,需要按照实际的文件进行微调。
给两个网站大家可以去看看 一个是 粤语屋 看港剧的 在8分钟前后会出现广告。 一个是优酷 电视剧好像在2分钟左右出现广告。重点再提一下,去除的不是弹窗广告这些,测试优酷·最好有个会员,不然前面的非会员的倒计时广告会烦死。
脚本我放在下方,大家有兴趣的可以去看一下
脚本
最后
有没有大佬出手去折腾一下爱奇艺。爱奇艺也是用m3u8来播放的,不过它广告和视频是整合到一起的,从视频名称上区分不出来,所以没办法这样去除。不过也有个思路就是hook addSourceBuffer方法,获取一帧图像,然后通过识别图像里是否存在广告标识,存在就不要这一段视频数据。等一个有爱奇艺会员的大佬去试试,真实现了,请跟我说一声,让我去观摩一下。