GithubHelp home page GithubHelp logo

m3u8-downloader's Introduction

m3u8 视频在线提取工具(English version)

界面

工具在线地址,推荐使用 chrome 浏览器。

研发背景

  • m3u8视频格式简介

    • m3u8视频格式原理:将完整的视频拆分成多个 .ts 视频碎片,.m3u8 文件详细记录每个视频片段的地址。
    • 视频播放时,会先读取 .m3u8 文件,再逐个下载播放 .ts 视频片段。
    • 常用于直播业务,也常用该方法规避视频窃取的风险。加大视频窃取难度。
  • 鉴于 m3u8 以上特点,无法简单通过视频链接下载,需使用特定下载软件。

    • 但软件下载过程繁琐,试错成本高。
    • 使用软件的下载情况不稳定,常出现浏览器正常播放,但软件下载速度慢,甚至无法正常下载的情况。
    • 软件被编译打包,无法了解内部运行机制,不清楚里面到底发生了什么。
  • 基于以上原因,开发了本工具。

工具特点

  • 无需安装,打开网页即可用。
  • 强制下载现有片段,无需等待完整视频下载完成。
  • 操作直观,精确到视频碎片的操作。

功能说明

【解析下载】输入 m3u8 链接,点击下载视频。 【跨域复制代码】当资源出现跨域限制时,点击复制页面代码,在视频页面的控制台输入。将工具注入到视频页面中,解决跨域问题。 【重新下载错误片段】当部分视频片段下载失败时,点击该按钮,重新下载错误片段。 【强制下载现有片段】将已经下载好的视频片段强制整合下载。可以提前观看已经下载的片段。该操作不影响当前下载进程。 【片段Icon】对应每一个 .ts 视频片段的下载情况。「灰色」:待下载,「绿色」:下载成功,「红色」:下载失败。点击红色 Icon 可重新下载对应错误片段。

使用说明

  • 打开视频目标网页,鼠标右键「检查」,或者「开发者工具」,或者按下键盘的「F12」键

  • 找到 network,输入 m3u8,过滤 m3u8 文件。

  • 刷新页面,监听 m3u8 文件。

  • 找到目标m3u8文件,查看文件内容,是否符合格式。

    • 如下为索引文件,不是真正的视频 m3u8 文件

    • 一般内容有许多 ts 字眼的文件才是我们需要的视频 m3u8 文件。

  • 拷贝这个 m3u8 文件的链接。

  • 打开工具页面,输入链接,点击「解析下载」。

  • 出现片段 Icon,则证明操作成功,耐心等待视频下载。

  • 片段全部下载成功,将触发浏览器自动下载,下载整合后的完整视频。

  • 如果有片段下载失败,则点击对应片段,或点击「重新下载错误片段」按钮。重新下载错误片段。

异常情况

【无法下载,没有显示片段Icon】

  • 一般由于跨域造成。

  • 点击「跨域复制代码」按钮。

  • 打开视频目标网页的「开发者工具界面」,找到 console 栏。

  • 粘贴刚刚复制的内容,回车。

  • 滚动页面到底部,发现工具显示在底部。然后在注入的工具中正常使用。

【下载后的视频资源不可看】

  • 网站对视频源进行了加密操作。不同的视频网站有不同的算法操作。无法通用处理。

  • 一般网站不会有这种情况。爱奇艺,腾讯等大视频网站才会有该安全措施。

实现思路

