最近想开发一个比较通用的下载器,了解了很多的东西,先从我的思想开始谈起吧!
之前我也写过几个具有针对性的下载器,比如说慕课网下载器,小象学院下载器,BiliBili
下载器等,这些一听名字就知道有多么的针对了,突然有一天晚上打开电脑准备学习,看到了慕课大学网站上有自己想要的东西,我虽然喜欢在线的内容,但是我无法忍受在线内容带来的感觉,我想让视频在我的Potplay
上面播放,于是我看了看大家口中所说的慕课大学中的加密视频,依旧是HLS
协议,依旧是完完整整的m3u8
地址,不过这个m3u8
完全没有慕课网那样加密三层,这原来就是一个普普通通的m3u8
文件,普通到只用FFMpeg
就可以完成下载了,我于是写了很长的FFMpeg
命令,用来下载这几个视频,一共是四个视频,写了四条命令,开了四个窗口,命令大概如下:
./ffmpeg.exe -allowed_extensions ALL -protocol_whitelist "file,http,https,rtp,udp,tcp,tls,crypto" -i "M3U8地址" -c copy "输出文件"
我想,之前写过了几个下载器了,那为什么不能再把这些下载器融合一下呢,既然所有的视频网站无非就是三种视频形式,BiliBili
的Dash
协议,大众使用的HLS
协议,还有普普通通的原生文件,我后台不需要对页面进行解析,只提供这三种格式的下载和合并逻辑不可以吗?
这么做的话,后台程序需要开放几个接口,针对于分段视频,需要传入一个数组,这个数组里面有分段视频的下载链接,这个数组是有顺序的,后台接收到之后就按照这个数组的顺序开始下载,下载完成后按照数组的顺序进行视频合并。
伪代码:
{
"segment_urls": [
"分段URL1",
"分段URL2"
],
"target_file": "~/home/Downloads/文件名.mp4"
}
合并的大概思路如下【但这是一种不怎么优雅的方式】
# 先将原来的flv转换成ts
./ffmpeg.exe -i "原来文件.flv" -vcodec copy -acodec copy -vbsf h264_mp4toannexb "输出文件.ts"
# 然后将转换后的ts进行合并
./ffmpeg.exe -i "concat:ts文件1|ts文件2" -c copy -bsf:a aac_adtstoasc "输出文件"
再比如说B站的Dash
,其实B站并没有完全的使用Dash
协议,它只是将视频分成了音频和视频两部分,并且开启了206响应码,让浏览器可以逐帧的加载视频,从而模拟了Dash
的思想,但是他应该是没有对视频切片的码率进行动态的切换,我们在看Youtube
视频的时候发现在网络很棒的时候视频质量很高,网络质量很差的时候突然间画面就模糊了,这才是真正的Dash
所要表达的思想,下载B站的Dash
的时候给接口同样传递一个只有两个元素的数组,第一个元素是视频,第二个元素是音频,然后后台按照这个规律进行下载并合并。
伪代码:
{
"dash_urls": [
"视频URL",
"音频URL"
],
"target_file": "~/home/Downloads/文件名.mp4"
}
合并的思路:
./ffmpeg.exe -i "视频文件" -i "音频文件" -c:v copy -c:a aac -strict experimental -map 0:v:0? -map 1:a:0? "输出文件"
普通格式的视频文件就更不用说了,只需要一个链接字符串就搞定了。那么再来说说慕课网这样的加密方式应该怎么去解密呢,我们可以将最终解密出来的M3U8
文本传递给后台,并且告诉后台解密这个M3U8
文件所需要的密码,还有这个密码所对应的加密方式,让后台根据这三个参数来进行视频的下载、解密和合并。
伪代码:
{
"m3u8_text": "M3U8文件的具体文本内容",
"decrypt_key": [1, 2, 3, 4, 5, 6, 7, 8...],
"decrypt_method": "AES/CBC/PKCS5PADDING",
"target_file": "~/home/Downloads/文件名.mp4"
}
合并的方式:
./ffmpeg.exe -i "concat:ts文件1|ts文件2" -c copy -bsf:a aac_adtstoasc "输出文件"
对于慕课大学的视频来说后台只需要接收到一个M3U8
文件的地址就可以了,因为它并不涉及很复杂的加密。
伪代码:
{
"m3u8_url": "M3U8的地址",
"target_file": "~/home/Downloads/文件名.mp4"
}
下载思路:
./ffmpeg.exe -allowed_extensions ALL -protocol_whitelist "file,http,https,rtp,udp,tcp,tls,crypto" -i "M3U8的URL地址" -c copy "输出文件"
后台搞定了,前端应该怎么写呢?我参考了Bilibili-Evolved
的下载思想,它把小型的视频直接放在浏览器的内存中下载,把大型的视频发送到Aria2c
中去下载,但是有个缺点,Aria2c
并不能实现视频的合并,最后造成的结果是视频零零散散的被下载下来,最后还要手动的通过FFMpeg
去合并,然而它没有提供很出色的FFMpeg
合并命令,手动合并视频就会带来很多的问题,倒不如把命令直接封装到程序中,程序执行命令而不是读取文件,这样不会因为编码的原因出错。回归正题,前端我们可以用脚本来实现,脚本去获取下载列表,以及后端所需要的全部的数据,传递给后端,所有的工作交给后端。
正当我使用脚本去写代码的时候我突然从Google搜索中得到了一个消息,TamperMonkey
要不能用了,因为Chrome Manifest V3发布了,也就意味着将限制CSP
的范围,以前的浏览器扩展可以随意指定CSP
,一旦限制后,那么就不能加载其他第三方的脚本在网页上运行了,也就是这个扩展必须要使用扩展内部拥有的内容,其他扩版的内容一律不允许使用。TamperMonkey
的作者在论坛中也担心Google
的这次扩展插件改版会对TamperMonkey
造成影响。而且Google的Minifest V3
也计划在今年(2020年)正式的发布。
那么不考虑油猴不行吗?显然是不行的,因为开发浏览器扩展的难度不是你看上去的那样,你要承受审核不通过,承受开发版在浏览器中的启动警告,插件还有一定的学习成本。
那么我直接用BookMark
做插件不行吗?对于国内的很多网站,这样做是可以的,因为他们没有使用CSP
,但是对于国外的网站,比如说Github
,使用了CSP
,那么就连插入脚本的机会都不给。
浏览器插件一直都是程序员和普通浏览器使用者热爱的一个东西,因为它可以让浏览器的功能更加强大,甚至实现不可思议的功能,例如直接下载页面上的视频,用它写爬虫比其他任何语言写爬虫都要舒坦很多,但是浏览器插件一直以来存在者安全的问题,所以也就一直被Google限制着。
因为浏览器插件可以操作所有的网页,所以它可以对网页执行任意的脚本,甚至可以收集用户的Cookie
,Google对插件都做了认真的审核,对于那些没有审核通过的一般都会被发放成*.crx
,当然这也是很久之前的一种格式了,这也就解释了为什么Google不推荐用户使用一个正在开发中的插件,Google会在每次启动的时候都会提醒用户使用了一个不安全的插件,有许多不良公司就是靠这些插件为生,于是Google开始加大审核力度,甚至插件要经过审核必须要先交5美元的审核费才能审核通过,但是这样也并不能避免安全性的问题,毕竟还有像TamperMonkey
这样的扩展中的扩展,TamperMonkey
的诞生使更多的人喜欢上了插件,因为他们不必要学习太多的插件相关的知识,还可以自己写点东西用,最关键的使不用担心Google的审核,这样的操作完全违背了Google要审核插件的初衷。
去年1月份的时候Google发布了一份Minifast V3
的文档,文档上面明确的规定了浏览器插件必须要使用审核过的脚本,不允许加载远程仓库上的脚本来执行,并且更加限制了CSP
(内容安全策略),这导致TamperMonkey
这样的扩展几乎就不能使用了。
但是我们不用TamperMonkey
写扩展程序不好吗,用BookMark
的方式,但是这种方式的话,首先使不能适用于大规模的代码,因为有些插件是要经过多层页面设计。
那么我们在BookMark
中插入script脚本不行吗?不在脚本中添加那么多的代码不就行了?这样的话又会被网站的CSP
给阻止掉了,毕竟人家Google还要用CSP
来阻止XSS
攻击的,除非自己写浏览器扩展,但是浏览器扩展并不适用于日常的脚本开发,这才是大问题。
我最近就想写一个下载工具,我已经厌倦了普通的网络请求方式的爬虫,想经过浏览器的内存直接实现自己想要的效果,毕竟浏览器支持在DevTools
中写代码,但是看过了Google对安全策略的改进,我发现这样的方式实现的下载器并不是很靠谱,很有可能在某次浏览器更新的时候被彻底的禁用掉。
综上所述,浏览器脚本并不靠谱,除非你不担心CSP
或者你是一个大型的应用,但是尽管如此,还必须要求按照Google的规定听话照做。如果我想要实现比较自由的,并不受任何约束的,那么就不能考虑浏览器脚本了。