MrXinYuan 发表于 2023-2-13 17:18

用Nuxt3做了一个m3u8在线下载工具

本帖最后由 MrXinYuan 于 2023-2-13 17:23 编辑

## 前言
之前一个朋友给我写了一个工具:m3u8在线下载工具,解释一下能够通过网页,下载m3u8视频到本地为Mp4,我就很震惊,随后了解到他使用了ffmpeg的wasm,最后又发现了一些列问题:wasm下载的话,会带来严重的跨域问题,可是经过研究油猴上某位大佬的这个工具我发现他的就不存在跨域问题,随后发现他的实现是使用ajax请求拿到每一个m3u8的ts片段,然后合并成为一个mp4,说干就干。

## 彩蛋
提前放个图,只看文字是在枯燥,也不知道各位看官有没有兴趣。


## 逛gay
要做一个程序,第一步当然是逛一下GitHub,找一找有没有可以用的轮子,当然让我找到了:https://github.com/Momo707577045/m3u8-downloader

这位大佬研究的很透彻,所以我还写什么呢?看大佬的就好了。似乎没有问题,不过我还是记下来留作是这次做这个小工具的纪念吧。

通过看大佬的代码,基本上了解了大概流程:
1. 使用ajax获取m3u8文件信息
2. 解析信息,判断是否需要解密,如果需要就那要密钥
3. 继续解析,获取到所有ts片段地址
4. 下载所有的ts片段并转换成mp4,同样是用Ajax,转换使用muxjs(如果需要解密的话先解密)
5. 最后把下载好的片段合并然后创建一个a标签下载

## 代码

以下代码仅为片段,完整版在这里:
https://github.com/ZN-GG/ZNGG-Nuxt3/blob/main/pages/tool/detail/M3U8V2Pro.vue

### 使用ajax获取m3u8信息
```ts
    const { origin } = new URL(url.value);
    let data = await ajax(url.value);
    if (data.indexOf('#EXT-X-KEY') > -1) {
      aesConf.value.status = true
      aesConf.value.method = (data.match(/(.*METHOD=([^,\s]+))/) || ['', '', ''])
      aesConf.value.uri = (data.match(/(.*URI="([^"]+))"/) || ['', '', ''])
      aesConf.value.iv = (data.match(/(.*IV=([^,\s]+))/) || ['', '', ''])
      aesConf.value.iv = aesConf.value.iv ? aesConf.value.stringToBuffer(aesConf.value.iv) : ''
      aesConf.value.uri = applyURL(aesConf.value.uri, url.value)
      await getAES();
    }
               
                // 获取AES配置
      async function getAES() {
                        // alert('视频被 AES 加密,点击确认,进行视频解码')
                        let res = await ajax(aesConf.value.uri, "arraybuffer")
                        aesConf.value.key = res
                        aesConf.value.decryptor = new AESDecryptor()
                        // aesConf.value.decryptor.constructor()
                        aesConf.value.decryptor.expandKey(aesConf.value.key);
      }
      
      function ajax<T = string>(url: string, type: XMLHttpRequestResponseType = "") {
    return new Promise<T>((resolve, reject) => {
      const xhr = new XMLHttpRequest();
      if (type) {
            xhr.responseType = type;
      }

      xhr.onreadystatechange = () => {
            if (xhr.readyState === 4) {
                const status = xhr.status;
                if (status >= 200 && status < 300) {
                  resolve(xhr.response);
                } else {
                  reject(new Error("请求失败"));
                }
            }
      };

      xhr.open("GET", url, true);
      xhr.send(null);
    });
}
```
               
### 防止错误文件缓存
有时候一些片段会下载错误,但是如果重新发起请求的话,chrome会拿起错误的缓存给我们,所以需要在下载时防止缓存,我们仅需要在ts后加一个不断变化的参数即可,时间戳就是一个不错的选择:
```ts
let r = '?r=' + new Date().getTime() + Math.random() + Math.random();
let data = await ajax<Buffer>(item.src + r, "arraybuffer");
```

### 剑走偏锋
标题起的好,其实就是个小垃圾找不到解决办法才这样的,在合成mp4的时候用的时mux.js这个js库,但是总是出现以ig问题:合成的mp4时间线有问题,2分钟的视频它写成俩小时,整个我肯定不能忍,但是无论如何都是这样,可是别人的又没有这个问题,于是我只能狗起来,明明用的时nuxt3,却只能像传统的html那样,外挂一个mux.min.js,去解决问题:
```ts
onMounted(() => {
    let script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = '/js/mux-mp4.min.js';
    document.getElementsByTagName('body').appendChild(script)
})
```
兄弟们,轻喷。


代码里有很多东西都是看前辈所写,另有一些自以为是的**优化**,故而成了现在这个样子。


那么下一个工具做什么呢?

侃遍天下无二人 发表于 2023-2-13 23:40

实际上跨域问题就不可能在前端绕开,并不是放个ajax就行了,脚本和插件是权限更高可以无视这个问题,比如我放gitee的一个m3u8你就下载不了

Access to XMLHttpRequest at 'https://kbtxwer.gitee.io/kyflow/21mooc/others/%E9%9B%85%E6%80%9DVIP%E5%90%AC%E8%AF%B4%E8%AF%BB%E5%86%99%E5%85%A8%E8%83%BD%E7%8F%AD/01-%E9%9B%85%E6%80%9D%E5%8F%A3%E8%AF%AD%E9%A2%98%E5%BA%93%E7%B2%BE%E8%AE%B2.m3u8' from origin 'https://www.zngg.net' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

MrXinYuan 发表于 2023-2-14 08:32

侃遍天下无二人 发表于 2023-2-13 23:40
实际上跨域问题就不可能在前端绕开,并不是放个ajax就行了,脚本和插件是权限更高可以无视这个问题,比如我 ...

一般来说确实是这样,但一般的资源并不存在这个问题。只是如果使用wasm的话,需要设置跨域隔离开启SharedArrayBuffer,一旦开启,就没有办法再网站内引用第三方的资源了,例如cdn的图片、js等

atoms 发表于 2023-2-13 18:32

厉害 很多m3u8是加密的 是不是没有办法下载

小懒虫丶 发表于 2023-2-13 18:45

学习一下,虽然不懂

131225 发表于 2023-2-13 20:18

学习一下,虽然不懂

alongzhenggang 发表于 2023-2-13 21:07

atoms 发表于 2023-2-13 18:32
厉害 很多m3u8是加密的 是不是没有办法下载

有的是插入几秒的TS加密    不管多长视频合并都只能播放十几秒

TS不合并反而正常

alongzhenggang 发表于 2023-2-13 21:09

atoms 发表于 2023-2-13 18:32
厉害 很多m3u8是加密的 是不是没有办法下载

还有的是开头加密下载不了

MrXinYuan 发表于 2023-2-14 08:27

atoms 发表于 2023-2-13 18:32
厉害 很多m3u8是加密的 是不是没有办法下载

很多加密的m3u8链接里面自带密钥,可以直接解密;还有的加密是为了方便仅在他们的软件里面播放,这种目前无法解密下载。

wangsking 发表于 2023-2-14 09:54

m3u8下载工具,很不错的教程!
页: [1] 2
查看完整版本: 用Nuxt3做了一个m3u8在线下载工具