【下载并解析 m3u8 文件】

  • 直接通过 ajax 的 get 请求 m3u8 文件。得到 m3u8 文件的内容字符串。读取字符串进行解析。

  • 需要注意的是,m3u8 文件不是 json 格式,不能将 dataType 设置为 json。 【队列下载 ts 视频片段】

  • 同样使用 ajax 的 get 请求视频碎片,一个 ajax 请求一个 ts 视频碎片,但关键点在于,下载的是视频文件,属于二进制数据,需要将 responseType 请求头设置为 arraybuffer。xhr.responseType = 'arraybuffer'

  • 使用队列下载,是因为视频碎片太多,不可能一次性请求全部。需要分批下载。

  • 同时由于浏览器同源并发限制,视频同时请求数不能过多。本工具设置为并发下载数为 10。 【组合 ts 视频片段】

  • 看似很难,但其实使用 Blob 对象即可将多个 ts 文件整合成一个文件。new Blob(),传入 ts 文件数组。

  • 这里有个小细节需要注意,需要在 new Blob 的第二个参数中设置文件的 MIME 类型,否则将默认为 txt 文件。 const fileBlob = new Blob(fileDataList, { type: 'video/MP2T' }) 【自动下载】

  • 下载,当然先要获得文件链接,即刚生成的 Blob 文件链接。

  • 使用 URL.createObjectURL,即可得到浏览器内存中,Blob 的文件链接。URL.createObjectURL(fileBlob)

  • 最后,使用 a 标签的 a.download 属性,将 a 标签设置为下载功能。主动调用 click 事件a.click()。完成文件自动下载。

核心代码

【整合及自动下载】

    // 下载整合后的TS文件
    downloadFile(fileDataList, fileName, fileType) {
      this.tips = 'ts 碎片整合中,请留意浏览器下载'
      const fileBlob = new Blob(fileDataList, { type: 'video/MP2T' }) // 创建一个Blob对象,并设置文件的 MIME 类型
      const a = document.createElement('a')
      a.download = fileName + '.' + fileType
      a.href = URL.createObjectURL(fileBlob)
      a.style.display = 'none'
      document.body.appendChild(a)
      a.click()
      a.remove()
    },

是的,涉及新知识点的部分只有上面一小段,其他的都是 JS 的基础应用。

除了 vue.js 文件,本工具代码均包含在 index.html 文件里面。包括换行,一共 540 行代码,其中 css 样式 190 行,html 标签 30 行。JS 逻辑代码 300 行。

罗列这些代码量只是想表明,本工具运用到的都只是 JS 的常见知识,并不复杂。鼓励大家多尝试阅读源码,其实看源码并没有想象中的那么困难。

AES 常规解密功能

  • 借助「aes-decryptor.js」,该文件来至 hls.js

MP4 转码功能

  • 借助「mux-mp4.js」,源码来至 mux.js
  • 但 mux.js 存在一个无法计算视频长度的 bug
  • 本人已 fork 该项目,并修复该 bug,修复后的项目链接在这里

第三方接入

  • 在 url 中通过 source 参数拼接下载地址即可,如:http://blog.luckly-mjw.cn/tool-show/m3u8-downloader/index.html?source=https://upyun.luckly-mjw.cn/Assets/media-source/example/media/index.m3u8

  • 系统将自动解析该参数

  • 「跳转下载」即新开页面,打开本工具页面,自动携带并解析目标地址
  • 「注入下载」为解决跨域而生,直接将代码注入到当前视频网站,进行视频下载
  • 插件源码: https://github.com/Momo707577045/m3u8-downloader/blob/master/m3u8-downloader.user.js
  • 手动添加油猴插件步骤
    • 点击 tamper-monkey「油猴」icon,点击「添加新脚本」

    • 在当前位置,粘贴上述链接中的源码

    • 点击「文本」,「保存」

    • 得到如下结果,即为添加成功

完结撒花,感谢阅读。

m3u8-downloader's People

Contributors

madeindra avatar momo707577045 avatar zhangsean avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

m3u8-downloader's Issues

English Version

Hello momo i would love to try your m3u8 downloader is there a english version that i could use? thanks in advance

cableav.tv 的视频无法下载

大佬好:

