写了一个无限制视频下载脚本

2022-05-31 17:38:14 +08:00
 dabaisuv

在家想下载视频到本地,发现很多视频网站的video标签的src指向了 Blob: http(s)://xxx.xxx.xxx/xxx,直接进这个链接的话会显示链接已禁用。 想法:既然能播放视频,就证明视频到最后一定是被 video 拿到了的.

谷歌一圈后发现了: 1.window.URL.createObjectURL(object)方法会返回该链接

A File, Blob, or MediaSource object to create an object URL for.( https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL

2.window.URL.revokeObjectURL(objectURL),禁用上面返回的链接

A string representing a object URL that was previously created by calling createObjectURL().( https://developer.mozilla.org/en-US/docs/Web/API/URL/revokeObjectURL)

尝试:

1.hook 了window.URL.revokeObjectURL(objectURL)来忽略禁用请求,结果没用,依旧被禁用。

2.换个方法,直接 hook 二进制流,你缓存多少,我给你复制多少。查了下MediaSource, 他结合上面的createObjectURL(object)可以分片的方式加载视频,大概就是看多少,就加多少。 其中的音频和视频分别放在两个 sourceBuffer 中,直接 hook 住SourceBuffer.appendBuffer()就能实现视频流的截取了。再将每个分片以数组的方式保存下来,最后等视频缓存完后 new Blob(video/audio bufferArray)这样就实现了视频和音频的保存。

3.由于播放的时候,视频和音频分在两个 SourceBuffer 中,所以最后会得到两个文件。又是一番谷歌,有如下命令:

ffmpeg -i video.mp4 -i audio.mp4 -c:v copy -c:a aac -strict experimental output.mp4

可以将其合并为一个视频。

4.想过用 ffmpeg 的 wasm 库来在线合并,最后输出的,发现 ffmpeg-core 初始化时所需要的文件在国内下载不下来导致报错,从而导致适用的用户可能有点少,所以就没加,可能是我使用方法不对,以后有时间可以改改。

5.发现有些网站的视频是在iframe标签下的,并且加了sandbox属性,而有该属性的话就会导致最后的下载被拦截,于是,我使用了如下代码来将页面中的所有frame替换成无sandbox属性的:

 (function (that) {
          let removeSandboxInterval = setInterval(() => {
             if (that.document.querySelectorAll('iframe')[0] !== undefined) {
                that.document.querySelectorAll('iframe').forEach((v, i, a) => {
                   let ifr = v;
                   ifr.removeAttribute('sandbox');
                   const parentElem = that.document.querySelectorAll('iframe')[i].parentElement;
                   a[i].remove();
                   parentElem.appendChild(ifr);
                });
                clearInterval(removeSandboxInterval);
             }
          }, 1000);
       })(window);

于是有了如下油猴脚本:

英文名:Unlimited_downloader

https://greasyfork.org/en/scripts/445751-unlimited-downloader

Ps: 都是谷歌翻译成英文的,因为英文是个通用语言,所以不同地方的人看起来可能要方便点。

简短说明:

原理:直接 hook 媒体二进制流,换句话说就是你能看到,你就能下载,你能缓存多快,你就能下载多快。

使用方法:安装后,打开任意有视频或音频的网站,等视频缓存条加载完后会自动下载下来。

也可以自己手动开 16 倍速加速缓存,控制台输入:document.querySelector('video').playbackRate = x

最后,免责声明:请在合法范围内使用脚本,请勿用作任何非法用途,后果与作者无关。

20070 次点击
所在节点    程序员
93 条回复
LiuJiang
2022-05-31 18:52:43 +08:00
哈哈哈,最近自己也写了个,给朋友用的
Buges
2022-05-31 18:54:28 +08:00
你想岔了,不是每个网站都使用同一种方式播放还没有检测的。
真正通用的方式是 patch chromium 的源码,直接截取播放的编码流,除了 DRM 和使用非浏览器自带播放器的网站外都能获取到。
当然具体操作最大的成本是构建 chromium 需要的大量资源。
dabaisuv
2022-05-31 18:57:59 +08:00
@libook 感谢回复,我对音频编码不太了解,倍速讲道理不会影响声音。是合并后的问题还是下载下来就有的问题,如果是下载下来就有问题......这个是截取的视频流音频流,会不会是他的网页播放器是定制的自动提高音频,然后服务器存的就是降频的音频。亦或者是本地播放器的问题,这个我不太能回答。如果是合并后出的问题,可能是 ffmpeg 编码的问题?
dabaisuv
2022-05-31 19:11:37 +08:00
@Buges 感谢回复,改源码这个复杂性就太高了。在写脚本前,我查了下,目前几乎所有前端视频都是 video.src=window.URL.createObjectURL(MediaSource),而放入 MediaSource 的 SourceBuffer 之前的视频和音频流都应该是加密的,以此来防止网络嗅探。而我只需要在网站的 js 代码自己解密视频和音频流并放入 SourceBuffer 的时候截取就行,免去了伤脑细胞的加密算法分析,更加符合了 Ulimited_Downloader 的名称。
另外,我目前查到的资料是,视频加密的话,最终基本都会到 SourceBuffer 这一步,而不用 SourceBuffer 的视频播放,一般可以使用手动使用 document.querySelector('video').src (如果网站使用了 iframe:document.querySelectorAll(iframe).forEach(v=>{console.log(v.contentDocument.querySelector('video').src)})直接获得视频直接链接,那这个脚本自然也没用处了。
israinbow
2022-05-31 19:15:45 +08:00
有 FF 的支持么, 楼上出现的插件都不支持 FF.
dabaisuv
2022-05-31 19:16:17 +08:00
@dabaisuv 如果是防检测的话,可以修改 toString()方法返回 hook 之前的函数的字符串,后续可以考虑加上
dabaisuv
2022-05-31 19:17:16 +08:00
@israinbow 感谢回复,可以具体说一下 FF 是什么缩写吗,我不太明白
dabaisuv
2022-05-31 19:20:36 +08:00
@dabaisuv 这又涉及到矛与盾的问题了,网站也可以不管 hook 没 hook ,而直接替换关键函数为信任的对应函数。这我也可以 hook 住它需要替换函数所需要的函数。总的来说就跟内核一样,谁更底层,谁更先,谁赢。
israinbow
2022-05-31 19:23:39 +08:00
@dabaisuv #27 Firefox, Mozilla 的火狐浏览器.
dabaisuv
2022-05-31 19:29:21 +08:00
@israinbow 没测试,不过我觉得应该支持,火狐能安装油猴插件把,能的话就应该能支持的,我这脚本没用浏览器特性,油猴的特性也没使用,甚至你可以直接用 fidder 插入代码。但不排除火狐有什么权限相关的问题。
Buges
2022-05-31 19:33:22 +08:00
@dabaisuv 不管怎么样这种方式终归是在 js 端和网站斗智斗勇,patch chromium 的方式论复杂到也不是多复杂,几年前某安全论坛就看到过相关的资料,媒体模块加几行代码打 log 就能把内容提取出来,具体写的很清楚,只是没有成品。对程序员来说实施起来不难,只是构建 chromium 的成本太高了。
tammy
2022-05-31 19:36:56 +08:00
johnnyNg
2022-05-31 19:37:23 +08:00
思路挺可以的
dabaisuv
2022-05-31 19:40:18 +08:00
@Buges 再次感谢回复,之前没接触过 chromium 源码,看了你的回复后,我觉得可以抽时间来读一读,也可以提升一下自己对浏览器的理解。
dabaisuv
2022-05-31 19:41:01 +08:00
@johnnyNg
@tammy

感谢支持
Buges
2022-05-31 19:47:32 +08:00
@dabaisuv 其实 chromium 的源码并不难,基本上就纯 OO ,没啥高级特性和黑魔法,而且很规范、注释丰富。不过规模太庞大了,代码量太多。之前给某 chromium 下游项目提 pr 看过 chromium 源码,体验就是定位两小时 patch 5 分钟,还有就是编译吃的资源太多,你得有高速的国际宽带+流量+大量的 SSD 硬盘空间+大内存+多核 CPU 再加上大量时间才能尝试构建。
kkocdko
2022-05-31 19:58:02 +08:00
(题主做了我一直想做的事

我感觉 hook 是现在页面增强很好的一个思路,之前有见过 hook 定时器来加速跳过视频站广告。

前端的不透明度是越来越高了。
ijrou
2022-05-31 19:58:05 +08:00
ijrou
2022-05-31 19:58:28 +08:00
@ijrou 要是你能搞定这个页面的话,那你这插件才是神。。。
libook
2022-05-31 19:59:46 +08:00
@dabaisuv 合并前有问题,可能是你说的那样。
小鹅通对 video 定制得挺变态的,但 drm 效果好,工信部在用。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/856510

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX