NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name x1080x-extract // @license MIT // @version 3.6 // @description 提取压缩包下载链接 // @updateURL https://openuserjs.org/meta/jasmineamber/x1080x-extract.meta.js // @downloadURL https://openuserjs.org/install/jasmineamber/x1080x-extract.user.js // @copyright 2023, jasmineamber (https://openuserjs.org/users/jasmineamber) // @author jasmine // @match *://x999x.me/forum.php?mod=viewthread&tid=* // @match *://x999x.me/home.php?mod=spacecp&ac=pm&from=extract_script // @match *://*.x999x.me/forum.php?mod=viewthread&tid=* // @match *://*.x999x.me/home.php?mod=spacecp&ac=pm&from=extract_script // @match *://x567x.me/forum.php?mod=viewthread&tid=* // @match *://x567x.me/home.php?mod=spacecp&ac=pm&from=extract_script // @match *://*.x567x.me/forum.php?mod=viewthread&tid=* // @match *://*.x567x.me/home.php?mod=spacecp&ac=pm&from=extract_script // @icon https://www.google.com/s2/favicons?domain=www.x999x.me // @require https://lib.baomitu.com/jquery/1.7.2/jquery.min.js // @require https://unpkg.com/hotkeys-js@3.8.7/dist/hotkeys.min.js // @require https://gitee.com/jasmineamber/tampermonkey/raw/master/qrcode.js // @require https://gitee.com/jasmineamber/tampermonkey/raw/master/unrar.min.js // @grant GM_xmlhttpRequest // @grant GM_notification // @grant GM_download // @grant GM_addStyle // @grant GM_setValue // @grant GM_getValue // @grant GM_registerMenuCommand // @grant GM_unregisterMenuCommand // @grant GM_openInTab // @connect unrar.d2cool.com // ==/UserScript== (async function () { 'use strict'; // 菜单列表 var menu_ALL = [ ['menu_download', '下载附件', '下载附件', false], ['menu_qr', '识别百度二维码', '识别百度二维码', true] ], menu_ID = []; for (let i = 0; i < menu_ALL.length; i++) { // 如果读取到的值为 null 就写入默认值 if (GM_getValue(menu_ALL[i][0]) == null) { GM_setValue(menu_ALL[i][0], menu_ALL[i][3]) }; } registerMenuCommand(); // 注册脚本菜单 function registerMenuCommand() { if (menu_ID.length >= menu_ALL.length) { // 如果菜单ID数组多于菜单数组,说明不是首次添加菜单,需要卸载所有脚本菜单 for (let i = 0; i < menu_ID.length; i++) { GM_unregisterMenuCommand(menu_ID[i]); } } for (let i = 0; i < menu_ALL.length; i++) { // 循环注册脚本菜单 menu_ALL[i][3] = GM_getValue(menu_ALL[i][0]); menu_ID[i] = GM_registerMenuCommand(`${menu_ALL[i][3]?'✅':'❌'} ${menu_ALL[i][1]}`, function () { menu_switch(`${menu_ALL[i][3]}`, `${menu_ALL[i][0]}`, `${menu_ALL[i][2]}`) }); } // GM_registerMenuCommand('💬 反馈 & 建议', function () {GM_openInTab(`https://${document.location.hostname}/home.php?mod=spacecp&ac=pm&from=extract_script`, {active: true,insert: true,setParent: true});}); } // 意见反馈 if (window.location.href.endsWith("from=extract_script")) { document.querySelector("#username").value = "jpyl0423" return } // 菜单开关 function menu_switch(menu_status, Name, Tips) { if (menu_status == 'true') { GM_setValue(`${Name}`, false); GM_notification({text: `已关闭 [${Tips}] 功能\n(点击刷新网页后生效)`, timeout: 3500, onclick: function(){location.reload();}}); } else { GM_setValue(`${Name}`, true); GM_notification({text: `已开启 [${Tips}] 功能\n(点击刷新网页后生效)`, timeout: 3500, onclick: function(){location.reload();}}); } registerMenuCommand(); // 重新注册脚本菜单 }; // 返回菜单值 function menu_value(menuName) { for (let menu of menu_ALL) { if (menu[0] == menuName) { return menu[3] } } } function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } async function get_valid_link() { const urls = ['https://unrar.d2cool.com:2443'] for(let i = 0;i <= urls.length;i++){ let url = urls[i]; const res = await new Promise((resolve, reject) => { GM_xmlhttpRequest({ method: "GET", url: `${url}`, responseType: "blob", timeout: 5000, onload: response => { resolve(response) }, onerror: response => { reject(response) }, }); }); let blob = res.response let text = await blob.text(); if(text == 'Hello World!') { return url } } } function add_element(type, attributes) { const ele = document.createElement(type) if (attributes) { for (const [key, value] of Object.entries(attributes)) { ele.setAttribute(key, value); } } return ele; } function download_attach(blobData, file_name=null) { let a = document.createElement("a") let url = URL.createObjectURL(blobData); a.href = url; if (file_name) { a.download = file_name; } else { a.download = attach_name; } document.body.appendChild(a); a.click(); setTimeout(function () { document.body.removeChild(a); window.URL.revokeObjectURL(url); }, 0); } function blobToBase64(blob) { return new Promise((resolve, _) => { const reader = new FileReader(); reader.onloadend = () => resolve(reader.result); reader.readAsDataURL(blob); }); } function BlobToImageData(blob) { let blobUrl = URL.createObjectURL(blob); return new Promise((resolve, reject) => { let img = new Image(); img.onload = () => resolve(img); img.onerror = err => reject(err); img.src = blobUrl; }).then(img => { URL.revokeObjectURL(blobUrl); let [w, h] = [img.width, img.height] let canvas = document.createElement("canvas"); canvas.width = w; canvas.height = h; let ctx = canvas.getContext("2d"); ctx.drawImage(img, 0, 0); return ctx.getImageData(0, 0, w, h); // some browsers synchronously decode image here }) } function toUnicode(str) { return str.split('').map(function (value, index, array) { var temp = value.charCodeAt(0).toString(16).toUpperCase(); if (temp.length > 2) { return '\\u' + temp; } return value; }).join(''); } function extractLink(text) { let link; text = text.replace(/^\uFEFF/gm, "").replace(/^\u00BB\u00BF/gm, ""); let reg_ed2k_mp4 = /^ed2k:\/\/.*mp4.*/gm let reg_ed2k_rar = /^ed2k:\/\/.*\.rar.*/gm let reg_115 = /^hhd800\.com@.*/gm let reg_ip = /http:\/\/(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).*/gm let reg_baidu = /https:\/\/pan\.baidu\.com\/s\/\w+|密码:\w{4}$/gm let reg_1fichier = /https:\/\/1fichier\.com\/\?\w+/gm let result = { reg: [reg_ed2k_mp4, reg_ed2k_rar, reg_115, reg_ip, reg_baidu, reg_1fichier], data: [] } result.reg.forEach(reg => { result.data.push(text.match(reg)) }) link = result.data.filter(item => item); return link } async function extract_attch() { document.querySelector(".extract svg").outerHTML = icon_loading; [...document.querySelectorAll(".link_copy")].map(item => item.parentNode.removeChild(item)) let download_url; if (GM_getValue("tid", null) === tid && GM_getValue("attach_data", null)) { download_url = GM_getValue("attach_data") } else { download_url = attach_url } // const res_attach = await new Promise((resolve, reject) => { // GM_xmlhttpRequest({ // method: "GET", // url: download_url, // cookie: document.cookie, // responseType: "blob", // onload: response => { // resolve(response) // }, // onerror: response => { // reject(response) // }, // }); // }); const res_attach = await fetch(download_url) let blobData = await res_attach.blob(); let res_text = await blobData.text() if (res_text.indexOf("DOCTYPE") !== -1) { console.log(await blobData.text()) alert("附件下载失败") document.querySelector(".extract svg").outerHTML = icon_extract return } GM_setValue("tid", tid) GM_setValue("attach_data", await blobToBase64(blobData)) if (menu_value("menu_download")) { download_attach(blobData) } try { let link; if (attach_name.endsWith(".txt")) { let text = await blobData.text(); link = extractLink(text) } else if (attach_name.endsWith(".rar")) { let rarArrayBuffer = await blobData.arrayBuffer(); const unrar = new Unrar(rarArrayBuffer); var files = unrar.getEntries(); for (var i = 0, len = files.length; i < len; ++i) { let file = files[i]; if (file.unpackSize > 400 && file.name.endsWith(".txt")) { let data = unrar.decompress(file.name); let blob = new Blob([data]); let text = await blob.text(); text = text.replace(/^\uFEFF/gm, "").replace(/^\u00BB\u00BF/gm, ""); let reg_ed2k_mp4 = /^(?!.*(?:8K))ed2k:\/\/.*mp4.*/gm let reg_ed2k_8k_mp4 = /^ed2k:\/\/.*8K.*mp4.*/gm let reg_ed2k_rar = /^ed2k:\/\/.*\.rar.*/gm let reg_115 = /^hhd800\.com@.*/gm let reg_ip = /http:\/\/(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).*/gm let reg_baidu = /https:\/\/pan\.baidu\.com\/s\/\w+|密码:\w{4}$/gm let reg_1fichier = /https:\/\/1fichier\.com\/\?\w+/gm let result = { reg: [reg_ed2k_mp4, reg_ed2k_8k_mp4, reg_ed2k_rar, reg_115, reg_ip, reg_baidu, reg_1fichier], data: [] } result.reg.forEach(reg => { result.data.push(text.match(reg)) }) link = result.data.filter(item => item); } if (file.name.endsWith(".png") && menu_value("menu_qr")) { let data = unrar.decompress(file.name); let blob = new Blob([data]); let imageData = await BlobToImageData(blob); let result = new QRCode.Decoder().setOptions({ canOverwriteImage: false }).decode(imageData.data, imageData.width, imageData.height); let baidu_link = []; baidu_link[0] = result.data.trim(); var rar_file = new File([blobData], "temp.rar"); let post_data = new FormData(); post_data.append("file", rar_file); let unrar_link = await get_valid_link() const res_code = await new Promise((resolve, reject) => { GM_xmlhttpRequest({ method: "POST", url: `${unrar_link}/unrar`, data: post_data, responseType: "blob", onload: response => { resolve(response) }, onerror: response => { reject(response) }, }); }); let code_blob = res_code.response let baidu_code = await code_blob.text(); baidu_link[0] = `${baidu_link[0]}?pwd=${baidu_code}` link.push(baidu_link); } if (file.name.endsWith(".srt")) { let data = unrar.decompress(file.name); let blob = new Blob([data]); subtitle_data = blob subtitle_name = file.name download_attach(subtitle_data, subtitle_name) } } } else { alert("不支持的附件格式") return } if (link.length === 0) { throw new Error('提取不到链接'); } link.sort( function(x, y) { return y[0].indexOf('_8K') - x[0].indexOf('_8K') } ) link.forEach(item => { const node_copy = document.querySelector(".pattl") const div_copy = add_element('div', { class: "link_copy" }) const span_txt = add_element('span', { class: "txt" }) const span_icon = add_element('span', { class: "icon" }) const svg_copy = add_element('svg', null) node_copy.appendChild(div_copy) div_copy.appendChild(span_txt) div_copy.appendChild(span_icon) span_icon.appendChild(svg_copy) svg_copy.outerHTML = `<svg xmlns="http://www.w3.org/2000/svg"viewBox="0 0 512 512"><title>点击复制</title><!--!Font Awesome Pro 6.0.0 by @fontawesome-https:License-https:2022 Fonticons,Inc.--><path d="M384 96L384 0h-112c-26.51 0-48 21.49-48 48v288c0 26.51 21.49 48 48 48H464c26.51 0 48-21.49 48-48V128h-95.1C398.4 128 384 113.6 384 96zM416 0v96h96L416 0zM192 352V128h-144c-26.51 0-48 21.49-48 48v288c0 26.51 21.49 48 48 48h192c26.51 0 48-21.49 48-48L288 416h-32C220.7 416 192 387.3 192 352z"></path></svg>` span_txt.innerText = `${item.join(`\n`)}\n` }) $('.link_copy .icon').click(function (event) { let addrsField = $(event.target).parents("span").first().prev() if (addrsField.length === 0) { addrsField = $(event.target).prev() } copyToClipboard(addrsField); addrsField.addClass('flashBG') .delay('1000').queue(function () { addrsField.removeClass('flashBG').dequeue(); }); }); } catch (e) { alert("提取失败,请手动操作") download_attach(blobData) } finally { document.querySelector(".extract svg").outerHTML = icon_extract } } const ele_attach = document.querySelector(".attnm a") if (!ele_attach) { return } const attach_name = ele_attach.text const attach_url = ele_attach.getAttribute("href") let subtitle_data = null; let subtitle_name = null; GM_addStyle(` .extract button { font: inherit; margin: 5px 0px 0px 10px; background: none; border: 1px solid#aaa; border-radius: 4px; cursor: pointer; padding: 5px 10px; transition: all 0.3s ease; display: flex; } .extract button:hover { background: #08c; color: #fff; transform: scale(1.1); } .extract svg { height: 20px; } .extract span { padding-left: 3px; } .tattl dd { margin: 0px; } .tattl { display: flex; float: none; } .link_copy { padding: 5px 10px; background: #F7F7F7; border: 2px solid #aaa; color: #666; font-size: .8em; display: flex; align-items: center; width: 500px; margin-top: 5px; } .link_copy .icon { display: block; max-width: 25px; cursor: pointer; margin-left: auto; } .link_copy .txt { width: 90%; display: inline-block; overflow: hidden; word-break: break-all; white-space: pre-line; } .link_copy svg { width: 20px; } /* click animation */ .flashBG { animation-name: flash; animation-timing-function: ease-out; animation-duration: 1s; } @keyframes flash { 0% { background: #28a745; } 100% { background: transparent; } } `) let tid_match = /tid=(\d+)/.exec(window.location.href) if (!tid_match) { return } let tid = tid_match[1] const node = document.querySelector(".tattl") const div_extract = add_element('div', { class: "extract" }) const button = add_element('button', null) const span = add_element('span', null) const svg = add_element('svg', null) button.appendChild(svg) button.appendChild(span) div_extract.appendChild(button) node.appendChild(div_extract) const icon_extract = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><!--! Font Awesome Pro 6.0.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M75.23 33.4L320 63.1L564.8 33.4C571.5 32.56 578 36.06 581.1 42.12L622.8 125.5C631.7 143.4 622.2 165.1 602.9 170.6L439.6 217.3C425.7 221.2 410.8 215.4 403.4 202.1L320 63.1L236.6 202.1C229.2 215.4 214.3 221.2 200.4 217.3L37.07 170.6C17.81 165.1 8.283 143.4 17.24 125.5L58.94 42.12C61.97 36.06 68.5 32.56 75.23 33.4H75.23zM321.1 128L375.9 219.4C390.8 244.2 420.5 255.1 448.4 248L576 211.6V378.5C576 400.5 561 419.7 539.6 425.1L335.5 476.1C325.3 478.7 314.7 478.7 304.5 476.1L100.4 425.1C78.99 419.7 64 400.5 64 378.5V211.6L191.6 248C219.5 255.1 249.2 244.2 264.1 219.4L318.9 128H321.1z"/></svg>` const icon_loading = `<svg version="1.1"id="L9"xmlns="http://www.w3.org/2000/svg"xmlns:xlink="http://www.w3.org/1999/xlink"x="0px"y="0px"viewBox="0 0 100 100"enable-background="new 0 0 0 0"xml:space="preserve"><path fill="black"d="M73,50c0-12.7-10.3-23-23-23S27,37.3,27,50 M30.9,50c0-10.5,8.5-19.1,19.1-19.1S69.1,39.5,69.1,50"><animateTransform attributeName="transform"attributeType="XML"type="rotate"dur="1s"from="0 50 50"to="360 50 50"repeatCount="indefinite"></animateTransform></path></svg>` svg.outerHTML = icon_extract span.innerText = "提取链接" button.onclick = extract_attch const checkElement = async selector => { while (document.querySelector(selector) === null) { await new Promise(resolve => requestAnimationFrame(resolve)) } await sleep(200); return document.querySelector(selector); }; hotkeys('alt+1,alt+2,alt+3,alt+4', async function (event, handler) { event.preventDefault(); if (!document.querySelector(".link_copy .icon")) { button.scrollIntoView(); await button.click(); } checkElement(".link_copy .icon").then((selector) => { let span = document.querySelectorAll(".link_copy .icon"); switch (handler.key) { case 'alt+1': span = span[0] break; case 'alt+2': if (span.length >= 2) { span = span[1] } else { span = span[0] }; break; case 'alt+3': if (span.length >= 3) { span = span[2] } else { span = span[0] } break; case 'alt+4': if (span.length >= 4) { span = span[3] } else { span = span[0] }; break; } span.click(); }); }); function copyToClipboard(element) { var $temp = $("<textarea>"); $("body").append($temp); $temp.val(element.html().replace(/<br>/gi, "\n")).select(); document.execCommand("copy"); $temp.remove(); } })();