https://cableav.tv/cjkwYuVN80p/
这个网站的视频,观看超过一段时间之后(5分钟左右),就不能继续观看了,
下载也一样,下载到一定的比例(20%-30#)服务器就会拒绝连接,导致下载失败。不知道是服务器故意这样做的还是我的操作有问题。

在network里找不到m3u8的链接

按照步骤找到网页中F12-network-但是在下面没有找到有m3u8的链接,只有ts文件。
请问怎么找到m3u8的链接呢?
谢谢
更新:已经找到了链接,但是那个链接并不是m3u8结尾的,而是很长一段,我看到网上有人把那段链接转换了一下得到了以m3u8结尾的链接就可以了,请问有什么办法可以得到可用的m3u8链接吗?
1609705046(1)

建议增加指定下载线程数功能

有些视频只允许较少的线程同时下载,超过了就会error,于是片段那里就一片红色。
所以建议增加一个指定下载线程数的功能~

不能播放

下载下来 .ts 文件不能播放怎么回事,用迅雷影音和 quicktime player 都不行

关于 d29b434 这个提交

这段代码的意义是什么?
是因为如果当前页面是http协议,无法正常下载https的m3u8,当前页面是https就无法正常下载http的m3u8吗?

else if (this.url.indexOf(location.protocol) === -1) { // 当前协议不一致,切换协议
    alert('当前协议不一致,跳转至正确页面重新下载')
    location.href = `${this.url.split(':')[0]}://blog.luckly-mjw.cn/tool-show/m3u8-downloader/index.html?source=${this.url}`
    return
}

请问一下AES怎么设置

我使用网页版的m3u4,他说AES配置错误。请问我应该怎么操作?如果可以操作,是否能更新一下md里的说明文件呢?

10小时视频下载,因内存不足快下完时页面崩溃

视频10小时,总共14.8g,电脑16g内存,快下完的时候页面崩溃。需要考虑做一下分割

尝试实现了一下,不够优雅,不好意思提pull request。每1000个保存一次对应文件是1.7g(ts格式)。

                // 添加了两个变量 this.downloadFinish(已经保存到本地的数量) this.downloadLocal(是否正在保存文件到本地)


                // 处理 ts 片段,AES 解密、mp4 转码
                dealTS(file, index, callback) {
                    const data = this.aesConf.uri ? this.aesDecrypt(file, index) : file
                    this.conversionMp4(data, index, (afterData) => { // mp4 转码
                        this.mediaFileList[index] = afterData // 判断文件是否需要解密
                        this.finishList[index].status = 'finish'
                        this.finishNum++
                            if (this.finishNum === this.tsUrlList.length) {
                                //this.downloadFile(this.mediaFileList, this.formatTime(this.beginTime, 'YYYY_MM_DD hh_mm_ss'))
                                const downloadLocalData = [];
                                for (i = 0; i < this.finishNum - this.downloadFinish; i++) {
                                    downloadLocalData[i] = this.mediaFileList[this.downloadFinish + i]
                                    this.mediaFileList[this.downloadFinish + i] = 0;
                                }
                                this.downloadFile(downloadLocalData, this.formatTime(new Date(), 'YYYY_MM_DD hh_mm_ss'))
                            } else if (this.finishNum > this.downloadFinish + 2000 && this.downloadLocal === false) {
                            this.downloadLocal = true;
                            const downloadLocalData = [];
                            for (i = 0; i < 1000; i++) {
                                downloadLocalData[i] = this.mediaFileList[this.downloadFinish + i]
                                this.mediaFileList[this.downloadFinish + i] = 0;
                            }
                            this.downloadFile(downloadLocalData, this.formatTime(new Date(), 'YYYY_MM_DD hh_mm_ss'))
                            downloadLocalData = [];
                            this.downloadLocal = false;
                            this.downloadFinish += 1000;
                        }
                        callback && callback()
                    })
                },

建议增加自定义header功能

有些网站为了防采集可能会验证header中的referer或其他自定义的头信息,建议增加自定义请求头的功能。

redownloading false fragmentation is bugged

it might be only visual but if there are more than 1 error, clicking on redownload button causes more fragment boxes than before to appear. and in some cases does not start redownloading.

只能播放一点

下载TS片 到 合成 mp4都没有问题,但是播放下载mp4文件的时候,只能播放前几秒,然后视频就不动了,但是进度还在走:画面静止,但是下面的视频进度一直在走。 请问 这个是什么问题,在使用Blob把TS转成MP4的时候 需要加什么参数吗?
--注:刚才看了一样例子 就是31秒,我的视频是15分钟的也只能播放30秒左右,就不能播放了。是不是这个就是这个程序的限制呢?

很好用

再加一个能搜索当前页面m3u8文件,选择直接下载的功能,必火

部分js引用http协议导致在https域名下无法加载的问题

BUG
复现过程
点击 “当无法下载,资源发生跨域限制时,在视频源页面打开控制台,注入代码解决,点击本按钮复制代码” 复制代码后,将代码复制到https源的目标页面,加载结束后 控制台输出

Mixed Content: The page at 'https://xxxxxx' was loaded over HTTPS, but requested an insecure script 'http://blog.luckly-mjw.cn/tool-show/m3u8-downloader/mux-mp4.js'. This request has been blocked; the content must be served over HTTPS.

Mixed Content: The page at 'https://xxxxx' was loaded over HTTPS, but requested an insecure script 'http://blog.luckly-mjw.cn/tool-show/m3u8-downloader/aes-decryptor.js'. This request has been blocked; the content must be served over HTTPS.

测试发现这两个js确实加载失败,将这两个js改为https源后可正常加载

这个repo非常棒,感谢分享 :)

