// ==UserScript== // @name 猫抓 - 深度搜索 // @namespace https://bmmmd.com // @version 2.4.7.0 // @description 猫抓扩展提取出来的深度搜索脚本。 // @author bmm // @match http://*/* // @match https://*/* // @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== // @grant none // @run-at document-start // @license GPL v3 // @downloadURL none // ==/UserScript== (function () { console.log("catch.js Start"); if (document.getElementById("CatCatchCatch")) { return; } // 启用开关 let enable = true; const buttonStyle = 'style="border:solid 1px #000;margin:2px;padding:2px;background:#fff;border-radius:4px;border:solid 1px #c7c7c780;color:#000;"'; const checkboxStyle = 'style="-webkit-appearance: auto;"'; const CatCatch = document.createElement("div"); CatCatch.setAttribute("id", "CatCatchCatch"); CatCatch.innerHTML = `
文件名设置
文件名:
表达式:
未设置
正则:
未设置
test
`; CatCatch.style = ` position: fixed; z-index: 999999; top: 10%; left: 90%; background: rgb(255 255 255 / 85%); border: solid 1px #c7c7c7; border-radius: 4px; color: rgb(26, 115, 232); padding: 5px 5px 5px 5px; font-size: 12px; font-family: "Microsoft YaHei", "Helvetica", "Arial", sans-serif; user-select: none; display: flex; align-items: flex-start; justify-content: space-evenly; flex-direction: column; line-height: 20px;`; document.getElementsByTagName('html')[0].appendChild(CatCatch); const tips = CatCatch.querySelector("#tips"); CatCatch.querySelector("#autoDown").addEventListener('change', function (event) { localStorage.setItem("CatCatchCatch_autoDown", this.checked ? "checked" : ""); }); CatCatch.querySelector("#ffmpeg").addEventListener('change', function (event) { localStorage.setItem("CatCatchCatch_ffmpeg", this.checked ? "checked" : ""); }); const $clean = CatCatch.querySelector("#clean"); $clean.addEventListener('click', function (event) { clearCache(); $clean.innerHTML = "清理完成!"; setTimeout(() => { $clean.innerHTML = "清理缓存"; }, 1000); }); CatCatch.querySelector("#download").addEventListener('click', function (event) { if (isComplete || window.confirm("提前下载可能会造成数据混乱.确认?")) { catchDownload(); } }); CatCatch.querySelector("#hide").addEventListener('click', function (event) { CatCatch.style.display = "none"; }); CatCatch.querySelector("#close").addEventListener('click', function (event) { enable = false; CatCatch.style.display = "none"; window.postMessage({ action: "catCatchToBackground", Message: "script", script: "catch.js", refresh: false }); }); CatCatch.querySelector("#restart").addEventListener('click', function (event) { clearCache(); document.querySelectorAll("video").forEach(function (element) { element.currentTime = 0; element.play(); }); }); CatCatch.querySelector("#setFileName").addEventListener('click', function (event) { setFileName = window.prompt("输入文件名, 不包含扩展名", setFileName ?? ""); getFileName(); }); CatCatch.querySelector("#test").addEventListener('click', function (event) { console.log(catchMedia); console.log(bufferList); }); // 文件名设置 let setFileName = null; const fileName = CatCatch.querySelector("#fileName"); const selector = CatCatch.querySelector("#selector"); selector.innerHTML = localStorage.getItem("CatCatchCatch_selector") ?? "未设置"; CatCatch.querySelector("#setSelector").addEventListener('click', function (event) { const result = window.prompt("文件名获取Selector表达式", localStorage.getItem("CatCatchCatch_selector") ?? ""); if (result == null) { return; } if (result == "") { clearFileName("selector"); return; } const title = document.querySelector(result); if (title && title.innerHTML) { selector.innerHTML = stringModify(result); localStorage.setItem("CatCatchCatch_selector", result); getFileName(); } else { clearFileName("selector", "表达式错误, 无法获取或内容为空!"); } }); const regular = CatCatch.querySelector("#regular"); regular.innerHTML = localStorage.getItem("CatCatchCatch_regular") ?? "未设置"; CatCatch.querySelector("#setRegular").addEventListener('click', function (event) { let result = window.prompt("文件名获取正则", localStorage.getItem("CatCatchCatch_regular") ?? ""); if (result == null) { return; } if (result == "") { clearFileName("regular"); return; } try { new RegExp(result); regular.innerHTML = stringModify(result); localStorage.setItem("CatCatchCatch_regular", result); getFileName(); } catch (e) { clearFileName("regular", "正则表达式错误"); console.log(e); } }); // 操作按钮 let isComplete = false; let x, y; function move(event) { CatCatch.style.left = event.pageX - x + 'px'; CatCatch.style.top = event.pageY - y + 'px'; } CatCatch.addEventListener('mousedown', function (event) { x = event.pageX - CatCatch.offsetLeft; y = event.pageY - CatCatch.offsetTop; document.addEventListener('mousemove', move); document.addEventListener('mouseup', function () { document.removeEventListener('mousemove', move); }); }); tips.innerHTML = "等待视频播放"; let catchMedia = []; let bufferList = {}; let mediaSize = 0; let index = 0; const _AddSourceBuffer = window.MediaSource.prototype.addSourceBuffer; window.MediaSource.prototype.addSourceBuffer = function (mimeType) { // 标题获取 setTimeout(() => { getFileName(); }, 2000); tips.innerHTML = "捕获数据中..."; const sourceBuffer = _AddSourceBuffer.call(this, mimeType); const _appendBuffer = sourceBuffer.appendBuffer; const type = mimeType.split("/").shift() + (++index); bufferList[type] = []; catchMedia.push({ mimeType, bufferList: bufferList[type] }); sourceBuffer.appendBuffer = function (data) { if (enable) { mediaSize += data.byteLength; tips.innerHTML = "捕获数据中: " + byteToSize(mediaSize); bufferList[type].push(data); } _appendBuffer.call(this, data); } return sourceBuffer; } window.MediaSource.prototype.addSourceBuffer.toString = function () { return _AddSourceBuffer.toString(); } const _endOfStream = window.MediaSource.prototype.endOfStream; window.MediaSource.prototype.endOfStream = function () { if (enable) { isComplete = true; tips.innerHTML = "捕获完成"; localStorage.getItem("CatCatchCatch_autoDown") == "checked" && catchDownload(); } _endOfStream.call(this); } window.MediaSource.prototype.endOfStream.toString = function () { return _endOfStream.toString(); } // 下载资源 function catchDownload() { if (catchMedia.length == 0) { alert("没抓到有效数据"); return; } // catchMedia 预处理 解决 从头捕获 文件头重复 临时解决办法 if (CatCatch.querySelector("#checkHead").checked) { for (let key in catchMedia) { const data = new Uint8Array(catchMedia[key].bufferList[1]); if (data[4] == 0x66 && data[5] == 0x74 && data[6] == 0x79 && data[7] == 0x70) { catchMedia[key].bufferList.shift(); } } } if (catchMedia.length >= 2 && localStorage.getItem("CatCatchCatch_ffmpeg") == "checked") { const media = []; for (let item of catchMedia) { const mime = item.mimeType.split(';')[0]; const fileBlob = new Blob(item.bufferList, { type: mime }); const type = mime.split('/')[0]; media.push({ data: URL.createObjectURL(fileBlob), type: type }); } window.postMessage({ action: "catCatchFFmpeg", use: "merge", media: media, title: fileName.innerHTML.trim() }); } else { const a = document.createElement('a'); for (let item of catchMedia) { const mime = item.mimeType.split(';')[0]; const type = mime.split('/')[0] == "video" ? "mp4" : "mp3"; const fileBlob = new Blob(item.bufferList, { type: mime }); a.href = URL.createObjectURL(fileBlob); a.download = `${fileName.innerHTML.trim()}.${type}`; a.click(); } a.remove(); } if (isComplete) { clearCache(true); tips.innerHTML = "下载完毕..."; } } function clearFileName(obj = "selector", warning = "") { localStorage.removeItem("CatCatchCatch_" + obj); (obj == "selector" ? selector : regular).innerHTML = "未设置"; getFileName(); warning && alert(warning); } function clearCache(all = false) { isComplete = false; mediaSize = 0; if (all) { catchMedia = []; bufferList = {}; return; } for (let key in catchMedia) { catchMedia[key].bufferList.splice(1); mediaSize += catchMedia[key].bufferList[0].byteLength; } } function byteToSize(byte) { if (!byte || byte < 1024) { return 0; } if (byte < 1024 * 1024) { return (byte / 1024).toFixed(1) + "KB"; } else if (byte < 1024 * 1024 * 1024) { return (byte / 1024 / 1024).toFixed(1) + "MB"; } else { return (byte / 1024 / 1024 / 1024).toFixed(1) + "GB"; } } function getFileName() { if (setFileName) { fileName.innerHTML = stringModify(setFileName); return; } let name = ""; if (localStorage.getItem("CatCatchCatch_selector")) { const title = document.querySelector(localStorage.getItem("CatCatchCatch_selector")); if (title && title.innerHTML) { name = title.innerHTML; } } if (localStorage.getItem("CatCatchCatch_regular")) { const str = name == "" ? document.documentElement.outerHTML : name; try { const reg = new RegExp(localStorage.getItem("CatCatchCatch_regular"), "g"); let result = str.match(reg); console.log(result, reg); if (result) { result = result.filter((item) => { return item !== ""; }); name = result.join("_"); } } catch (e) { console.log(e); } } fileName.innerHTML = name ? stringModify(name) : stringModify(document.title); } function stringModify(str) { if (!str) { return str; } return str.replace(/['\\:\*\?"<\/>\|~]/g, function (m) { return { "'": ''', '\\': '\', '/': '/', ':': ':', '*': '*', '?': '?', '"': '"', '<': '<', '>': '>', '|': '|', '~': '_' }[m]; }); } })();