From f7124d84a3084705b0825b3b096c493770fbb6fe Mon Sep 17 00:00:00 2001 From: wenyifan Date: Sat, 20 Aug 2022 14:29:49 +0800 Subject: [PATCH] init --- README.md | 38 +++++++++++++++++ downloadMedia.js | 106 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 144 insertions(+) create mode 100644 README.md create mode 100644 downloadMedia.js diff --git a/README.md b/README.md new file mode 100644 index 0000000..baa07a6 --- /dev/null +++ b/README.md @@ -0,0 +1,38 @@ +# 通用网页视频下载油猴脚本 + +## 特性 +- 使用JS-Hook技术基于MediaSource原理捕获解密后的原始视频流,通杀几乎网页视频保护方案 +- 支持直播流 + +## 已测试场景 +- bilibili所有视频含付费保护视频 +- bilibili直播 +- 虎牙直播 +- 慕课网 +- 腾讯课堂 +- P站 -_-; + +## 用法 +- 使用油猴插件导入脚本,修改作用域 +- 脚本生效后视频完成加载会自动完成下载 +- 下载后的文件需要使用FFmpeg完成音视频合并 + +## 参数 +```javascript +//自动快进 +evanEnv.enableAutoForward = true +//完成后自动下载 +evanEnv.enableAutoDownload = true +``` + +## FFmpeg合并示例 +```shell +ffmpeg -i mediasource_0_0.mp4 -i mediasource_0_1.mp4 -c copy -bsf:a aac_adtstoasc out.mp4 +``` + +## 常见问题 +- 合并后声音播放不正常:由于部分网站使用了HE-AAC v2(AAC+SBR+PS)作为音频编码,大部分播放器还不支持此音频流格式,故声音不正常,使用Windows自带的视频播放器播放正常 + + +## 特别说明 +- 仅限内部交流使用,请勿用于非法用途 \ No newline at end of file diff --git a/downloadMedia.js b/downloadMedia.js new file mode 100644 index 0000000..11b80c6 --- /dev/null +++ b/downloadMedia.js @@ -0,0 +1,106 @@ +// ==UserScript== +// @name Universal encrypted video downloader +// @namespace http://tampermonkey.net/ +// @version 0.1 +// @description Bypass the encrypted video download protection via js hook +// @author Evan +// @match https://www.bilibili.com/video/* +// @match https://www.bilibili.com/bangumi/play/* +// @match https://www.youtube.com/watch* +// @match https://www.huya.com/* +// @match https://live.bilibili.com/* +// @grant none +// ==/UserScript== + +evanEnv = new Object(); +evanEnv.mediaSources = []; +evanEnv.enableAutoForward = true; +evanEnv.enableAutoDownload = true; + +(function () { + evanEnv.videos = document.getElementsByTagName('video'); + evanEnv.buildArrayBuffer = function (bufferList) { + var totalLength = 0; + for (var i = 0; i < bufferList.length; i++) { + totalLength += bufferList[i].byteLength; + } + var tmp = new Uint8Array(totalLength); + var lastLength = 0; + for (var ix = 0; ix < bufferList.length; ix++) { + tmp.set(new Uint8Array(bufferList[ix]), lastLength); + lastLength += bufferList[ix].byteLength; + } + return tmp.buffer; + }; + evanEnv.downloadRawData = function (bufferList, fileName = 'out.mp4') { + var buff = evanEnv.buildArrayBuffer(bufferList); + let url = window.URL.createObjectURL(new Blob([buff], {type: "arraybuffer"})) + const link = document.createElement('a'); + link.style.display = 'none'; + link.href = url; + link.setAttribute('download', fileName); + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + }; + + evanEnv.download = function () { + for (var i = 0; i < evanEnv.mediaSources.length; i++) { + var currentItem = evanEnv.mediaSources[i]; + if (currentItem.downloaded == undefined || currentItem.downloaded == false) { + for (var x = 0; x < currentItem.rawSources.length; x++) { + evanEnv.downloadRawData(currentItem.rawSources[x], 'mediasource_' + i + '_' + x + '.mp4'); + } + } + currentItem.downloaded = true; + } + }; + evanEnv.downloadMediaSource = function (mediaSource) { + for (var x = 0; x < mediaSource.rawSources.length; x++) { + evanEnv.downloadRawData(mediaSource.rawSources[x], 'mediasource_' + x + '.mp4'); + mediaSource.downloaded = true; + } + }; + + var proxy_addSourceBuffer = MediaSource.prototype.addSourceBuffer; + MediaSource.prototype.addSourceBuffer = function (mimeType) { + var mediaSourceThis = this; + + evanEnv.mediaSources.push(this); + this.lastPos = 0; + if (evanEnv.enableAutoDownload) { + this.onsourceended = function () { + evanEnv.download(); + }; + this.onsourceclose = function () { + evanEnv.downloadMediaSource(this); + }; + } + + + var retSourceBuffer = proxy_addSourceBuffer.apply(this, [].slice.call(arguments)); + if (this.rawSources == undefined) { + this.rawSources = []; + } + var buffList = []; + this.rawSources.push(buffList); + retSourceBuffer.rawData = buffList; + if (evanEnv.enableAutoForward) { + retSourceBuffer.onupdate = function () { + if (this.buffered != this.buffered.length > 0) { + var endPos = this.buffered.end(0); + if (endPos > 5 && endPos - mediaSourceThis.lastPos > 25) { + evanEnv.videos[0].currentTime = endPos - 3; + mediaSourceThis.lastPos = evanEnv.videos[0].currentTime; + } + } + }; + } + return retSourceBuffer; + }; + var proxy_appendBuffer = SourceBuffer.prototype.appendBuffer; + SourceBuffer.prototype.appendBuffer = function (buf) { + this.rawData.push(buf); + return proxy_appendBuffer.apply(this, [].slice.call(arguments)); + }; +})(); \ No newline at end of file