是否能部属到glitch呢?

因.cn的网址在海外响应较慢,有时候还会被浏览器误封,是否能部属到glitch及若要提供不同的语言版本是要直接pull request或是自己建个新的repo呢

The resource is empty, please check whether the link is valid

Some web sites are using file extension tricks to make tools like yours become useless, with this exact error you used to give. but in reality, files inside an m3u8 are really pointing to an actual *.ts or *.mp4.

for example, one site I use changes file extensions to *.jpg for this purpose. I myself download such m3u8 files, prefix all file names with hosting directory url, download all fragments with wget and just append them with total commander (windows).

Instead, I would love to be able to use your extension to do the download&concat.

you can code it by yourself or just trust we are trying to get a bunch of video fragments, just not with the exact expected extension, put a *.ts or *.mp4 to file names, and then concat as usual.

cheers

https://bitdash-a.akamaihd.net/content/sintel/hls/playlist.m3u8 这种无法解析

附件:
playlist.m3u8.zip

格式内容:

#EXTM3U

#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="stereo",LANGUAGE="en",NAME="English",DEFAULT=YES,AUTOSELECT=YES,URI="audio/stereo/en/128kbit.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="stereo",LANGUAGE="dubbing",NAME="Dubbing",DEFAULT=NO,AUTOSELECT=YES,URI="audio/stereo/none/128kbit.m3u8"

#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="surround",LANGUAGE="en",NAME="English",DEFAULT=YES,AUTOSELECT=YES,URI="audio/surround/en/320kbit.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="surround",LANGUAGE="dubbing",NAME="Dubbing",DEFAULT=NO,AUTOSELECT=YES,URI="audio/stereo/none/128kbit.m3u8"

#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subs",NAME="Deutsch",DEFAULT=NO,AUTOSELECT=YES,FORCED=NO,LANGUAGE="de",URI="subtitles_de.m3u8"
#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subs",NAME="English",DEFAULT=YES,AUTOSELECT=YES,FORCED=NO,LANGUAGE="en",URI="subtitles_en.m3u8"
#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subs",NAME="Espanol",DEFAULT=NO,AUTOSELECT=YES,FORCED=NO,LANGUAGE="es",URI="subtitles_es.m3u8"
#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subs",NAME="Français",DEFAULT=NO,AUTOSELECT=YES,FORCED=NO,LANGUAGE="fr",URI="subtitles_fr.m3u8"

#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=258157,CODECS="avc1.4d400d,mp4a.40.2",AUDIO="stereo",RESOLUTION=422x180,SUBTITLES="subs"
video/250kbit.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=520929,CODECS="avc1.4d4015,mp4a.40.2",AUDIO="stereo",RESOLUTION=638x272,SUBTITLES="subs"
video/500kbit.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=831270,CODECS="avc1.4d4015,mp4a.40.2",AUDIO="stereo",RESOLUTION=638x272,SUBTITLES="subs"
video/800kbit.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1144430,CODECS="avc1.4d401f,mp4a.40.2",AUDIO="surround",RESOLUTION=958x408,SUBTITLES="subs"
video/1100kbit.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1558322,CODECS="avc1.4d401f,mp4a.40.2",AUDIO="surround",RESOLUTION=1277x554,SUBTITLES="subs"
video/1500kbit.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=4149264,CODECS="avc1.4d4028,mp4a.40.2",AUDIO="surround",RESOLUTION=1921x818,SUBTITLES="subs"
video/4000kbit.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=6214307,CODECS="avc1.4d4028,mp4a.40.2",AUDIO="surround",RESOLUTION=1921x818,SUBTITLES="subs"
video/6000kbit.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=10285391,CODECS="avc1.4d4033,mp4a.40.2",AUDIO="surround",RESOLUTION=4096x1744,SUBTITLES="subs"
video/10000kbit.m3u8

关于下载文件大小问题

概述

使用油猴脚本,下载下来的文件特别大,两种格式均尝试。

排查

image
下载页面的分片大小都比较大
image
播放页面相对小很多
直接down了下ts文件,发现也是比较大的那种。
不知道这种是属于普遍问题,还是是我这边访问网站做了处理的问题。看到好多说下载崩溃的,感觉应该也是这类问题。

这方面是小白,知道有封装格式和编码格式两种说,是不是网站在自己的播放器访问情况下会做编码格式的处理?
观察请求头发现Accept-Encoding字段会有差异。下载页面为:gzip, deflate,播放页面为:identity,或者是后端那边对不同来源的请求做了响应区分?
看了下m3u8文件,里面似乎也没有找到比较明显的对单分片大小做控制的手段。想问下能在m3u8做视频大小或清晰度控制吗?
或有无其他排查的方向或解决方案

script removed from violent monkey malware?

is this UserScript malware, today after updating in violent monkey I get this message This script was deleted from Greasy Fork, and due to its negative effects, it has been automatically removed from your browser.

多个EXT-X-KEY

请教下 类似这种多个key的是什么解密逻辑?
#EXT-X-KEY:METHOD=SAMPLE-AES,URI="data:text/plain;base64,AAAASnBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAACoSEFSpCo7bLctFQFF8rssCiMoSEFSpCo7bLctFQFF8rssCiMpI88aJmwY=",KEYID=0x54A90A8EDB2DCB4540517CAECB0288CA,IV=0xCEB45439F229097D77E6FE412A6D8DEA,KEYFORMATVERSIONS="1",KEYFORMAT="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed"
#EXT-X-KEY:METHOD=SAMPLE-AES,URI="skd://54a90a8edb2dcb4540517caecb0288ca",KEYFORMATVERSIONS="1",KEYFORMAT="com.apple.streamingkeydelivery"

Extension crashes while downloading

While downloading files of size about 3 GB or above, just before downloading the last segment the memory consumption increases to about twice the file size and the system become unresponsive.Also after some waiting the extension displays it crashed. I have a 8 GB RAM still I am facing problem with 3GB files.
Please look into this problem and resolve it.
I had a nice time using this extension.
Thank you.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.