工具网页视频捕获工具
Breezli网页视频捕获工具
本地解析工具
基于Windows系统
MKVToolNix Downloads – Matroska tools for Linux/Unix and Windows
(当然网站里也有其他系统的工具,只是我没用用过)
**下载后解压出来 **MKVToolNix
文件夹
**启动项是 **mkvtoolnix-gui.exe

浏览器脚本
media-source-extract
装到油猴里(文件放在最后了)

使用

脚本文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345
| // ==UserScript== // @name media-source-extract // @namespace https://github.com/Momo707577045/media-source-extract // @version 0.8.2 // @description https://github.com/Momo707577045/media-source-extract 配套插件 // @author Momo707577045 // @include * // @exclude http://blog.luckly-mjw.cn/tool-show/media-source-extract/player/player.html // @downloadURL https://blog.luckly-mjw.cn/tool-show/media-source-extract/media-source-extract.user.js // @updateURL https://blog.luckly-mjw.cn/tool-show/media-source-extract/media-source-extract.user.js // @grant none // @run-at document-start // ==/UserScript==
(function () { 'use strict'; (function () { if (document.getElementById('media-source-extract')) { return }
// 复写 call 函数,绕过劫持检查 Function.prototype.toString.call = function (caller) { return `'function ${caller.name}() { [native code] }'` }
// 轮询监听 iframe 的加载 setInterval(() => { try { Array.prototype.forEach.call(document.getElementsByTagName('iframe'), (iframe) => { // 若 iframe 使用了 sandbox 进行操作约束,删除原有 iframe,拷贝其备份,删除 sandbox 属性,重新载入 // 若 iframe 已载入,再修改 sandbox 属性,将修改无效。故通过新建 iframe 的方式绕过 if (iframe.hasAttribute('sandbox')) { const parentNode = iframe.parentNode; const tempIframe = iframe.cloneNode() tempIframe.removeAttribute("sandbox"); iframe.remove() parentNode.appendChild(tempIframe); } }) } catch (error) { console.log(error) } }, 1000)
let sumFragment = 0 // 已经捕获的所有片段数 let isClose = false // 是否关闭 let isStreamDownload = false // 是否使用流式下载 let _sourceBufferList = [] // 媒体轨道 const $showBtn = document.createElement('div') // 展示按钮 const $btnDownload = document.createElement('div') // 下载按钮 const $btnStreamDownload = document.createElement('div') // 流式下载按钮 const $downloadNum = document.createElement('div') // 已捕获视频片段数 const $tenRate = document.createElement('div') // 十倍速播放 const $closeBtn = document.createElement('div') // 关闭 const $container = document.createElement('div') // 容器 $closeBtn.innerHTML = ` <img style=" padding-top: 4px; width: 24px; display: inline-block; cursor: pointer; " src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAMAAABg3Am1AAAAk1BMVEUAAAD////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////ROyVeAAAAMHRSTlMA1Sq7gPribxkJx6Ey8onMsq+GTe10QF8kqJl5WEcvIBDc0sHAkkk1FgO2ZZ+dj1FHfPqwAAACNElEQVRIx6VW6ZqqMAwtFlEW2Rm3EXEfdZa+/9PdBEvbIVXu9835oW1yjiQlTWQE/iYPuTObOTzMNz4bQFRlY2FgnFXRC/o01mytiafP+BPvQZk56bcLSOXem1jpCy4QgXvRtlEVCARfUP65RM/hp29/+0R7eSbhoHlnffZ8h76e6x1tyw9mxXaJ3nfTVLd89hQr9NfGceJxfLIXmONh6eNNYftNSESRmgkHlEOjmhgBbYcEW08FFQN/ro6dvAczjhgXEdQP76xHEYxM+igQq259gLrCSlwbD3iDtTMy+A4Yuk0B6zV8c+BcO2OgFIp/UvJdG4o/Rp1JQYXeZFflPEFMfvugiFGFXN587YtgX7C8lRGFXPCGGYCCzlkoxJ4xqmi/jrIcdYYh5pwxiwI/gt7lDDFrcLiMKhBJ//W78ENsJgVUsV8wKpjZBXshM6cCW0jbRAilICFxIpgGMmmiWGHSIR6ViY+DPFaqSJCbQ5mbxoZLIlU0Al/cBj6N1uXfFI0okLppi69StmumSFQRP6oIKDedFi3vRDn3j6KozCZlu0DdJb3AupJXNLmqkk9+X9FEHLt1Jq8oi1H5n01AtRlvwQZQl9hmtPY4JEjMDs5ftWJN4Xr4lLrV2OHiUDHCPgvA/Tn/hP4zGUBfjZ3eLJ+NIOfHxi8CMoAQtYfmw93v01O0e7VlqqcCsXML3Vsu94cxnb4c7ML5chG8JIP9b38dENGaj3+x+TpiA/AL/fen8In7H8l3ZjdJQt2TAAAAAElFTkSuQmCC">` $showBtn.innerHTML = ` <img style=" padding-top: 4px; width: 24px; display: inline-block; cursor: pointer; " src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADIBAMAAABfdrOtAAAAElBMVEUAAAD///////////////////8+Uq06AAAABXRSTlMA2kCAv5tF5NoAAAErSURBVHja7dzNasJAFIbhz8Tu7R0Eq/vQNHuxzL6YnPu/ldYpAUckxJ8zSnjfdTIPzHrOUawJdqmDJre1S/X7avigbM08kMgMSmt+iPWKbcwTsb3+KswXseOFLb2RnaTgjXTxtpwRq7XMgWz9kZ8cSKcwE6SX+SMGAgICAvJCyHdz2ud0pEx+/BpFaj2kEgQEBAQEBAQEBOT1kXWSkhbvk1vptOLs1LEWNrmVRgIBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBeTayTqpufogxduqM3q2AgICAgICAgICA3IOko4ZXkB/pqOHzhyZBQEBAQLIieVahtDNBDnrLgZT+yC4HUkmtN9JnWUiVZbVWliVhseCJdPqvCH5IV2tQNl4r6Bod+wWq9eeDik+xFQAAAABJRU5ErkJggg==">`
// 十倍速播放 function _tenRatePlay() { let playbackRate = 10 if ($tenRate.innerHTML === '十倍速捕获') { $tenRate.innerHTML = '恢复正常播放' } else { playbackRate = 1 $tenRate.innerHTML = '十倍速捕获' }
let $domList = document.getElementsByTagName('video') for (let i = 0, length = $domList.length; i < length; i++) { const $dom = $domList[i] $dom.playbackRate = playbackRate } }
// 获取顶部 window title,因可能存在跨域问题,故使用 try catch 进行保护 function getDocumentTitle() { let title = document.title; try { title = window.top.document.title } catch (error) { console.log(error) } return title }
// 流式下载 function _streamDownload() { var _hmt = _hmt || []; (function () { var hm = document.createElement("script"); hm.src = "https://hm.baidu.com/hm.js?1f12b0865d866ae1b93514870d93ce89"; var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(hm, s); })();
// 对应状态未下载结束的媒体轨道 const remainSourceBufferList = [] _sourceBufferList.forEach((target) => { // 对应的 MSE 状态为已下载完成状态 if (target.MSEInstance.readyState === 'ended') { target.streamWriter.close() } else { remainSourceBufferList.push(target) } }) // 流式下载,释放已下载完成的媒体轨道,回收内存 _sourceBufferList = remainSourceBufferList }
// 普通下载 function _download() { var _hmt = _hmt || []; (function () { var hm = document.createElement("script"); hm.src = "https://hm.baidu.com/hm.js?1f12b0865d866ae1b93514870d93ce89"; var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(hm, s); })();
_sourceBufferList.forEach((target) => { const mime = target.mime.split(';')[0] const type = mime.split('/')[1] const fileBlob = new Blob(target.bufferList, { type: mime }) // 创建一个Blob对象,并设置文件的 MIME 类型 const a = document.createElement('a') a.download = `${getDocumentTitle()}.${type}` a.href = URL.createObjectURL(fileBlob) a.style.display = 'none' document.body.appendChild(a) // 禁止 click 事件冒泡,避免全局拦截 a.onclick = function (e) { e.stopPropagation(); } a.click() a.remove() }) }
// 监听资源全部录取成功 let _endOfStream = window.MediaSource.prototype.endOfStream window.MediaSource.prototype.endOfStream = function endOfStream() { if (isStreamDownload) { alert('资源全部捕获成功,即将下载!') setTimeout(_streamDownload) // 等待 MediaSource 状态变更 _endOfStream.call(this) return }
if (confirm('资源全部捕获成功,即将下载!') == true) { _download() } else { // 不下载资源 } _endOfStream.call(this) }
// 录取资源 let _addSourceBuffer = window.MediaSource.prototype.addSourceBuffer window.MediaSource.prototype.addSourceBuffer = function addSourceBuffer(mime) { _appendDom() let sourceBuffer = _addSourceBuffer.call(this, mime) let _append = sourceBuffer.appendBuffer let bufferList = [] const _sourceBuffer = { mime, bufferList, MSEInstance: this, }
// 如果 streamSaver 已提前加载完成,则初始化对应的 streamWriter try { if (window.streamSaver) { const type = mime.split(';')[0].split('/')[1] _sourceBuffer.streamWriter = streamSaver.createWriteStream(`${getDocumentTitle()}.${type}`).getWriter() } } catch (error) { console.error(error) }
_sourceBufferList.push(_sourceBuffer) sourceBuffer.appendBuffer = function (buffer) { sumFragment++ $downloadNum.innerHTML = `已捕获 ${sumFragment} 个片段`
if (isStreamDownload && _sourceBuffer.streamWriter) { // 流式下载 _sourceBuffer.streamWriter.write(new Uint8Array(buffer)); } else { // 普通 blob 下载 bufferList.push(buffer) } _append.call(this, buffer) } return sourceBuffer } window.MediaSource.prototype.addSourceBuffer.toString = function toString() { return 'function addSourceBuffer() { [native code] }' }
// 添加操作的 dom function _appendDom() { if (document.getElementById('media-source-extract')) { return } $container.style = ` position: fixed; top: 50px; right: 50px; text-align: right; z-index: 9999; ` const baseStyle = ` float:right; clear:both; margin-top: 10px; padding: 0 20px; color: white; cursor: pointer; font-size: 16px; font-weight: bold; line-height: 40px; text-align: center; border-radius: 4px; background-color: #3498db; box-shadow: 0 3px 6px 0 rgba(0, 0, 0, 0.3); ` $tenRate.innerHTML = '十倍速捕获' $downloadNum.innerHTML = '已捕获 0 个片段' $btnStreamDownload.innerHTML = '特大视频下载,边下载边保存' $btnDownload.innerHTML = '下载已捕获片段' $btnDownload.id = 'media-source-extract' $tenRate.style = baseStyle $downloadNum.style = baseStyle $btnDownload.style = baseStyle $btnStreamDownload.style = baseStyle $btnStreamDownload.style.display = 'none' $showBtn.style = ` float:right; clear:both; display: none; margin-top: 4px; height: 34px; width: 34px; line-height: 34px; text-align: center; border-radius: 4px; background-color: rgba(0, 0, 0, 0.5); ` $closeBtn.style = ` float:right; clear:both; margin-top: 10px; height: 34px; width: 34px; line-height: 34px; text-align: center; display: inline-block; border-radius: 50%; background-color: rgba(0, 0, 0, 0.5); `
$btnDownload.addEventListener('click', _download) $tenRate.addEventListener('click', _tenRatePlay)
// 关闭控制面板 $closeBtn.addEventListener('click', function () { $downloadNum.style.display = 'none' $btnStreamDownload.style.display = 'none' $btnDownload.style.display = 'none' $closeBtn.style.display = 'none' $tenRate.style.display = 'none' $showBtn.style.display = 'inline-block' isClose = true })
// 显示控制面板 $showBtn.addEventListener('click', function () { if (!isStreamDownload) { $btnDownload.style.display = 'inline-block' $btnStreamDownload.style.display = 'inline-block' } $downloadNum.style.display = 'inline-block' $closeBtn.style.display = 'inline-block' $tenRate.style.display = 'inline-block' $showBtn.style.display = 'none' isClose = false })
// 启动流式下载 $btnStreamDownload.addEventListener('click', function () { (function () { var hm = document.createElement("script"); hm.src = "https://hm.baidu.com/hm.js?1f12b0865d866ae1b93514870d93ce89"; var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(hm, s); })(); isStreamDownload = true $btnDownload.style.display = 'none' $btnStreamDownload.style.display = 'none' _sourceBufferList.forEach(sourceBuffer => { if (!sourceBuffer.streamWriter) { const type = sourceBuffer.mime.split(';')[0].split('/')[1] sourceBuffer.streamWriter = streamSaver.createWriteStream(`${getDocumentTitle()}.${type}`).getWriter() sourceBuffer.bufferList.forEach(buffer => { sourceBuffer.streamWriter.write(new Uint8Array(buffer)); }) sourceBuffer.bufferList = [] } }) })
document.getElementsByTagName('html')[0].insertBefore($container, document.getElementsByTagName('head')[0]); $container.appendChild($btnStreamDownload) $container.appendChild($downloadNum) $container.appendChild($btnDownload) $container.appendChild($tenRate) $container.appendChild($closeBtn) $container.appendChild($showBtn)
// 加载 stream 流式下载器 try { let $streamSaver = document.createElement('script') $streamSaver.src = 'https://upyun.luckly-mjw.cn/lib/stream-saver.js' document.body.appendChild($streamSaver); $streamSaver.addEventListener('load', () => { $btnStreamDownload.style.display = 'inline-block' }) } catch (error) { console.error(error) } } })() })();
|