我们在使用网页展示数据的时候,我们会使用 data: 协议来显示数据,比较常见的场景如上传图片显示,一般来说都是通过从文件中读取之后,转换成base64代码,然后使用 data: 协议来显示图片,具体操作很多,如 FileReader 从文件中读取二进制, 使用Canvas绘制之后转换成二进制等,我提出来的主要原因是用于网页视频下载

现代HTML5视频播放的常见操作

相较而言,对于视频的提取,我们通常提取的是视频的原始地址,比如说 https://hostname/path/to/video.mp4?token=token_value?t=some_time,版权方或者视频所有者会将视频通过各种验证(包括不限于时间,机器,IP,登录会话)等方式来保证视频的不被下载,在早些时候,大部分的视频在HTML5时代,都是原始的视频链接,加上一堆的验证TOKEN来保证视频被下载的难度,经过一段时间的发展,大家好像发现了一个通用解决方案,也就是 blob: 协议,通过JS从服务器处理视频分片,然后在浏览器本地通过 URL.createObjectURL 创建一个 URI 来提供视频下载,代码如下:

var data = URL.createObjectURL(new Blob(["hello,world"], {type: "text/plain"}))

得到的URI如下:blob:https://dxkite.cn/1fbd093a-d40f-4798-9114-85992f0929fb,在浏览器新标签中打开将会是 hello,world 的一个纯文本响应,有效期为页面的存活期或者手动调用 URL.revokeObjectURL 回收数据,当数据回收之后,文件就会被删除,在视频播放器的操作中,通常就是这样一份代码,从后端获取数据之后处理成 blob: 协议的数据,播放的时候就很难通过视频链接(这里是 blob 协议的地址)来获取视频,因为创建之后就删除了

const video = document.getElementById('video');
const obj_url = window.URL.createObjectURL(blob);
video.src = obj_url;
video.play()
window.URL.revokeObjectURL(obj_url);

获取blob流的可行方案

一般来说,视频播放的时候,视频创建的 blob 流就回收了,但是,众所周知嘛,浏览器是咱自己的东西,想要他变成自己的形状不是很容易吗?JS这东西,什么都可以改,比如:

(function() {
    'use strict';
    console.log('hook running');
    var _cou = window.URL.createObjectURL;
    window.URL.createObjectURL = function (obj) {
        var url = _cou(obj)
        console.log("createObjectURL obj:", obj)
        console.log("createObjectURL url:", url)
        return url
    }

    window.URL.revokeObjectURL = function (url) {
        console.log("revokeObjectURL:", url)
    }
})();

在所有脚本执行之前对其进行HOOK即可,如在B站Hook,可以看到Hook的地址和播放器的地址:


PS: 屑,blob没有释放他也失效了,我可能需要一个比较另类的方式继续下去

视频播放的获取

我都已经侵入了你的网页,你怎么显示还不是归我管?继续修改JS,添加一层MediaSource的方法Hook:

    // invoke SourceBuffer
    var _addSourceBuffer = window.MediaSource.prototype.addSourceBuffer
    window.MediaSource.prototype.addSourceBuffer = function(mime) {
        console.log("MediaSource.addSourceBuffer ",mime)
        var sourceBuffer = _addSourceBuffer.call(this, mime)
        var _append = sourceBuffer.appendBuffer
        sourceBuffer.appendBuffer= function(buffer) {
            console.log(mime, buffer)
            _append.call(this, buffer)
        }
        return sourceBuffer
    }

以上代码实现了HOOK网页中的媒体资源的控制,对,获取到了视频的原始二进制数据,屑,这次文档到这里结束了,再搞下去网站都要没了。

依旧是拜年祭,ArrayBuffer为视频二进制数据,接下来只要导出即可


参考文献