// ==UserScript== // @name 网盘链接识别 // @namespace https://greasyfork.org/zh-CN/scripts/445489-网盘链接识别 // @supportURL https://greasyfork.org/zh-CN/scripts/445489-网盘链接识别/feedback // @version 23.9.20.16.25 // @description 识别网页中显示的网盘链接,目前包括百度网盘、蓝奏云、天翼云、中国移动云盘(原:和彩云)、阿里云、文叔叔、奶牛快传、123盘、腾讯微云、迅雷网盘、115网盘、夸克网盘、城通网盘(部分)、坚果云、BT磁力,支持蓝奏云、天翼云(需登录)、123盘、奶牛和坚果云(需登录)直链获取下载,页面动态监控加载的链接 // @author WhiteSevs // @match *://*/* // @run-at document-end // @license GPL-3.0-only // @grant GM_setValue // @grant GM_getValue // @grant GM_xmlhttpRequest // @grant GM_download // @grant GM_addStyle // @grant GM_info // @grant GM_registerMenuCommand // @grant GM_unregisterMenuCommand // @grant unsafeWindow // @connect * // @connect lanzous.com // @connect lanzouc.com // @connect lanzouk.com // @connect lanzouu.com // @connect lanzouh.com // @connect lanzouf.com // @connect lanzoul.com // @connect lanzoub.com // @connect lanzoum.com // @connect lanzout.com // @connect lanzoup.com // @connect lanzouj.com // @connect lanzouy.com // @connect lanzoug.com // @connect lanzouq.com // @connect lanzouo.com // @connect lanzouw.com // @connect lanzoui.com // @connect lanzoux.com // @connect lanzoue.com // @connect lanzouv.com // @connect lanosso.com // @connect 189.cn // @connect 123pan.com // @connect 123pan.cn // @connect wenshushu.cn // @connect jianguoyun.com // @connect cowtransfer.com // @exclude /^http(s|):\/\/s1\.hdslb\.com\/.*$/ // @exclude /^http(s|):\/\/(message|www)\.bilibili\.com\/.*$/ // @exclude /^http(s|):\/\/.*\.mail\.qq\.com\/.*$/ // @exclude /^http(s|):\/\/.*video\.qq\.com\/.*$/ // @exclude /^http(s|):\/\/.*\.vscode-cdn\.net\/.*$/ // @exclude /^http(s|):\/\/.*vscode\.dev\/.*$/ // @require https://unpkg.com/any-touch/dist/any-touch.umd.min.js // @require https://greasyfork.org/scripts/462234-message/code/Message.js?version=1252081 // @require https://greasyfork.org/scripts/456470-%E7%BD%91%E7%9B%98%E9%93%BE%E6%8E%A5%E8%AF%86%E5%88%AB-%E5%9B%BE%E6%A0%87%E5%BA%93/code/%E7%BD%91%E7%9B%98%E9%93%BE%E6%8E%A5%E8%AF%86%E5%88%AB-%E5%9B%BE%E6%A0%87%E5%BA%93.js?version=1211345 // @require https://greasyfork.org/scripts/465550-js-%E5%88%86%E9%A1%B5%E6%8F%92%E4%BB%B6/code/JS-%E5%88%86%E9%A1%B5%E6%8F%92%E4%BB%B6.js?version=1249092 // @require https://greasyfork.org/scripts/456485-pops/code/pops.js?version=1252080 // @require https://greasyfork.org/scripts/455186-whitesevsutils/code/WhiteSevsUtils.js?version=1253311 // @require https://greasyfork.org/scripts/465772-domutils/code/DOMUtils.js?version=1253312 // @downloadURL none // ==/UserScript== (function () { /** * @type {import("../库/any-touch.umd")} */ const AnyTouch = window.AnyTouch; /** * @type {import("../库/Qmsg")} */ const Qmsg = window.Qmsg; /** * @type {import("../库/pops")} */ const pops = window.pops; /** * @type {import("../库/Utils")} */ const utils = window.Utils.noConflict(); /** * @type {import("../库/DOMUtils")} */ const DOMUtils = window.DOMUtils.noConflict(); const log = new utils.Log(GM_info); log.config({ logMaxCount: 200000, autoClearConsole: false, }); const httpx = new utils.Httpx(GM_xmlhttpRequest); httpx.config({ onabort: function () { Qmsg.error("请求被取消"); }, ontimeout: function () { Qmsg.error("请求超时"); }, onerror: function (response) { Qmsg.error("请求异常"); log.error(["httpx-onerror", response]); }, }); let GM_Menu = null; const NetDisk = { /** * 是否初始化 * @type {boolean} */ isInit: false, /** * 页面显示出的文字 * @type {string} */ pageText: null, /** * 链接字典 * @type {utils.Dictionary} */ linkDict: null, isMatching: false /* 正在匹配链接中 */, matchLink: null /* 匹配到的 */, hasMatchLink: false /* 已存在匹配的链接 */, regular: { baidu: [ { link_innerText: `pan.baidu.com/s/[0-9a-zA-Z-_]{6,24}([\\s\\S]{0,${parseInt( GM_getValue("innerText_baidu", 20) )}}(密码|访问码|提取码)[\\s\\S]{0,10}[0-9a-zA-Z]{4}|)` /* 百度网盘链接 */, link_innerHTML: `pan.baidu.com/s/[0-9a-zA-Z-_]{6,24}([\\s\\S]{0,${parseInt( GM_getValue("innerHTML_baidu", 300) )}}(密码|访问码|提取码)[\\s\\S]{0,15}[0-9a-zA-Z]{4}|)` /* 百度网盘链接 */, shareCode: /pan\.baidu\.com\/s\/([0-9a-zA-Z-_]+)/gi /* 链接参数 */, shareCodeNeedRemoveStr: /pan\.baidu\.com\/s\//gi /* 需要替换空的字符串,比如pan.baidu.com/s/替换为空 */, checkAccessCode: /(密码|访问码|提取码).+/g /* 用来判断是否存在密码 */, accessCode: /([0-9a-zA-Z]{4})/gi /* 提取码(如果存在的话) */, uiLinkShow: "pan.baidu.com/s/{#shareCode#}?pwd={#accessCode#} 提取码: {#accessCode#}" /* 用于显示的链接 */, blank: "https://pan.baidu.com/s/{#shareCode#}?pwd={#accessCode#}" /* 新标签页打开的链接 */, copyUrl: "链接:https://pan.baidu.com/s/{#shareCode#}?pwd={#accessCode#}\n密码:{#accessCode#}" /* 用于复制到剪贴板的链接 */, }, ], lanzou: [ { link_innerText: `lanzou[a-z]{0,1}.com/(tp/|u/|)([a-zA-Z0-9_-]{5,22}|[%0-9a-zA-Z]{4,90}|[\\u4e00-\\u9fa5]{1,20})([\\s\\S]{0,${parseInt( GM_getValue("innerText_lanzou", 20) )}}(密码|访问码|提取码)[\\s\\S]{0,10}[a-zA-Z0-9]{3,6}|)`, link_innerHTML: `lanzou[a-z]{0,1}.com/(tp/|u/|)([a-zA-Z0-9_-]{5,22}|[%0-9a-zA-Z]{4,90}|[\\u4e00-\\u9fa5]{1,20})([\\s\\S]{0,${parseInt( GM_getValue("innerHTML_lanzou", 300) )}}(密码|访问码|提取码)[\\s\\S]{0,15}[a-zA-Z0-9]{3,6}|)`, shareCode: /lanzou[a-z]{0,1}.com\/(tp\/|u\/|)([a-zA-Z0-9_\-]{5,22}|[%0-9a-zA-Z]{4,90}|[\u4e00-\u9fa5]{1,20})/gi, shareCodeNotMatch: /^(ajax|file|undefined|1125)/gi /* shareCode参数中不可能存在的链接,如果shareCode存在这些,那就拒绝匹配 */, shareCodeNeedRemoveStr: /lanzou[a-z]{0,1}.com\/(tp\/|u\/|)/gi, checkAccessCode: /(密码|访问码|提取码).+/g, accessCode: /([0-9a-zA-Z]{3,})/gi, uiLinkShow: "lanzoux.com/{#shareCode#} 提取码: {#accessCode#}", blank: "https://www.lanzoux.com/{#shareCode#}", copyUrl: "链接:https://www.lanzoux.com/{#shareCode#}\n密码:{#accessCode#}", }, ], tianyiyun: [ { link_innerText: `(cloud.189.cn/web/share\\?code=([0-9a-zA-Z_-]){8,14}|cloud.189.cn/t/([a-zA-Z0-9_-]{8,14}))([\\s\\S]{0,${parseInt( GM_getValue("innerText_tianyiyun", 20) )}}(密码|访问码|提取码)[\\s\\S]{0,10}[0-9a-zA-Z]{4}|)`, link_innerHTML: `(cloud.189.cn/web/share\\?code=([0-9a-zA-Z_\-]){8,14}|cloud.189.cn/t/([a-zA-Z0-9_-]{8,14}))([\\s\\S]{0,${parseInt( GM_getValue("innerHTML_tianyiyun", 300) )}}(密码|访问码|提取码)[\\s\\S]{0,15}[0-9a-zA-Z]{4}|)`, shareCode: /cloud.189.cn\/web\/share\?code=([0-9a-zA-Z_\-]){8,14}|cloud.189.cn\/t\/([a-zA-Z0-9_\-]{8,14})/gi, shareCodeNeedRemoveStr: /cloud\.189\.cn\/t\/|cloud.189.cn\/web\/share\?code=/gi, checkAccessCode: /(密码|访问码|提取码).+/g, accessCode: /([0-9a-zA-Z]{4})/gi, uiLinkShow: "cloud.189.cn/t/{#shareCode#} 提取码: {#accessCode#}", blank: "https://cloud.189.cn/t/{#shareCode#}", copyUrl: "链接:https://cloud.189.cn/t/{#shareCode#}\n密码:{#accessCode#}", }, ], hecaiyun: [ { link_innerText: `caiyun.139.com/m/i\\?([a-zA-Z0-9_-]{8,14})([\\s\\S]{0,${parseInt( GM_getValue("innerText_hecaiyun", 20) )}}(密码|访问码|提取码)[\\s\\S]{0,10}[0-9a-zA-Z]{4}|)`, link_innerHTML: `caiyun.139.com/m/i\\?([a-zA-Z0-9_-]{8,14})([\\s\\S]{0,${parseInt( GM_getValue("innerHTML_hecaiyun", 300) )}}(密码|访问码|提取码)[\\s\\S]{0,15}[0-9a-zA-Z]{4}|)`, shareCode: /caiyun\.139\.com\/m\/i\?([a-zA-Z0-9_\-]{8,14})/gi, shareCodeNeedRemoveStr: /caiyun\.139\.com\/m\/i\?/gi, checkAccessCode: /(密码|访问码|提取码).+/g, accessCode: /([0-9a-zA-Z]{4})/gi, uiLinkShow: "caiyun.139.com/m/i?{#shareCode#} 提取码: {#accessCode#}", blank: "https://caiyun.139.com/m/i?{#shareCode#}", copyUrl: "链接:https://caiyun.139.com/m/i?{#shareCode#}\n密码:{#accessCode#}", }, ], aliyun: [ { link_innerText: `aliyundrive.com/s/([a-zA-Z0-9_-]{8,14})([\\s\\S]{0,${parseInt( GM_getValue("innerText_aliyun", 20) )}}(密码|访问码|提取码)[\\s\\S]{0,10}[0-9a-zA-Z]{4}|)`, link_innerHTML: `aliyundrive.com/s/([a-zA-Z0-9_-]{8,14})([\\s\\S]{0,${parseInt( GM_getValue("innerHTML_aliyun", 300) )}}(密码|访问码|提取码)[\\s\\S]{0,15}[0-9a-zA-Z]{4}|)`, shareCode: /aliyundrive\.com\/s\/([a-zA-Z0-9_\-]{8,14})/g, shareCodeNotMatch: /undefined/gi, shareCodeNeedRemoveStr: /aliyundrive\.com\/s\//gi, checkAccessCode: /(密码|访问码|提取码).+/g, accessCode: /([0-9a-zA-Z]{4})/gi, acceesCodeNotMatch: /^(font)/gi, uiLinkShow: "aliyundrive.com/s/{#shareCode#} 提取码: {#accessCode#}", blank: "https://aliyundrive.com/s/{#shareCode#}", copyUrl: "链接:https://aliyundrive.com/s/{#shareCode#}\n密码:{#accessCode#}", }, ], wenshushu: [ { link_innerText: `(wss.ink/f/([a-zA-Z0-9_-]{8,14})|ws28.cn/f/([a-zA-Z0-9_-]{8,14})|wss1.cn/f/([a-zA-Z0-9_-]{8,14})|wenshushu.cn/f/([a-zA-Z0-9_-]{8,14})|wenshushu.cn/k/([a-zA-Z0-9_-]{8,14}))([\\s\\S]{0,${parseInt( GM_getValue("innerText_wenshushu", 20) )}}(密码|访问码|提取码)[\\s\\S]{0,10}[0-9a-zA-Z]{4}|)`, link_innerHTML: `(wss.ink/f/([a-zA-Z0-9_-]{8,14})|ws28.cn/f/([a-zA-Z0-9_-]{8,14})|wss1.cn/f/([a-zA-Z0-9_-]{8,14})|wenshushu.cn/f/([a-zA-Z0-9_-]{8,14})|wenshushu.cn/k/([a-zA-Z0-9_-]{8,14}))([\\s\\S]{0,${parseInt( GM_getValue("innerHTML_wenshushu", 300) )}}(密码|访问码|提取码)[\\s\\S]{0,15}[0-9a-zA-Z]{4}|)`, shareCode: /wss.ink\/f\/([a-zA-Z0-9_-]{8,14})|ws28.cn\/f\/([a-zA-Z0-9_-]{8,14})|wss1.cn\/f\/([a-zA-Z0-9_-]{8,14})|wenshushu.cn\/f\/([a-zA-Z0-9_-]{8,14})|wenshushu.cn\/k\/([a-zA-Z0-9_-]{8,14})/gi, shareCodeNeedRemoveStr: /wss.ink\/f\/|ws28.cn\/f\/|wss1.cn\/f\/|wenshushu.cn\/f\/|wenshushu.cn\/k\//gi, checkAccessCode: /(密码|访问码|提取码).+/g, accessCode: /[0-9a-zA-Z]{4}/gi, uiLinkShow: "wss.ink/f/{#shareCode#} 提取码: {#accessCode#}", blank: "https://wss.ink/f/{#shareCode#}", copyUrl: "链接:https://wss.ink/f/{#shareCode#}\n密码:{#accessCode#}", }, ], nainiu: [ { link_innerText: `cowtransfer.com/s/([a-zA-Z0-9_-]{8,14})([\\s\\S]{0,${parseInt( GM_getValue("innerText_nainiu", 20) )}}(密码|访问码|提取码)[\\s\\S]{0,10}[0-9a-zA-Z]{4,6}|)`, link_innerHTML: `cowtransfer.com/s/([a-zA-Z0-9_-]{8,14})([\\s\\S]{0,${parseInt( GM_getValue("innerText_nainiu", 20) )}}(密码|访问码|提取码)[\\s\\S]{0,15}[0-9a-zA-Z]{4,6}|)`, shareCode: /cowtransfer.com\/s\/([a-zA-Z0-9_\-]{8,14})/gi, shareCodeNeedRemoveStr: /cowtransfer\.com\/s\//gi, checkAccessCode: /(密码|访问码|提取码).+/g, accessCode: /([0-9a-zA-Z]{4,6})/gi, uiLinkShow: "cowtransfer.com/s/{#shareCode#} 提取码: {#accessCode#}", blank: "https://cowtransfer.com/s/{#shareCode#}", copyUrl: "链接:https://cowtransfer.com/s/{#shareCode#}\n密码:{#accessCode#}", }, ], _123pan: [ { link_innerText: `123pan.com/s/([a-zA-Z0-9_-]{8,14})([\\s\\S]{0,${parseInt( GM_getValue("innerText__123pan", 20) )}}(密码|访问码|提取码)[\\s\\S]{0,10}[0-9a-zA-Z]{4}|)`, link_innerHTML: `123pan.com/s/([a-zA-Z0-9_-]{8,14})([\\s\\S]{0,${parseInt( GM_getValue("innerHTML__123pan", 300) )}}(密码|访问码|提取码)[\\s\\S]{0,15}[0-9a-zA-Z]{4}|)`, shareCode: /123pan.com\/s\/([a-zA-Z0-9_\-]{8,14})/gi, shareCodeNeedRemoveStr: /123pan.com\/s\//gi, checkAccessCode: /(密码|访问码|提取码).+/g, accessCode: /([0-9a-zA-Z]{4})/gi, uiLinkShow: "123pan.com/s/{#shareCode#} 提取码: {#accessCode#}", blank: "https://123pan.com/s/{#shareCode#}", copyUrl: "链接:https://123pan.com/s/{#shareCode#}\n密码:{#accessCode#}", }, ], weiyun: [ { link_innerText: `weiyun.com/[0-9a-zA-Z-_]{7,24}([\\s\\S]{0,${parseInt( GM_getValue("innerText_weiyun", 20) )}}(访问码|密码|提取码)[\\s\\S]{0,10}[0-9a-zA-Z]{4,6}|)`, link_innerHTML: `weiyun.com/[0-9a-zA-Z-_]{7,24}([\\s\\S]{0,${parseInt( GM_getValue("innerHTML_weiyun", 300) )}}(访问码|密码|提取码)[\\s\\S]{0,15}[0-9a-zA-Z]{4,6}|)`, shareCode: /weiyun.com\/([0-9a-zA-Z\-_]{7,24})/gi, shareCodeNotMatch: /^(ajax|file|download|ptqrshow|xy-privacy|comp|web)/gi, shareCodeNeedRemoveStr: /weiyun.com\//gi, checkAccessCode: /(提取码|密码|访问码).+/g, accessCode: /([0-9a-zA-Z]{4,6})/gi, uiLinkShow: "share.weiyun.com/{#shareCode#} 提取码: {#accessCode#}", blank: "https://share.weiyun.com/{#shareCode#}", copyUrl: "链接:https://share.weiyun.com/{#shareCode#}\n密码:{#accessCode#}", }, ], xunlei: [ { link_innerText: `xunlei.com/s/[0-9a-zA-Z-_]{8,30}([\\s\\S]{0,${parseInt( GM_getValue("innerText_xunlei", 20) )}}(访问码|提取码|密码|)[\\s\\S]{0,10}[0-9a-zA-Z]{4}|)`, link_innerHTML: `xunlei.com\/s\/[0-9a-zA-Z\-_]{8,30}([\\s\\S]{0,${parseInt( GM_getValue("innerHTML_xunlei", 300) )}}(访问码|提取码|密码|)[\\s\\S]{0,15}[0-9a-zA-Z]{4}|)`, shareCode: /xunlei.com\/s\/([0-9a-zA-Z\-_]{8,30})/gi, shareCodeNeedRemoveStr: /xunlei.com\/s\//gi, checkAccessCode: /(提取码|密码|访问码).+/g, accessCode: /([0-9a-zA-Z]{4})/gi, uiLinkShow: "pan.xunlei.com/s/{#shareCode#} 提取码: {#accessCode#}", blank: "https://pan.xunlei.com/s/{#shareCode#}", copyUrl: "链接:https://pan.xunlei.com/s/{#shareCode#}\n密码:{#accessCode#}", }, ], _115pan: [ { link_innerText: `115.com/s/[0-9a-zA-Z-_]{8,24}([\\s\\S]{0,${parseInt( GM_getValue("innerText__115pan", 20) )}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,10}[0-9a-zA-Z]{4}|)`, link_innerHTML: `115.com\/s\/[0-9a-zA-Z-_]{8,24}([\\s\\S]{0,${parseInt( GM_getValue("innerHTML__115pan", 300) )}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,15}[0-9a-zA-Z]{4}|)`, shareCode: /115.com\/s\/([0-9a-zA-Z\-_]{8,24})/gi, shareCodeNeedRemoveStr: /115.com\/s\//gi, checkAccessCode: /(提取码|密码|\?password=|访问码).+/gi, accessCode: /(\?password=|)([0-9a-zA-Z]{4})/i, uiLinkShow: "115.com/s/{#shareCode#} 提取码: {#accessCode#}", blank: "https://115.com/s/{#shareCode#}", copyUrl: "链接:https://115.com/s/{#shareCode#}\n密码:{#accessCode#}", }, ], chengtong: [ { link_innerText: `(ctfile.com|ghpym.com)/d/[0-9a-zA-Z-_]{8,26}([\\s\\S]{0,${parseInt( GM_getValue("innerText__chengtong", 20) )}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,10}[0-9a-zA-Z]{4,6}|)`, link_innerHTML: `(ctfile.com|ghpym.com)/d/[0-9a-zA-Z-_]{8,26}([\\s\\S]{0,${GM_getValue( "innerHTML__chengtong", 300 )}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,15}[0-9a-zA-Z]{4,6}|)`, shareCode: /(ctfile.com|ghpym.com)\/d\/([0-9a-zA-Z\-_]{8,26})/gi, shareCodeNeedRemoveStr: /(ctfile.com|ghpym.com)\/d\//gi, checkAccessCode: /(提取码|密码|访问码).+/gi, accessCode: /([0-9a-zA-Z]{4,6})/gi, uiLinkShow: "url95.ctfile.com/d/{#shareCode#} 提取码: {#accessCode#}", blank: "https://url95.ctfile.com/d/{#shareCode#}", copyUrl: "链接:https://url95.ctfile.com/d/{#shareCode#}\n密码:{#accessCode#}", }, { link_innerText: `pan.jc-box.com/d/[0-9a-zA-Z-_]{8,26}([\\s\\S]{0,${parseInt( GM_getValue("innerText__chengtong", 20) )}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,10}[0-9a-zA-Z]{4,6}|)`, link_innerHTML: `pan.jc-box.com/d/[0-9a-zA-Z-_]{8,26}([\\s\\S]{0,${GM_getValue( "innerHTML__chengtong", 300 )}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,15}[0-9a-zA-Z]{4,6}|)`, shareCode: /pan.jc-box.com\/d\/([0-9a-zA-Z\-_]{8,26})/gi, shareCodeNeedRemoveStr: /pan.jc-box.com\/d\//gi, checkAccessCode: /(提取码|密码|访问码).+/gi, accessCode: /([0-9a-zA-Z]{4,6})/gi, uiLinkShow: "pan.jc-box.com/d/{#shareCode#} 提取码: {#accessCode#}", blank: "http://pan.jc-box.com/d/{#shareCode#}", copyUrl: "链接:http://pan.jc-box.com/d/{#shareCode#}\n密码:{#accessCode#}", }, { link_innerText: `download.jamcz.com/d/[0-9a-zA-Z-_]{8,26}([\\s\\S]{0,${parseInt( GM_getValue("innerText__chengtong", 20) )}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,10}[0-9a-zA-Z]{4,6}|)`, link_innerHTML: `download.jamcz.com/d/[0-9a-zA-Z-_]{8,26}([\\s\\S]{0,${GM_getValue( "innerHTML__chengtong", 300 )}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,15}[0-9a-zA-Z]{4,6}|)`, shareCode: /download.jamcz.com\/d\/([0-9a-zA-Z\-_]{8,26})/gi, shareCodeNeedRemoveStr: /download.jamcz.com\/d\//gi, checkAccessCode: /(提取码|密码|访问码).+/gi, accessCode: /([0-9a-zA-Z]{4,6})/gi, uiLinkShow: "download.jamcz.com/d/{#shareCode#} 提取码: {#accessCode#}", blank: "http://download.jamcz.com/d/{#shareCode#}", copyUrl: "链接:http://download.jamcz.com/d/{#shareCode#}\n密码:{#accessCode#}", }, { link_innerText: `(2k.us/file/|u062.com/file/|545c.com/file/|t00y.com/file/)[0-9a-zA-Z-_]{8,26}([\\s\\S]{0,${parseInt( GM_getValue("innerText__chengtong", 20) )}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,10}[0-9a-zA-Z]{4,6}|)`, link_innerHTML: `(2k.us/file/|u062.com/file/|545c.com/file/|t00y.com/file/)[0-9a-zA-Z-_]{8,26}([\\s\\S]{0,${parseInt( GM_getValue("innerHTML__chengtong", 300) )}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,15}[0-9a-zA-Z]{4,6}|)`, shareCode: /(2k.us\/file\/|u062.com\/file\/|545c.com\/file\/|t00y.com\/file\/)([0-9a-zA-Z\-_]{8,26})/gi, shareCodeNeedRemoveStr: /2k.us\/file\/|u062.com\/file\/|545c.com\/file\/|t00y.com\/file\//gi, checkAccessCode: /(提取码|密码|访问码).+/gi, accessCode: /([0-9a-zA-Z]{4,6})/gi, uiLinkShow: "u062.com/file/{#shareCode#} 提取码: {#accessCode#}", blank: "https://u062.com/file/{#shareCode#}", copyUrl: "链接:https://u062.com/file/{#shareCode#}\n密码:{#accessCode#}", }, { link_innerText: `ctfile.com/f/[0-9a-zA-Z-_]{8,26}([\\s\\S]{0,${parseInt( GM_getValue("innerText__chengtong", 20) )}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,10}[0-9a-zA-Z]{4,6}|)`, link_innerHTML: `ctfile.com/f/[0-9a-zA-Z-_]{8,26}([\\s\\S]{0,${GM_getValue( "innerHTML__chengtong", 300 )}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,15}[0-9a-zA-Z]{4,6}|)`, shareCode: /ctfile.com\/f\/([0-9a-zA-Z\-_]{8,26})/gi, shareCodeNeedRemoveStr: /ctfile.com\/f\//gi, checkAccessCode: /(提取码|密码|访问码).+/gi, accessCode: /([0-9a-zA-Z]{4,6})/gi, uiLinkShow: "url95.ctfile.com/f/{#shareCode#} 提取码: {#accessCode#}", blank: "https://url95.ctfile.com/f/{#shareCode#}", copyUrl: "链接:https://url95.ctfile.com/f/{#shareCode#}\n密码:{#accessCode#}", }, { link_innerText: `(pan.jc-box.com|545c.com)/f/[0-9a-zA-Z-_]{8,26}([\\s\\S]{0,${parseInt( GM_getValue("innerText__chengtong", 20) )}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,10}[0-9a-zA-Z]{4,6}|)`, link_innerHTML: `(pan.jc-box.com|545c.com)/f/[0-9a-zA-Z-_]{8,26}([\\s\\S]{0,${GM_getValue( "innerHTML__chengtong", 300 )}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,15}[0-9a-zA-Z]{4,6}|)`, shareCode: /(pan.jc-box.com|545c.com)\/f\/([0-9a-zA-Z\-_]{8,26})/gi, shareCodeNeedRemoveStr: /(pan.jc-box.com|545c.com)\/f\//gi, checkAccessCode: /(提取码|密码|访问码).+/gi, accessCode: /([0-9a-zA-Z]{4,6})/gi, uiLinkShow: "pan.jc-box.com/f/{#shareCode#} 提取码: {#accessCode#}", blank: "http://pan.jc-box.com/f/{#shareCode#}", copyUrl: "链接:http://pan.jc-box.com/f/{#shareCode#}\n密码:{#accessCode#}", }, { link_innerText: `down.jc-box.com/f/[0-9a-zA-Z-_]{8,26}([\\s\\S]{0,${parseInt( GM_getValue("innerText__chengtong", 20) )}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,10}[0-9a-zA-Z]{4,6}|)`, link_innerHTML: `down.jc-box.com/f/[0-9a-zA-Z-_]{8,26}([\\s\\S]{0,${GM_getValue( "innerHTML__chengtong", 300 )}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,15}[0-9a-zA-Z]{4,6}|)`, shareCode: /down.jc-box.com\/f\/([0-9a-zA-Z\-_]{8,26})/gi, shareCodeNeedRemoveStr: /down.jc-box.com\/f\//gi, checkAccessCode: /(提取码|密码|访问码).+/gi, accessCode: /([0-9a-zA-Z]{4,6})/gi, uiLinkShow: "down.jc-box.com/f/{#shareCode#} 提取码: {#accessCode#}", blank: "http://down.jc-box.com/f/{#shareCode#}", copyUrl: "链接:http://down.jc-box.com/f/{#shareCode#}\n密码:{#accessCode#}", }, { link_innerText: `download.cx05.cc/f/[0-9a-zA-Z-_]{8,26}([\\s\\S]{0,${parseInt( GM_getValue("innerText__chengtong", 20) )}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,10}[0-9a-zA-Z]{4,6}|)`, link_innerHTML: `download.cx05.cc/f/[0-9a-zA-Z-_]{8,26}([\\s\\S]{0,${GM_getValue( "innerHTML__chengtong", 300 )}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,15}[0-9a-zA-Z]{4,6}|)`, shareCode: /download.cx05.cc\/f\/([0-9a-zA-Z\-_]{8,26})/gi, shareCodeNeedRemoveStr: /download.cx05.cc\/f\//gi, checkAccessCode: /(提取码|密码|访问码).+/gi, accessCode: /([0-9a-zA-Z]{4,6})/gi, uiLinkShow: "download.cx05.cc/f/{#shareCode#} 提取码: {#accessCode#}", blank: "http://download.cx05.cc/f/{#shareCode#}", copyUrl: "链接:http://download.cx05.cc/f/{#shareCode#}\n密码:{#accessCode#}", }, { link_innerText: `(089u|474b).com/dir/[0-9a-zA-Z-_]{8,26}([\\s\\S]{0,${parseInt( GM_getValue("innerText__chengtong", 20) )}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,10}[0-9a-zA-Z]{4,6}|)`, link_innerHTML: `(089u|474b).com/dir/[0-9a-zA-Z-_]{8,26}([\\s\\S]{0,${GM_getValue( "innerHTML__chengtong", 300 )}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,15}[0-9a-zA-Z]{6}|)`, shareCode: /(089u|474b).com\/dir\/([0-9a-zA-Z\-_]{8,26})/gi, shareCodeNeedRemoveStr: /(089u|474b).com\/dir\//gi, checkAccessCode: /(提取码|密码|访问码).+/gi, accessCode: /([0-9a-zA-Z]{6})/gi, uiLinkShow: "089u.com/dir/{#shareCode#} 提取码: {#accessCode#}", blank: "https://089u.com/dir/{#shareCode#}", copyUrl: "链接:https://089u.com/dir/{#shareCode#}\n密码:{#accessCode#}", }, ], kuake: [ { link_innerText: `quark.cn/s/[0-9a-zA-Z-_]{8,24}([\\s\\S]{0,${parseInt( GM_getValue("innerText_kuake", 20) )}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,10}[0-9a-zA-Z]{4}|)`, link_innerHTML: `quark.cn/s/[0-9a-zA-Z-_]{8,24}([\\s\\S]{0,${parseInt( GM_getValue("innerHTML_kuake", 300) )}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,15}[0-9a-zA-Z]{4}|)`, shareCode: /quark.cn\/s\/([0-9a-zA-Z\-_]{8,24})/gi, shareCodeNeedRemoveStr: /quark.cn\/s\//gi, checkAccessCode: /(提取码|密码|访问码).+/gi, accessCode: /([0-9a-zA-Z]{4})/gi, uiLinkShow: "quark.cn/s/{#shareCode#} 提取码: {#accessCode#}", blank: "https://pan.quark.cn/s/{#shareCode#}", copyUrl: "链接:https://pan.quark.cn/s/{#shareCode#}\n密码:{#accessCode#}", }, ], magnet: [ { link_innerText: `magnet:\\?xt=urn:btih:[0-9a-fA-F]{32,40}`, link_innerHTML: `magnet:\\?xt=urn:btih:[0-9a-fA-F]{32,40}`, shareCode: /magnet:\?xt=urn:btih:([0-9a-fA-F]{32,40})/gi, shareCodeNeedRemoveStr: /magnet:\?xt=urn:btih:/gi, checkAccessCode: /(提取码|密码|访问码).+/gi, accessCode: /([0-9a-zA-Z]{4})/gi, uiLinkShow: "magnet:?xt=urn:btih:{#shareCode#}", blank: "magnet:?xt=urn:btih:{#shareCode#}", copyUrl: "magnet:?xt=urn:btih:{#shareCode#}", }, ], jianguoyun: [ { link_innerText: `jianguoyun.com/p/[0-9a-zA-Z-_]{16,24}([\\s\\S]{0,${parseInt( GM_getValue("innerText_jianguoyun", 20) )}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,10}[0-9a-zA-Z]+|)`, link_innerHTML: `jianguoyun.com/p/[0-9a-zA-Z-_]{16,24}([\\s\\S]{0,${parseInt( GM_getValue("innerHTML_jianguoyun", 300) )}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,15}[0-9a-zA-Z]+|)`, shareCode: /jianguoyun.com\/p\/([0-9a-zA-Z\-_]{16,24})/gi, shareCodeNeedRemoveStr: /jianguoyun.com\/p\//gi, checkAccessCode: /(提取码|密码|访问码).+/gi, accessCode: /([0-9a-zA-Z]+)/gi, uiLinkShow: "jianguoyun.com/p/{#shareCode#} 提取码: {#accessCode#}", blank: "https://www.jianguoyun.com/p/{#shareCode#}", copyUrl: "链接:https://www.jianguoyun.com/p/{#shareCode#}\n密码:{#accessCode#}", }, ], onedrive: [ { name: "10101619", link_innerText: `10101619-my.sharepoint.com/.*/personal/chendexian_10101619_onmicrosoft_com/[0-9a-zA-Z-_]+([\\s\\S]{0,${parseInt( GM_getValue("innerText_onedrive_10101619", 20) )}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,10}[0-9a-zA-Z]+|)`, link_innerHTML: `10101619-my.sharepoint.com/.*/personal/chendexian_10101619_onmicrosoft_com/[0-9a-zA-Z-_]+([\\s\\S]{0,${parseInt( GM_getValue("innerHTML_onedrive_10101619", 300) )}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,15}[0-9a-zA-Z]+|)`, shareCode: /10101619-my.sharepoint.com\/.*\/personal\/chendexian_10101619_onmicrosoft_com\/([0-9a-zA-Z\-_]+)/gi, shareCodeNeedRemoveStr: /10101619-my.sharepoint.com\/.*\/personal\/chendexian_10101619_onmicrosoft_com\//gi, checkAccessCode: /(提取码|密码|访问码).+/gi, accessCode: /([0-9a-zA-Z]+)/gi, uiLinkShow: "10101619-my.sharepoint.com/:u:/g/personal/chendexian_10101619_onmicrosoft_com/{#shareCode#} 提取码: {#accessCode#}", blank: "https://10101619-my.sharepoint.com/:u:/g/personal/chendexian_10101619_onmicrosoft_com/{#shareCode#}", copyUrl: "链接:https://10101619-my.sharepoint.com/:u:/g/personal/chendexian_10101619_onmicrosoft_com/{#shareCode#}\n密码:{#accessCode#}", }, { name: "hurstheads", link_innerText: `hurstheads-my.sharepoint.com/.*/personal/storage_01_hurstheads_onmicrosoft_com/[0-9a-zA-Z-_]+([\\s\\S]{0,${parseInt( GM_getValue("innerText_onedrive_10101619", 20) )}}(访问码|密码|提取码|\\?password=|\\?e=)[\\s\\S]{0,10}[0-9a-zA-Z]+|)`, link_innerHTML: `hurstheads-my.sharepoint.com/.*/personal/storage_01_hurstheads_onmicrosoft_com/[0-9a-zA-Z-_]+([\\s\\S]{0,${parseInt( GM_getValue("innerHTML_onedrive_10101619", 300) )}}(访问码|密码|提取码|\\?password=|\\?e=)[\\s\\S]{0,15}[0-9a-zA-Z]+|)`, shareCode: /hurstheads-my.sharepoint.com\/.*\/personal\/storage_01_hurstheads_onmicrosoft_com\/([0-9a-zA-Z\-_]+)/gi, shareCodeNeedRemoveStr: /hurstheads-my.sharepoint.com\/.*\/personal\/storage_01_hurstheads_onmicrosoft_com\//gi, checkAccessCode: /(提取码|密码|访问码|\?e=).+/gi, accessCode: /([0-9a-zA-Z]+)/gi, uiLinkShow: "hurstheads-my.sharepoint.com/:u:/g/personal/storage_01_hurstheads_onmicrosoft_com/{#shareCode#} 提取码: {#accessCode#}", blank: "https://hurstheads-my.sharepoint.com/:u:/g/personal/storage_01_hurstheads_onmicrosoft_com/{#shareCode#}?e={#accessCode#}", copyUrl: "链接:https://hurstheads-my.sharepoint.com/:u:/g/personal/storage_01_hurstheads_onmicrosoft_com/{#shareCode#}?e={#accessCode#}\n密码:{#accessCode#}", }, ], }, /** * 初始化字典 */ initLinkDict() { NetDisk.linkDict = new utils.Dictionary(); Object.keys(NetDisk.regular).forEach((keys) => { NetDisk.linkDict.set(keys, new utils.Dictionary()); }); }, /** * 删除某些需要忽略的text或html,如:设置、直链弹窗 * @param {string} text - 需要进行处理的字符串 * @param {boolean} isHTML - 是否是html属性 * @returns {string} */ ignoreStrRemove(text, isHTML = false) { let ignoreNodeList = [ document.querySelector(".whitesevPopOneFile") /* 单文件直链弹窗 */, document.querySelector(".whitesevPopMoreFile") /* 多文件直链弹窗 */, document.querySelector( ".whitesevPop-whitesevPopSetting" ) /* 设置页面弹窗 */, document.querySelector( ".whitesevPopNetDiskHistoryMatch" ) /* 历史存储记录弹窗 */, document.querySelector( ".whitesevPopNetDiskHistoryMatch .netdiskrecord-table" ) /* 历史存储记录弹窗 */, ]; ignoreNodeList.forEach((ignoreNodeItem) => { if (ignoreNodeItem == null) { return; } let innerItemText = isHTML ? ignoreNodeItem.innerHTML : ignoreNodeItem.innerText; innerItemText = innerItemText == null ? "" : innerItemText; text = text.replaceAll(innerItemText, ""); }); return text; }, /** * 对页面进行match,处理匹配网盘链接 * @param {string} clipboardText 剪贴板文本 */ matchPageLink(clipboardText = "") { if (!this.isInit) { this.matchLink = new Set(); this.initLinkDict(); this.isInit = true; } /* 选择的进行匹配的项 all、innerText、innerHTML */ let matchTextRange = GM_getValue("pageMatchRange", "all"); /* 对innerText 和 innerHTML进行match */ if (matchTextRange.toLowerCase() === "all") { this.pageText = this.ignoreStrRemove(document.body.innerText); this.pageText += this.ignoreStrRemove(document.body.innerHTML, true); this.pageText += clipboardText; Object.keys(this.regular).forEach((netDiskName) => { let item = this.regular[netDiskName]; item.forEach((netDiskListItem, index) => { NetDiskWorker.GM_matchWorker.postMessage({ regexp: new RegExp(netDiskListItem["link_innerText"], "gi"), pageText: this.pageText, netDiskName: netDiskName, netDiskIndex: index, }); NetDiskWorker.GM_matchWorker.postMessage({ regexp: new RegExp(netDiskListItem["link_innerHTML"], "gi"), pageText: this.pageText, netDiskName: netDiskName, netDiskIndex: index, }); }); }); } else { if (matchTextRange.toLowerCase() === "innertext") { /* 对innerText进行match */ this.pageText = this.ignoreStrRemove(document.body.innerText); } else { /* 对innerHTML进行match */ this.pageText = this.ignoreStrRemove(document.body.innerHTML, true); } this.pageText += clipboardText; Object.keys(this.regular).forEach((netDiskName) => { let item = this.regular[netDiskName]; item.forEach((netDiskListItem, index) => { NetDiskWorker.GM_matchWorker.postMessage({ regexp: new RegExp( netDiskListItem[`link_${matchTextRange}`], "gi" ), pageText: this.pageText, netDiskName: netDiskName, netDiskIndex: index, }); }); }); } }, /** * 处理链接,将匹配到的链接转为参数和密码存入字典中 * @param {string} netDiskName 网盘名称 * @param {number} netDiskIndex 网盘名称的索引下标 * @param {string} url */ handleLink(netDiskName, netDiskIndex, url) { /* 当前字典 */ let currentDict = this.linkDict.get(netDiskName); let shareCode = this.handleShareCode(netDiskName, netDiskIndex, url); if (utils.isNull(shareCode)) { return; } let accessCode = this.handleAccessCode(netDiskName, netDiskIndex, url); if (currentDict.has(shareCode)) { /* 根据shareCode获取accessCode和netDiskIndex信息 */ let shareCodeDict = this.linkDict.get(netDiskName).get(shareCode); if ( utils.isNull(shareCodeDict.accessCode) && !utils.isNull(accessCode) ) { currentDict.set(shareCode, { accessCode: accessCode, netDiskIndex: netDiskIndex, }); NetDiskUI.view.changeLinkView( netDiskName, netDiskIndex, shareCode, accessCode ); log.info( `已存在该链接,但无密码,设置密码 ${netDiskName} ${netDiskIndex}: ${shareCode} ===> ${accessCode}` ); } } else { this.hasMatchLink = true; currentDict.set(shareCode, { accessCode: accessCode, netDiskIndex: netDiskIndex, }); NetDiskUI.matchIcon.add(netDiskName); NetDiskUI.view.addLinkView( netDiskName, netDiskIndex, shareCode, accessCode ); log.success( `添加链接 ${netDiskName} ${netDiskIndex}: ${shareCode} ===> ${accessCode}` ); } }, /** * 对传入的url进行处理,返回shareCode * @param {string} netDiskName 网盘名称 * @param {number} netDiskIndex 网盘名称索引下标 * @param {string} url 链接 * @returns */ handleShareCode(netDiskName, netDiskIndex, url) { /* 当前执行的规则 */ let netDiskMatchRegular = this.regular[netDiskName][netDiskIndex]; let shareCodeMatch = url.match(netDiskMatchRegular.shareCode); if ( shareCodeMatch == null || (shareCodeMatch != null && shareCodeMatch.length === 0) ) { log.error(`根据链接获取shareCode失败`); log.error([[...arguments], netDiskMatchRegular.shareCode]); return ""; } let shareCode = shareCodeMatch[0].replace( netDiskMatchRegular.shareCodeNeedRemoveStr, "" ); let shareCodeNotMatch = netDiskMatchRegular.shareCodeNotMatch; if (shareCodeNotMatch != null && shareCode.match(shareCodeNotMatch)) { log.error(`不可能的shareCode => ${shareCode}`); return ""; } shareCode = decodeURI(shareCode); /* %E7%BD%91%E7%9B%98 => 网盘 */ return shareCode; }, /** * 对传入的url进行处理,返回accessCode * @param {string} netDiskName 网盘名称 * @param {number} netDiskIndex 网盘名称索引下标 * @param {string} url 链接 * @returns {string} "xxxx" || "" */ handleAccessCode(netDiskName, netDiskIndex, url) { /* 当前执行正则匹配的规则 */ let netDiskMatchRegular = this.regular[netDiskName][netDiskIndex]; let accessCode = ""; let accessCodeMatch = url.match(netDiskMatchRegular.checkAccessCode); if (accessCodeMatch) { accessCode = accessCodeMatch[accessCodeMatch.length - 1].match( netDiskMatchRegular.accessCode ); if (utils.isNull(accessCode)) { return ""; } accessCode = accessCode[accessCode.length - 1]; if (accessCode.startsWith("http")) { /* 排除不可能的accessCode */ accessCode = ""; } } return accessCode; }, /** * 获取在弹窗中显示出的链接 * @param {string} netDiskName 网盘名称,指NetDisk.regular的内部键名 * @param {number} netDiskIndex 网盘名称索引下标 * @param {string} shareCode * @param {string} accessCode * @returns {string} */ handleLinkShow(netDiskName, netDiskIndex, shareCode, accessCode) { let netDiskMatchRegular = NetDisk.regular[netDiskName][netDiskIndex]; if (netDiskMatchRegular == null) { Qmsg.error("BUG: 获取uiLink规则失败"); log.error([ "BUG: 分析参数", netDiskName, netDiskIndex, shareCode, accessCode, ]); throw "获取uiLink规则失败"; } let uiLink = netDiskMatchRegular["uiLinkShow"].replace( /{#shareCode#}/gi, shareCode ); if (accessCode && accessCode != "") { uiLink = uiLink.replace(/{#accessCode#}/g, accessCode); } else { uiLink = uiLink.replace(/( |提取码:|{#accessCode#}|\?pwd=)/g, ""); } return uiLink; }, /** * 获取剪贴板文本 * @returns */ getClipboardText() { return new Promise((res) => { navigator.permissions .query({ name: "clipboard-read", }) .then((result) => { const hasFocus = document.hasFocus(); /* 这个是重点,可判断是否为当前dom页面 */ if ( hasFocus && (result.state === "granted" || result.state === "prompt") ) { const clipboard = navigator.clipboard.readText(); clipboard.then((clipText) => { res(clipText); }); } else { res(""); } }); }); }, }; /** * 网盘直链解析 */ const NetDiskParse = { netDisk: { /** * 百度网盘 * @constructor * @returns {object} */ baidu: function () { let that = this; /** * 入口 * @param {number} netDiskIndex 网盘名称索引下标 * @param {string} shareCode * @param {string} accessCode * @returns */ this.default = function (netDiskIndex, shareCode, accessCode) { let bdurl = GM_getValue("bdurl"); let paramSurl = GM_getValue("paramSurl"); let paramPwd = GM_getValue("paramPwd"); let paramKey = GM_getValue("paramKey"); let paramWebSiteKey = GM_getValue("paramWebSiteKey"); let baidu_website_key_enable = GM_getValue( "baidu-website-key-enable", false ); if (!bdurl) { Qmsg.error("请完善配置 网址-Url"); return null; } if (!paramSurl) { Qmsg.error("请完善配置 参数-Key"); return null; } if (!paramPwd) { Qmsg.error("请完善配置 密码-Key"); return null; } if (!paramKey) { Qmsg.error("请完善配置 密钥-Key"); return null; } if (baidu_website_key_enable && !paramWebSiteKey) { Qmsg.error("请完善配置 密钥-Value"); return null; } var tempFormNode = document.createElement("form"); var list = {}; /* 表单数据 */ list[paramSurl] = shareCode; list[paramPwd] = accessCode; if (baidu_website_key_enable) { list[paramKey] = paramWebSiteKey; } tempFormNode.action = bdurl; /* 解析网址 */ tempFormNode.method = "post"; tempFormNode.style.display = "none"; tempFormNode.target = "_blank"; for (var x in list) { var opt = document.createElement("textarea"); opt.name = x; opt.value = list[x]; /* alert(opt.name) */ tempFormNode.appendChild(opt); } document.body.appendChild(tempFormNode); tempFormNode.submit(); }; return this; }, /** * 蓝奏云 * 流程:判断是否是多文件 * 单文件 => 请求https://www.lanzoux.com/{shareToken} 判断链接类型和是否能正常获取 * => 请求https://www.lanzoux.com/tp/{shareToken} 获取文件sign * => 请求https://www.lanzoux.com/ajaxm.php 获取下载参数,下载参数例如:https://develope.lanzoug.com/file/?xxxxxxxxx * 多文件 => 先请求https://www.lanzoux.com/{shareToken} 获取文件sign => 请求https://www.lanzoux.com/filemoreajax.php 获取json格式的文件参数, * 参数内容如{"info":"success","text":[{"duan":"xx","icon":"","id":"".....},{},{}]} * @constructor * @returns {object} */ lanzou: function () { let that = this; this.handleUrl = { default: function (paramShareCode) { return NetDisk.regular.lanzou[that.netDiskIndex]["blank"].replace( /{#shareCode#}/g, paramShareCode ); }, tp: function (paramShareCode) { return NetDisk.regular.lanzou[that.netDiskIndex]["blank"].replace( /{#shareCode#}/gi, `tp/${paramShareCode}` ); }, }; this.regexp = { unicode: { /** * 判断该链接是否是中文 */ match: /[%\u4e00-\u9fa5]+/g, tip: "中文链接", isUnicode: false, }, /** * 蓝奏文件取消分享 */ noFile: { match: /div>来晚啦...文件取消分享了<\/div>/g, tip: "来晚啦...文件取消分享了", }, /** * 蓝奏文件链接错误 */ noExists: { match: /div>文件不存在,或已删除<\/div>/g, tip: "文件不存在,或已删除", }, /** * 2023-9-19 蓝奏云修改分享规则,需要vip用户才可以分享 apk、ipa 链接 */ needVipToShare: { match: /class="fbox">非会员.+请先开通会员/gi, tip: "该链接为非会员用户分享的文件,目前无法下载", }, /** * 蓝奏多文件 */ moreFile: { match: //g, }, /** * 蓝奏设置了密码的单文件请求需要的sign值 */ sign: { match: /var[\s]*(posign|postsign|vidksek)[\s]*=[\s]*'(.+?)';/, }, /** * 蓝奏文件名 */ fileName: { match: /(.*)<\/title>/, }, /** * 蓝奏文件大小 */ size: { match: /<span class=\"mtt\">\((.*)\)<\/span>/, }, /** * 蓝奏文件直链host */ loadDownHost: { match: /var[\s]*(vkjxld)[\s]*=[\s]*'(.+?)'/i, }, /** * 蓝奏文件直链 */ loadDown: { match: /var[\s]*(loaddown|oreferr|spototo|domianload|hyggid)[\s]*=[\s]*'(.+?)'/i, }, /** * 蓝奏云之苹果使用类型的文件 */ appleDown: { match: /var[\s]*appitem[\s]*=[\s]*'(.+?)'/i, }, /** * 蓝奏云文件上传时间 */ uploadTime: { match: /mt2\"\>时间:<\/span>(.+?)[\s]*<span/i, }, }; /** * 入口 * @param {number} netDiskIndex * @param {string} shareCode * @param {string} accessCode */ this.default = async function (netDiskIndex, shareCode, accessCode) { that.netDiskIndex = netDiskIndex; that.shareCode = shareCode; that.accessCode = accessCode; that.regexp.unicode.isUnicode = Boolean( that.shareCode.match(that.regexp.unicode.match) ); await that.getFileLink(shareCode, accessCode); }; /** * 获取文件链接 * @param {boolean} getShareCodeByPageAgain * @returns */ this.getFileLink = async function (getShareCodeByPageAgain = false) { let url = that.handleUrl.default(that.shareCode); log.info("蓝奏云-获取文件下载链接" + url); let getResp = await httpx.get({ url: url, headers: { Accept: "*/*", "User-Agent": utils.getRandomAndroidUA(), referer: window.location.origin, }, }); if (!getResp.status) { return; } let respData = getResp.data; if (respData.readyState !== 4) { log.error(respData); Qmsg.error("请求失败,请重试"); return; } if (!that.checkPageCode(respData)) { return; } if (that.isMoreFile(respData)) { await that.getMoreFile(); } else { log.info(respData); if (getShareCodeByPageAgain) { let shareCodeNewMatch = respData.responseText.match( /var[\s]*link[\s]*=[\s]*\'tp\/(.+?)\';/i ); that.shareCode = shareCodeNewMatch[shareCodeNewMatch.length - 1]; log.info(`新参数 => ${that.shareCode}`); } await that.getLinkByTp(); } }; /** * 页面检查,看看是否存在文件失效情况 * @param {object} response * @returns {boolean} * + true 未失效 * + false 已失效 */ this.checkPageCode = function (response) { let pageText = response.responseText; if (pageText.match(that.regexp.noFile.match)) { Qmsg.error(that.regexp.noFile.tip); return false; } if (pageText.match(that.regexp.noExists.match)) { Qmsg.error(that.regexp.noExists.tip); return false; } if (pageText.match(that.regexp.needVipToShare.match)) { Qmsg.error(that.regexp.needVipToShare.tip); return false; } return true; }; /** * 判断是否是多文件的链接 * @param {object} response * @returns {boolean} * + true 多文件 * + false 单文件 */ this.isMoreFile = function (response) { let pageText = response.responseText; if (pageText.match(that.regexp.moreFile.match)) { log.info("该链接为多文件"); return true; } else { log.info("该链接为单文件"); return false; } }; /** * 访问蓝奏tp获取sign */ this.getLinkByTp = async function () { let getResp = await httpx.get({ url: that.handleUrl.tp(that.shareCode), headers: { Accept: "*/*", "User-Agent": utils.getRandomAndroidUA(), referer: window.location.origin, }, }); if (!getResp.status) { return; } let respData = getResp.data; log.info("by_tp ↓"); log.info(respData); if (respData.readyState === 4) { await that.getLink(respData); } else { Qmsg.error("请求失败,请重试"); } }; /** * 获取链接 * @param {object} response * @returns */ this.getLink = async function (response) { let pageText = response.responseText; if (pageText == null) { log.error("shareCode错误,重新从页面中获取"); await that.getFileLink(true); return; } let sign = pageText.match(that.regexp.sign.match); let postData_p = ""; let postData_sign = ""; let fileNameMatch = pageText.match(that.regexp.fileName.match); let fileName = fileNameMatch ? fileNameMatch[1].trim() : ""; let fileSizeMatch = pageText.match(that.regexp.size.match); let fileSize = fileSizeMatch ? fileSizeMatch[1].trim() : ""; let fileUploadTime = pageText.match(that.regexp.uploadTime.match); if (fileUploadTime) { fileUploadTime = fileUploadTime[fileUploadTime.length - 1].trim(); } if (sign) { postData_sign = sign[sign.length - 1]; log.info(`获取Sign: ${postData_sign}`); if (that.accessCode) { log.info("传入参数=>有密码"); postData_p = that.accessCode; } else { log.info("传入参数=>无密码"); } let postResp = await httpx.post({ url: "https://www.lanzoux.com/ajaxm.php", responseType: "json", headers: { "content-type": "application/x-www-form-urlencoded; charset=UTF-8", "user-agent": utils.getRandomAndroidUA(), referer: window.location.origin, }, data: `action=downprocess&sign=${postData_sign}&p=${postData_p}`, }); if (!postResp.status) { return; } let respData = postResp.data; log.info(respData); if (respData.readyState === 4) { let json_data = utils.toJSON(respData.responseText); let downloadUrl = `${json_data["dom"]}/file/${json_data["url"]}`; let zt = json_data["zt"]; if ("密码不正确".indexOf(json_data["inf"]) != -1) { Qmsg.error("密码不正确!"); NetDiskUI.newAccessCodeView( undefined, "lanzou", that.netDiskIndex, that.shareCode, (userInputAccessCode) => { that.default( that.netDiskIndex, that.shareCode, userInputAccessCode ); } ); } else { fileName = json_data["inf"] ? json_data["inf"] : fileName; downloadUrl = await NetDiskParse.getRedirectFinalUrl( downloadUrl, utils.getRandomAndroidUA() ); log.info(downloadUrl); downloadUrl = NetDiskFilterScheme.handleUrl( "lanzou-static-scheme-enable", "lanzou-static-scheme-forward", downloadUrl ); NetDiskUI.staticView.oneFile({ title: "蓝奏云单文件直链", fileName: fileName, fileSize: fileSize, downloadUrl: downloadUrl, fileUploadTime: fileUploadTime, }); } } else { Qmsg.error("请求失败,请重试"); } } else { let loadDownHost = pageText.match(that.regexp.loadDownHost.match); let loadDown = pageText.match(that.regexp.loadDown.match); let appleDown = pageText.match(that.regexp.appleDown.match); if (utils.isNull(loadDown)) { loadDown = pageText.match(/var[\s]*(cppat)[\s]*=[\s]*'(.+?)'/i); } if (utils.isNull(loadDownHost) && appleDown) { appleDown = appleDown[appleDown.length - 1]; loadDownHost = [appleDown]; loadDown = [""]; log.success(["多文件-当前链接猜测为苹果的文件", appleDown]); } if (utils.isNull(loadDownHost)) { Qmsg.error("蓝奏云直链:获取sign的域名失败,请反馈开发者", { timeout: 3500, }); return; } if (utils.isNull(loadDown)) { Qmsg.error("蓝奏云直链:获取sign失败,请反馈开发者", { timeout: 3500, }); return; } let downloadUrl = `${loadDownHost[loadDownHost.length - 1]}${ loadDown[loadDown.length - 1] }`; log.info([fileName, fileSize, downloadUrl]); downloadUrl = await NetDiskParse.getRedirectFinalUrl( downloadUrl, utils.getRandomAndroidUA() ); log.info(downloadUrl); downloadUrl = NetDiskFilterScheme.handleUrl( "lanzou-static-scheme-enable", "lanzou-static-scheme-forward", downloadUrl ); NetDiskUI.staticView.oneFile({ title: "蓝奏云单文件直链", fileName: fileName, fileSize: fileSize, downloadUrl: downloadUrl, fileUploadTime: fileUploadTime, }); } }; /** * 多文件获取 */ this.getMoreFile = async function () { let getResp = await httpx.get({ url: that.handleUrl.default(that.shareCode), headers: { Accept: "*/*", "user-agent": utils.getRandomAndroidUA(), referer: window.location.origin, }, }); if (!getResp.status) { return; } let respData = getResp.data; log.info(respData); if (respData.readyState !== 4) { Qmsg.error("请求失败,请重试"); return; } let pageText = respData.responseText; let fid = pageText.match(/\'fid\':(.+?),/)[1].replaceAll("'", ""); let uid = pageText.match(/\'uid\':(.+?),/)[1].replaceAll("'", ""); let pgs = 1; let t_name = pageText.match(/\'t\':(.+?),/)[1]; let t_rexp = new RegExp(t_name + "[\\s]*=[\\s]*('|\")(.+?)('|\");"); let t = pageText.match(t_rexp)[2]; let k_name = pageText.match(/\'k\':(.+?),/)[1]; let k_rexp = new RegExp(k_name + "[\\s]*=[\\s]*('|\")(.+?)('|\");"); let k = pageText.match(k_rexp)[2]; let lx = that.shareCode.match(that.regexp.unicode.match) ? 1 : 2; let postData = `lx=${lx}&fid=${fid}&uid=${uid}&pg=${pgs}&rep=0&t=${t}&k=${k}&up=1&ls=1&pwd=${that.accessCode}`; log.info(`多文件请求参数:${postData}`); let postResp = await httpx.post({ url: "https://www.lanzoux.com/filemoreajax.php", responseType: "json", headers: { "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", "user-agent": utils.getRandomAndroidUA(), referer: window.location.origin, }, data: postData, }); if (!postResp.status) { return; } let postRespData = postResp.data; log.info(postRespData); let json_data = utils.toJSON(postRespData.responseText); let zt = json_data["zt"]; let info = json_data["info"]; if (zt === 4) { Qmsg.error(info); } else if (zt === 1) { Qmsg.success("获取文件夹成功,解析文件直链中..."); var folder = json_data["text"]; /* 获取多文件的数组信息 */ var folderList = []; /* 弹出内容 */ log.info(`本链接一共${folder.length}个文件`); for (let i = 0; i < folder.length; i++) { let item = folder[i]; let _shareCode_ = item.id; let fileName = item.name_all; let fileSize = item.size; let uploadTime = item.time; log.info(`第${i + 1}个开始解析`); let folderInfo = await that.parseMoreFile( _shareCode_, fileName, fileSize, uploadTime ); log.info(`第${i + 1}个解析完毕`); folderList.push(folderInfo); } NetDiskUI.staticView.moreFile("蓝奏云多文件直链", folderList); } else if ("密码不正确".indexOf(info) !== -1) { Qmsg.error("密码不正确!"); NetDiskUI.newAccessCodeView( undefined, "lanzou", that.netDiskIndex, that.shareCode, (userInputAccessCode) => { that.default( that.netDiskIndex, that.shareCode, userInputAccessCode ); } ); } else if ("没有了".indexOf(info) !== -1) { Qmsg.error("没有文件了"); } else { Qmsg.error("未知错误"); } }; /** * 多文件解析并返回html * @param {string} paramShareCode 解析多文件获取的shareCode * @param {string} fileName 文件名 * @param {string} fileSize 文件大小 * @param {string} fileUploadTime 文件上传时间 * @async */ this.parseMoreFile = async function ( paramShareCode, fileName, fileSize, fileUploadTime ) { /* 根据获取到的json中多文件链接来获取单文件直链 */ let resultInfo = {}; let getResp = await httpx.get({ url: that.handleUrl.tp(paramShareCode), headers: { Accept: "*/*", "user-agent": utils.getRandomAndroidUA(), referer: window.location.origin, }, }); let respData = getResp.data; if (getResp.status) { let pageText = respData.responseText; let loadDownHost = pageText.match(that.regexp.loadDownHost.match); let loadDown = pageText.match(that.regexp.loadDown.match); let appleDown = pageText.match(that.regexp.appleDown.match); if (utils.isNull(loadDown)) { loadDown = pageText.match(/var[\s]*(cppat)[\s]*=[\s]*'(.+?)'/i); } if (utils.isNull(loadDown) && appleDown) { appleDown = appleDown[appleDown.length - 1]; loadDownHost = [appleDown]; loadDown = [""]; log.success(["多文件-当前链接猜测为苹果的文件", appleDown]); } let submit_url = "javascript:;"; let downloadUrl = ""; if (utils.isNotNull(loadDownHost) && utils.isNotNull(loadDown)) { let needRedirectDownloadUrl = `${ loadDownHost[loadDownHost.length - 1] }${loadDown[loadDown.length - 1]}`; downloadUrl = await NetDiskParse.getRedirectFinalUrl( needRedirectDownloadUrl, utils.getRandomAndroidUA() ); submit_url = NetDiskFilterScheme.handleUrl( "lanzou-static-scheme-enable", "lanzou-static-scheme-forward", downloadUrl ); resultInfo["success"] = true; resultInfo["downloadUrl"] = submit_url; } else if (pageText.match("来晚啦...文件取消分享了</div>")) { resultInfo["success"] = false; fileSize = "来晚啦...文件取消分享了"; } else if (utils.isNull(loadDownHost)) { log.error(pageText); resultInfo["success"] = false; fileSize = "获取sign的域名失败,请反馈开发者"; } else if (utils.isNull(loadDown)) { log.error(pageText); resultInfo["success"] = false; fileSize = "获取sign失败,请反馈开发者"; } else { resultInfo["success"] = false; fileSize = "解析直链失败"; } resultInfo["fileName"] = fileName; resultInfo["fileSize"] = fileSize; resultInfo["fileUploadTime"] = fileUploadTime; } else { log.error(respData); resultInfo["success"] = false; resultInfo["fileName"] = fileName; resultInfo["fileSize"] = `解析失败,${getResp.msg}`; } return resultInfo; }; return this; }, /** * 天翼云 * @constructor * @returns {object} */ tianyiyun: function () { let that = this; this.code = { ShareNotFound: "抱歉,您访问的页面地址有误,或者该页面不存在。", ShareAuditNotPass: "抱歉,该内容审核不通过", FileNotFound: "抱歉,文件不存在", ShareExpiredError: "抱歉,您访问的页面地址有误,或者该页面不存在", ShareAuditWaiting: "抱歉,该链接处于审核中", ShareInfoNotFound: "抱歉,您访问的页面地址有误,或者该页面不存在", FileTooLarge: "抱歉,文件太大,不支持下载", InvalidSessionKey: "天翼云PC端Cookie未生成,是否前去登录?<br />    (注意,需要当前浏览器的UA切换成PC且在登录后要等待进入个人云空间后生成Cookie,不是手机端浏览的个人云空间,那样生成的Cookie无法使用)", }; this.default = async function (netDiskIndex, shareCode, accessCode) { log.info([netDiskIndex, shareCode, accessCode]); that.netDiskIndex = netDiskIndex; that.shareCode = shareCode; that.accessCode = accessCode; await that.getDownloadParams(); }; /** * 获取下载参数 * @returns {Promise} */ this.getDownloadParams = async function () { let postResp = await httpx.post({ url: "https://cloud.189.cn/api/open/share/getShareInfoByCodeV2.action", data: `shareCode=${that.shareCode}`, headers: { accept: "application/json;charset=UTF-8", "content-type": "application/x-www-form-urlencoded", "user-agent": "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Mobile Safari/537.36 Edg/94.0.992.38", referer: "https://cloud.189.cn/", origin: "https://cloud.189.cn", }, onerror: function () {}, }); if (!postResp.status) { let errorData = utils.toJSON(postResp.data[0].responseText); log.error(["获取下载参数失败的JSON信息", errorData]); if (errorData["res_code"] in that.code) { Qmsg.error(that.code[errorData["res_code"]]); } else { Qmsg.error(errorData["res_message"]); } return; } let postData = postResp.data; log.info(postData); let jsonData = utils.toJSON(postData.responseText); if (jsonData.res_code == 0) { log.info(["解析的JSON信息", jsonData]); that.isFolder = jsonData.isFolder; if (that.isFolder) { log.info("该链接是文件夹"); if (that.accessCode) { NetDiskParse.setClipboard( "tianyiyun", that.shareCode, that.accessCode, "已复制" ); } window.open(`https://cloud.189.cn/t/${that.shareCode}`, "_blank"); return; } if (jsonData["needAccessCode"] && !that.accessCode) { Qmsg.error("密码不正确!"); NetDiskUI.newAccessCodeView( undefined, "tianyiyun", that.netDiskIndex, that.shareCode, (userInputAccessCode) => { that.default( that.netDiskIndex, that.shareCode, userInputAccessCode ); } ); return; } that.fileId = jsonData.fileId; that.fileName = jsonData.fileName; that.fileSize = jsonData.fileSize; that.fileType = jsonData.fileType; that.shareId = jsonData.shareId; that.fileCreateDate = jsonData.fileCreateDate; that.fileLastOpTime = jsonData.fileLastOpTime; if (!that.shareId) { await that.getShareId(); } else { await that.getDownloadUrl(); } } else { if (that.code.hasOwnProperty(jsonData["res_code"])) { Qmsg.error(that.code[jsonData["res_code"]]); } else { Qmsg.error("获取FileId失败"); } } }; /** * 暂不需要获取cookie * @returns {string} "" */ this.getCookie = function () { let cookie = ""; return cookie; }; /** * 获取shareId * @returns {Promise} */ this.getShareId = async function () { let getResp = await httpx.get({ url: `https://cloud.189.cn/api/open/share/checkAccessCode.action?shareCode=${that.shareCode}&accessCode=${that.accessCode}`, headers: { accept: "application/json;charset=UTF-8", "cache-control": "no-cache", "user-agent": utils.getRandomAndroidUA(), referer: `https://cloud.189.cn/web/share?code=${that.shareCode}`, }, responseType: "json", }); if (!getResp.status) { return; } let respData = getResp.data; log.info(respData); let jsonData = utils.toJSON(respData.responseText); if (jsonData["res_code"] === 0) { that.shareId = jsonData["shareId"]; await that.getDownloadUrl(); } else { Qmsg.error("获取shareId失败"); log.info(jsonData); } }; /** * 获取下载链接 * @returns {Promise} */ this.getDownloadUrl = async function () { let getResp = await httpx.get({ url: `https://cloud.189.cn/api/open/file/getFileDownloadUrl.action?noCache=0.6537236244516991&fileId=${that.fileId}&dt=1&shareId=${that.shareId}`, headers: { accept: "application/json;charset=UTF-8", "cache-control": "no-cache", "user-agent": utils.getRandomPCUA(), referer: `https://cloud.189.cn/web/share?code=${that.shareCode}`, }, cookie: that.getCookie(), responseType: "json", onerror: function () {}, }); log.info(getResp); if (!getResp.status) { let errorResultJSON = utils.toJSON(getResp.data[0].responseText); if (errorResultJSON["errorCode"] === "InvalidSessionKey") { that.gotoLogin(that.code["InvalidSessionKey"]); } else { Qmsg.error("请求异常"); } return; } let respData = getResp.data; let jsonData = utils.toJSON(respData.responseText); log.info(jsonData); if (jsonData["res_code"] === 0) { let downloadUrl = jsonData["fileDownloadUrl"]; downloadUrl = NetDiskFilterScheme.handleUrl( "tianyiyun-scheme-enable", "tianyiyun-scheme-forward", downloadUrl ); NetDiskUI.staticView.oneFile({ title: "天翼云单文件直链", fileName: that.fileName, fileSize: utils.formatByteToSize(that.fileSize), downloadUrl: downloadUrl, fileUploadTime: that.fileCreateDate, fileLatestTime: that.fileLastOpTime, }); } else if ( "InvalidSessionKey" === jsonData["res_code"] || "InvalidSessionKey" === jsonData["errorCode"] ) { that.gotoLogin(that.code["InvalidSessionKey"]); } else if (that.code.hasOwnProperty(jsonData["res_code"])) { Qmsg.error(that.code[jsonData["res_code"]]); } else { Qmsg.error("请求失败"); log.error(respData); } }; /** * 天翼云登录弹窗 * @param {string} text 弹窗的显示的内容 */ this.gotoLogin = function (text = "") { pops.confirm({ title: { position: "center", text: "天翼云", }, content: { text: text, html: false, }, btn: { reverse: true, position: "end", ok: { text: "前往", enable: true, callback: () => { window.open( "https://cloud.189.cn/api/portal/loginUrl.action?redirectURL=https://cloud.189.cn/web/main", "_blank" ); }, }, }, animation: GM_getValue("popsAnimation", "pops-anim-fadein-zoom"), mask: true, drag: GM_getValue("pcDrag", false), height: pops.isPhone() ? NetDiskUI.popsStyle.tianyiyunNeedLoginTip_Phone.height : NetDiskUI.popsStyle.tianyiyunNeedLoginTip_PC.height, forbiddenScroll: true, width: pops.isPhone() ? NetDiskUI.popsStyle.tianyiyunNeedLoginTip_Phone.width : NetDiskUI.popsStyle.tianyiyunNeedLoginTip_PC.width, }); }; return this; }, /** * 文叔叔 * @constructor * @returns {object} */ wenshushu: function () { let that = this; this.code = { 1004: "no token", 1008: "您没有权限访问", 1013: "糟糕,此任务已过期销毁,下次要记得续期", 1088: "糟糕,您访问的页面不存在", }; this.default = async function (netDiskIndex, shareCode, accessCode) { that.netDiskIndex = netDiskIndex; that.shareCode = shareCode; that.accessCode = accessCode; Qmsg.info("正在请求直链中..."); await that.getWss(); }; this.getWss = async function () { let postResp = await httpx.post({ url: "https://www.wenshushu.cn/ap/login/anonymous", responseType: "json", dataType: "json", data: JSON.stringify({ dev_info: "{}", }), headers: { accept: "application/json, text/plain, */*", "user-agent": utils.getRandomAndroidUA(), referer: window.location.origin, }, }); log.success(postResp); if (!postResp.status) { return; } let respData = postResp.data; let jsonData = utils.toJSON(respData.responseText); if (jsonData["code"] === 0) { that.token = jsonData["data"]["token"]; await that.getPid(); } else if (jsonData["code"] in that.code) { Qmsg.error(that.code[jsonData["code"]]); } else { Qmsg.error("获取wss失败"); } }; /** * 获取pid * @returns {Promise} */ this.getPid = async function () { let postResp = await httpx.post({ url: "https://www.wenshushu.cn/ap/task/mgrtask", dataType: "json", responseType: "json", data: JSON.stringify({ tid: that.shareCode, password: "", ufileid: "", }), headers: { accept: "application/json, text/plain, */*", "user-agent": utils.getRandomAndroidUA(), referer: window.location.origin, "x-token": that.token, }, }); log.success(postResp); if (!postResp.status) { return; } let respData = postResp.data; let jsonData = utils.toJSON(respData.responseText); if (jsonData["code"] === 0) { let bid = jsonData["data"]["boxid"]; let pid = jsonData["data"]["ufileid"]; await that.getFileNList(bid, pid); } else if (jsonData["code"] in that.code) { Qmsg.error(that.code[jsonData["code"]]); } else { Qmsg.error("获取pid失败"); } }; /** * 获取文件列表信息 * @param {string} bid * @param {string} pid * @returns */ this.getFileNList = async function (bid, pid) { let postResp = await httpx.post({ url: "https://www.wenshushu.cn/ap/ufile/nlist", dataType: "json", responseType: "json", data: JSON.stringify({ start: 0, sort: { name: "asc", }, bid: bid, pid: pid, options: { uploader: "true", }, size: 50, }), headers: { accept: "application/json, text/plain, */*", "user-agent": "Mozilla/5.0 (Linux; Android 6.0.1; Moto G (4)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Mobile Safari/537.36 Edg/91.0.864.59", referer: window.location.origin, "x-token": that.token, }, }); log.success(postResp); if (!postResp.status) { return; } let respData = postResp.data; let jsonData = utils.toJSON(respData.responseText); if (jsonData["code"] === 0) { if (jsonData["data"]["fileList"][0]["type"] === 2) { Qmsg.error("该链接为多层级文件嵌套,跳转"); NetDiskParse.blank( NetDiskParse.getBlankUrl( "wenshushu", that.netDiskIndex, that.shareCode, that.accessCode ), "wenshushu", that.shareCode, that.accessCode ); } else { await that.getDownloadUrl(jsonData["data"]["fileList"][0]); } } else if (jsonData["code"] in that.code) { Qmsg.error(that.code[jsonData["code"]]); } else { Qmsg.error("获取文件信息失败"); } }; /** * 获取下载链接 * @param {object} data * @returns {Promise} */ this.getDownloadUrl = async function (data) { let file_name = data.fname; let file_size = utils.formatByteToSize(data.size); let postResp = await httpx.post({ url: "https://www.wenshushu.cn/ap/dl/sign", dataType: "json", responseType: "json", data: JSON.stringify({ ufileid: data.fid, consumeCode: 0, }), headers: { accept: "application/json, text/plain, */*", "user-agent": utils.getRandomAndroidUA(), referer: window.location.origin, "x-token": that.token, }, }); if (!postResp.status) { return; } log.success(postResp); let respData = postResp.data; let jsonData = utils.toJSON(respData.responseText); if (jsonData["code"] == 0) { let downloadUrl = jsonData["data"]["url"]; if (downloadUrl === "") { Qmsg.error("对方的分享流量不足"); } else { downloadUrl = NetDiskFilterScheme.handleUrl( "wenshushu-static-scheme-enable", "wenshushu-static-scheme-forward", downloadUrl ); /* 文叔叔没有上传时间信息(暂时是这样的) */ NetDiskUI.staticView.oneFile({ title: "文叔叔单文件直链", fileName: file_name, fileSize: file_size, downloadUrl: downloadUrl, }); } } else if (jsonData["data"] in that.code) { Qmsg.error(that.code[jsonData["data"]]); } else { Qmsg.error("获取下载链接失败"); } }; return this; }, /** * 123盘 * @constructor * @returns {object} */ _123pan: function () { let that = this; this.code = { 5103: "分享码错误或者分享地址错误", 5104: "分享已过期", "-1000": "获取出错", "-2000": "请求异常", "-3000": "请求意外中止", "-4000": "请求超时", 104: "文件已失效", }; this.default = async function (netDiskIndex, shareCode, accessCode) { log.info([netDiskIndex, shareCode, accessCode]); that.netDiskIndex = netDiskIndex; that.shareCode = shareCode; that.accessCode = accessCode; that.panelList = []; that.Authorization = GM_getValue("_123pan_User_Authorization"); let checkLinkValidityStatus = await that.checkLinkValidity(); if (!checkLinkValidityStatus) { return; } let infoLists = await that.getFiles(); if (!infoLists) { return; } if (infoLists.length === 1 && infoLists[0]["Type"] == 0) { let fileInfo = infoLists[0]; if (fileInfo["Status"] == 104) { Qmsg.error("文件已失效"); return; } let downloadUrl = fileInfo["DownloadUrl"]; let fileSize = ""; if (downloadUrl === "") { let downloadInfo = await that.getFileDownloadInfo( fileInfo["Etag"], fileInfo["FileId"], fileInfo["S3KeyFlag"], that.shareCode, fileInfo["Size"] ); if (downloadInfo && downloadInfo["code"] === 0) { downloadUrl = NetDiskFilterScheme.handleUrl( "_123pan-static-scheme-enable", "_123pan-static-scheme-forward", downloadInfo["data"]["DownloadURL"] ); fileSize = utils.formatByteToSize(fileInfo["Size"]); } else if (downloadInfo && downloadInfo["code"] === 401) { downloadUrl = "javascript:;"; fileSize = "请登录后下载"; } else { downloadUrl = "javascript:;"; fileSize = "获取下载链接失败"; } } else { downloadUrl = NetDiskFilterScheme.handleUrl( "_123pan-static-scheme-enable", "_123pan-static-scheme-forward", downloadUrl ); fileSize = utils.formatByteToSize(fileInfo["Size"]); } let fileUploadTime = new Date(fileInfo["CreateAt"]).getTime(); let fileLatestTime = new Date(fileInfo["UpdateAt"]).getTime(); fileUploadTime = utils.formatTime(fileUploadTime); fileLatestTime = utils.formatTime(fileLatestTime); NetDiskUI.staticView.oneFile({ title: "123盘单文件直链", fileName: fileInfo["FileName"], fileSize: fileSize, downloadUrl: downloadUrl, fileUploadTime: fileUploadTime, fileLatestTime: fileLatestTime, }); } else { Qmsg.info("正在递归文件"); that.folderNumber = 0; await that.recursiveAlgorithm(infoLists); Qmsg.info("正在排序中..."); utils.sortListByProperty(that.panelList, (item) => { let timeStamp = new Date(item["updateTime"]).getTime(); return timeStamp; }); log.info(that.panelList); let dataDownload = []; that.panelList.forEach((item) => { let fileUploadTime = new Date(item["createTime"]).getTime(); let fileLatestTime = new Date(item["updateTime"]).getTime(); fileUploadTime = utils.formatTime(fileUploadTime); fileLatestTime = utils.formatTime(fileLatestTime); let dataDownloadInfo = { fileName: item["fileName"], fileUploadTime, fileLatestTime, }; if (item["fileSize"] === 0) { /* 异常的 */ dataDownloadInfo["success"] = false; if ( typeof item["url"] === "string" && !item["url"].startsWith("http") ) { dataDownloadInfo["fileSize"] = item["url"]; } else { dataDownloadInfo["fileSize"] = "获取直链失败"; } } else { /* 正常的 */ dataDownloadInfo["success"] = true; dataDownloadInfo["downloadUrl"] = item["url"]; dataDownloadInfo["fileSize"] = item["fileSize"]; } dataDownload.push(dataDownloadInfo); }); NetDiskUI.staticView.moreFile("123盘多文件直链", dataDownload); log.info("递归完毕"); } }; /** * 校验链接有效性 * @returns {boolean} */ this.checkLinkValidity = async function () { Qmsg.info("正在校验链接有效性"); let url = `https://www.123pan.com/s/${that.shareCode}`; let getResp = await httpx.get({ url: url, headers: { "user-agent": utils.getRandomPCUA(), referer: "https://www.123pan.com", }, }); log.info(getResp); if (!getResp.status) { return false; } let respData = getResp.data; let g_initialPropsMatch = respData.responseText.match( /window.g_initialProps[\s]*=[\s]*\{(.+?)\};/s ); if (g_initialPropsMatch) { log.info(g_initialPropsMatch); let g_initialProps = utils.toJSON( `{${g_initialPropsMatch[g_initialPropsMatch.length - 1]}}` ); log.info(g_initialProps); if (g_initialProps.res.code !== 0) { Qmsg.error(g_initialProps.res.message); return false; } let HasPwd = g_initialProps.res.data.HasPwd; if (HasPwd && (that.accessCode == null || that.accessCode === "")) { /* 该链接需要密码但是没有获取到 */ Qmsg.error("密码缺失!"); NetDiskUI.newAccessCodeView( "密码缺失", "_123pan", that.netDiskIndex, that.shareCode, (userInputAccessCode) => { that.default( that.netDiskIndex, that.shareCode, userInputAccessCode ); } ); } else { /* 该链接不需要密码 || 该链接需要密码且已获取到 */ return true; } } else { Qmsg.error("校验链接-获取初始化内容失败"); } }; /** * 获取文件 * @param {number} parentFileId * @returns {Promise} */ this.getFiles = async function (parentFileId = 0) { let url = `https://www.123pan.com/b/api/share/get?limit=100&next=1&orderBy=share_id&orderDirection=desc&shareKey=${that.shareCode}&SharePwd=${that.accessCode}&ParentFileId=${parentFileId}&Page=1`; let getResp = await httpx.get({ url: url, headers: { accept: "*/*", "user-agent": utils.getRandomPCUA(), referer: `https://www.123pan.com/s/${that.shareCode}`, }, }); log.info(getResp); if (!getResp.status) { return; } let respData = getResp.data; let json_data = utils.toJSON(respData.responseText); if (json_data["code"] === 0) { let infoList = json_data["data"]["InfoList"]; return infoList; } else if (json_data["code"] === 5103) { NetDiskUI.newAccessCodeView( undefined, "_123pan", that.netDiskIndex, that.shareCode, (userInputAccessCode) => { that.default( that.netDiskIndex, that.shareCode, userInputAccessCode ); } ); } else if (that.code[json_data["code"]]) { Qmsg.error(that.code[json_data["code"]]); } else if ("message" in json_data) { Qmsg.error(json_data["message"]); } else { Qmsg.error("123盘:未知的JSON格式"); } }; /** * 递归算法使用的请求 * @param {string} parentFileId * @returns */ this.getFilesByRec = async function (parentFileId) { let getResp = await httpx.get({ url: `https://www.123pan.com/b/api/share/get?limit=100&next=1&orderBy=share_id&orderDirection=desc&shareKey=${that.shareCode}&SharePwd=${that.accessCode}&ParentFileId=${parentFileId}&Page=1`, headers: { accept: "*/*", "user-agent": utils.getRandomAndroidUA(), referer: `https://www.123pan.com/s/${that.shareCode}`, }, }); if (!getResp.status) { return; } let respData = getResp.data; log.info(respData); let jsonData = utils.toJSON(respData.responseText); if (jsonData["code"] == 0) { return jsonData["data"]["InfoList"]; } }; /** * 异步递归算法 * @param {Array} infoList */ this.recursiveAlgorithm = async function (infoList) { for (let i = 0; i < infoList.length; i++) { let item = infoList[i]; let fileType = item["Type"]; log.info(fileType ? "文件夹" : "文件"); if (fileType) { /* 是文件夹 */ let retList = await that.getFilesByRec(item["FileId"]); retList && (await that.recursiveAlgorithm(retList)); } else { /* 是文件 */ log.info(item); let fileName = item["FileName"]; let fileSize = utils.formatByteToSize(item["Size"]); let fileDownloadUrl = item["DownloadUrl"]; let fileStatus = item["Status"]; /* 文件有效状态 */ if (fileStatus == 104) { that.panelList = [ ...that.panelList, { url: "文件已失效", fileName: fileName, fileSize: 0, createTime: item["CreateAt"], updateTime: item["UpdateAt"], }, ]; } else if (fileDownloadUrl === "") { let downloadInfo = await that.getFileDownloadInfo( item["Etag"], item["FileId"], item["S3KeyFlag"], that.shareCode, item["Size"] ); if (downloadInfo && downloadInfo["code"] === 0) { fileDownloadUrl = downloadInfo["data"]["DownloadURL"]; NetDiskFilterScheme.handleUrl( "_123pan-static-scheme-enable", "_123pan-static-scheme-forward", fileDownloadUrl ); that.panelList = [ ...that.panelList, { url: fileDownloadUrl, fileName: fileName, fileSize: fileSize, createTime: item["CreateAt"], updateTime: item["UpdateAt"], }, ]; } else if (downloadInfo && downloadInfo["code"] === 401) { that.panelList = [ ...that.panelList, { url: "请登录后下载", fileName: fileName, fileSize: 0, createTime: item["CreateAt"], updateTime: item["UpdateAt"], }, ]; } else { that.panelList = [ ...that.panelList, { url: "获取下载链接失败", fileName: fileName, fileSize: 0, createTime: item["CreateAt"], updateTime: item["UpdateAt"], }, ]; } } else { fileDownloadUrl = NetDiskFilterScheme.handleUrl( "_123pan-static-scheme-enable", "_123pan-static-scheme-forward", fileDownloadUrl ); that.panelList = [ ...that.panelList, { url: fileDownloadUrl, fileName: fileName, fileSize: fileSize, createTime: item["CreateAt"], updateTime: item["UpdateAt"], }, ]; } } } }; /** * 获取单文件下载链接 * 123云盘新增了下载验证 * @param {string} Etag * @param {string} FileID * @param {string} S3keyFlag * @param {string} ShareKey * @param {string} Size * @returns */ this.getFileDownloadInfo = async function ( Etag, FileID, S3keyFlag, ShareKey, Size ) { let authK_V = that.getFileDownloadAuth(); let headers = { "App-Version": "3", Platform: "web", "Content-Type": "application/json;charset=UTF-8", Host: "www.123pan.com", accept: "*/*", "user-agent": utils.getRandomPCUA(), Referer: "https://www.123pan.com/s/" + ShareKey, Origin: "https://www.123pan.com", }; if (that.Authorization) { headers["Authorization"] = "Bearer " + that.Authorization; } log.success("获取下载链接加密参数:" + authK_V); let postResp = await httpx.post({ url: `https://www.123pan.com/a/api/share/download/info?${authK_V[0]}=${authK_V[1]}`, data: JSON.stringify({ Etag: Etag, FileID: FileID, S3keyFlag: S3keyFlag, ShareKey: ShareKey, Size: Size, }), responseType: "json", headers: headers, }); if (!postResp.status) { return; } let postData = postResp.data; let jsonData = utils.toJSON(postData.responseText); log.info(jsonData); if (jsonData["code"] == 0) { jsonData["data"]["DownloadURL"] = await that.decodeDownloadUrl( jsonData["data"]["DownloadURL"] ); return jsonData; } else { return { code: jsonData["code"], }; } }; /** * 获取单文件下载链接的加密参数 * 感谢:https://github.com/qaiu/netdisk-fast-download/ */ this.getFileDownloadAuth = function () { function encry_time(param) { var param_time, param_other = arguments["length"] > 0x2 && void 0x0 !== arguments[0x2] ? arguments[0x2] : 0x8; if (0x0 === arguments["length"]) return null; "object" === typeof param ? (param_time = param) : (0xa === ("" + param)["length"] && (param = 0x3e8 * parseInt(param)), (param_time = new Date(param))); var param_timezoneoffset = param + 0xea60 * new Date(param)["getTimezoneOffset"](), param_time_n = param_timezoneoffset + 0x36ee80 * param_other; return ( (param_time = new Date(param_time_n)), { y: param_time["getFullYear"](), m: param_time["getMonth"]() + 0x1 < 0xa ? "0" + (param_time["getMonth"]() + 0x1) : param_time["getMonth"]() + 0x1, d: param_time["getDate"]() < 0xa ? "0" + param_time["getDate"]() : param_time["getDate"](), h: param_time["getHours"]() < 0xa ? "0" + param_time["getHours"]() : param_time["getHours"](), f: param_time["getMinutes"]() < 0xa ? "0" + param_time["getMinutes"]() : param_time["getMinutes"](), } ); } function encry_join(param) { for ( var a = arguments["length"] > 0x1 && void 0x0 !== arguments[0x1] ? arguments[0x1] : 0xa, funcRun = function () { for (var b, c = [], d = 0x0; d < 0x100; d++) { b = d; for (var index = 0x0; index < 0x8; index++) b = 0x1 & b ? 0xedb88320 ^ (b >>> 0x1) : b >>> 0x1; c[d] = b; } return c; }, _funcRun_ = funcRun(), _param = param, _param_1 = -0x1, _param_0 = 0x0; _param_0 < _param["length"]; _param_0++ ) _param_1 = (_param_1 >>> 0x8) ^ _funcRun_[0xff & (_param_1 ^ _param.charCodeAt(_param_0))]; return (_param_1 = (-0x1 ^ _param_1) >>> 0x0), _param_1.toString(a); } function getSign(urlPath) { var param_web = "web"; var param_type = 3; var param_time = Math.round( (new Date().getTime() + 0x3c * new Date().getTimezoneOffset() * 0x3e8 + 28800000) / 0x3e8 ).toString(); var key = "a,d,e,f,g,h,l,m,y,i,j,n,o,p,k,q,r,s,t,u,b,c,v,w,s,z"; var randomRoundNum = Math["round"](0x989680 * Math["random"]()); var number_split; var time_a; var time_y; var time_m; var time_d; var time_h; var time_f; var time_array; var time_push; for (var number_item in ((number_split = key.split(",")), (time_a = encry_time(param_time)), (time_y = time_a["y"]), (time_m = time_a["m"]), (time_d = time_a["d"]), (time_h = time_a["h"]), (time_f = time_a["f"]), (time_array = [time_y, time_m, time_d, time_h, time_f].join("")), (time_push = []), time_array)) time_push["push"](number_split[Number(time_array[number_item])]); var param_no; var param_join_s; return ( (param_no = encry_join(time_push["join"](""))), (param_join_s = encry_join( "" ["concat"](param_time, "|") ["concat"](randomRoundNum, "|") ["concat"](urlPath, "|") ["concat"](param_web, "|") ["concat"](param_type, "|") ["concat"](param_no) )), [ param_no, "" ["concat"](param_time, "-") ["concat"](randomRoundNum, "-") ["concat"](param_join_s), ] ); } return getSign("/a/api/share/download/info"); }; /** * 将直链的param参数解析成真正的直链 * @param {string} url * @returns */ this.decodeDownloadUrl = async function (url) { if (url === "") { return ""; } let decodeURL = new URL(url); let params = decodeURL.search.replace(/^\?params=/gi, ""); params = params.split("&")[0]; try { let newDecodeUrl = decodeURI(atob(params)); Qmsg.info("正在获取重定向直链"); let getResp = await httpx.get({ url: newDecodeUrl, responseType: "json", "user-agent": utils.getRandomAndroidUA(), Referer: "https://www.123pan.com/s/" + that.shareCode, Origin: "https://www.123pan.com", onerror: function () {}, }); log.info(getResp); if (!getResp.status && getResp.data[0].status !== 210) { /* 很奇怪,123盘返回的状态码是210 */ return newDecodeUrl; } let respData = getResp.data[0]; let resultJSON = utils.toJSON(respData.responseText); let newURL = new URL(resultJSON.data.redirect_url); newURL.searchParams.set("auto_redirect", 1); log.success(resultJSON); return newURL.toString(); } catch (error) { log.error(error); return url; } }; return this; }, /** * 坚果云 * @constructor * @returns {object} */ jianguoyun: function () { let that = this; this.errorCode = { UnAuthorized: "请先登录坚果云账号", }; this.default = async function (netDiskIndex, shareCode, accessCode) { log.info([netDiskIndex, shareCode, accessCode]); that.netDiskIndex = netDiskIndex; that.shareCode = shareCode; that.accessCode = accessCode; let downloadParams = await that.getRequestDownloadParams(); if (!downloadParams) { return; } if (downloadParams["isdir"]) { /* 是文件夹 */ that.parseMoreFile(downloadParams["hash"], downloadParams["name"]); } else { /* 是文件 */ let fileSize = utils.formatByteToSize(downloadParams["size"]); let downloadUrl = await that.getFileLink( downloadParams.hash, downloadParams.name ); if (!downloadUrl) { return; } downloadUrl = NetDiskFilterScheme.handleUrl( "jianguoyun-static-scheme-enable", "jianguoyun-static-scheme-forward", downloadUrl ); log.info(downloadUrl); /* 坚果云盘没有上传时间信息(暂时是这样的) */ NetDiskUI.staticView.oneFile({ title: "坚果云盘单文件直链", fileName: downloadParams["name"], fileSize: fileSize, downloadUrl: downloadUrl, }); } }; /** * 解析多文件信息 * @param {string} hash 文件hash值 * @param {string} fileName 文件名 * @returns */ this.parseMoreFile = async function (hash = "", fileName = "") { let folderInfo = await that.getFolderInfo(hash); if (!folderInfo) { return; } let downloadList = []; Qmsg.success("正在遍历多文件信息"); for (let i = 0; i < folderInfo.length; i++) { let item = folderInfo[i]; let downloadUrl = await that.getDirLink( hash, fileName, item["relPath"] ); if (!downloadUrl) { return; } downloadUrl = NetDiskFilterScheme.handleUrl( "jianguoyun-static-scheme-enable", "jianguoyun-static-scheme-forward", downloadUrl ); log.info(downloadUrl); downloadList = [ ...downloadList, { url: downloadUrl, name: item["relPath"].replace(/^\//gi, ""), size: utils.formatByteToSize(item["size"]), mtime: item["mtime"], content: "", }, ]; await utils.sleep(150); } if (downloadList.length == 0) { return; } let folderList = []; utils.sortListByProperty(downloadList, (item) => { return item["mtime"]; }); downloadList.forEach((item) => { folderList.push({ success: true, fileName: item["name"], fileSize: item["size"], downloadUrl: item["url"], }); }); /* 坚果云盘没有上传时间信息(暂时是这样的) */ NetDiskUI.staticView.moreFile("坚果云多文件直链", folderList); }; /** * 获取下载链接所需要的hash值和name */ this.getRequestDownloadParams = async function () { log.info("获取hash值"); Qmsg.info("正在获取请求信息"); let pageInfoRegexp = /var[\s]*PageInfo[\s]*=[\s]*{([\s\S]+)};/i; let formData = new FormData(); formData.append("pd", that.accessCode); let requestDetails = { url: `https://www.jianguoyun.com/p/${that.shareCode}`, data: that.accessCode === "" ? undefined : `pd=${that.accessCode}`, responseType: "html", headers: { "content-type": "application/x-www-form-urlencoded", "User-Agent": utils.getRandomPCUA(), referer: `https://www.jianguoyun.com/p/${that.shareCode}`, }, }; let requestResp = null; if (that.accessCode === "") { requestResp = await httpx.get(requestDetails); } else { requestResp = await httpx.post(requestDetails); } if (!requestResp.status) { return; } let respData = requestResp.data; log.info("请求信息"); log.info(respData); let pageInfo = respData.responseText.match(pageInfoRegexp); if (pageInfo) { pageInfo = pageInfo[pageInfo.length - 1]; pageInfo = `({${pageInfo}})`; pageInfo = eval(pageInfo); log.info(pageInfo); let fileName = pageInfo["name"]; let fileSize = pageInfo["size"]; let fileHash = pageInfo["hash"]; let fileNeedsPassword = pageInfo["needsPassword"]; let fileOwner = pageInfo["owner"]; let isdir = pageInfo["isdir"]; let fileErrorCode = pageInfo["errorCode"]; fileName = decodeURIComponent(fileName); log.success("是否是文件夹 ===> " + isdir); log.success("hash ===> " + fileHash); log.success("name ===> " + fileName); log.success("size ===> " + fileSize); if ( fileNeedsPassword && (that.accessCode == null || that.accessCode === "") ) { /* 需要密码但没密码 */ Qmsg.error("密码不正确!"); NetDiskUI.newAccessCodeView( "密码缺失", "jianguoyun", that.netDiskIndex, that.shareCode, (userInputAccessCode) => { that.default( that.netDiskIndex, that.shareCode, userInputAccessCode ); } ); return; } if (fileErrorCode === "AuthenticationFailed") { Qmsg.error("密码错误"); NetDiskUI.newAccessCodeView( undefined, "jianguoyun", that.netDiskIndex, that.shareCode, (userInputAccessCode) => { that.default( that.netDiskIndex, that.shareCode, userInputAccessCode ); } ); return; } if (fileHash === "" || fileHash == null) { log.error("hash为空,可能文件被撤销分享了"); Qmsg.error(`文件分享已被撤销`); return; } if (fileSize == null && isdir == false) { log.error("无size,可能文件被删除了"); Qmsg.error(`“${fileName}”文件已被拥有者(“${fileOwner}”)删除`); return; } else { return { name: fileName, hash: fileHash, size: fileSize, needsPassword: fileNeedsPassword, owner: fileOwner, isdir: isdir, }; } } else if ( respData.responseText.match("对不起,找不到您指定的文件。") ) { log.error("啊噢! (404) 对不起,找不到您指定的文件。"); Qmsg.error("坚果云: 对不起,找不到您指定的文件。"); } else if ( respData.responseText.match("对不起,您的某些输入不正确。") ) { log.error("可能该链接不需要访问码或者访问码有问题"); NetDiskUI.newAccessCodeView( undefined, "jianguoyun", that.netDiskIndex, that.shareCode, (userInputAccessCode) => { that.default( that.netDiskIndex, that.shareCode, userInputAccessCode ); } ); } else { log.error("获取PageInfo失败"); Qmsg.error("坚果云: 获取PageInfo失败"); } }; /** * 获取下载链接 * @param {string} fileHash 文件hash值 * @param {string} fileName 文件名 * @returns {Promise} */ this.getFileLink = async function (fileHash = "", fileName = "") { fileName = encodeURIComponent(fileName); let getResp = await httpx.get({ url: `https://www.jianguoyun.com/d/ajax/fileops/pubFileLink?k=${fileHash}&name=${fileName}&wm=false${ that.accessCode === "" ? "" : "&pd=" + that.accessCode }&forwin=1&_=${new Date().getTime()}`, responseType: "json", headers: { "User-Agent": utils.getRandomPCUA(), }, onerror: function () {}, }); if (!getResp.status) { if (utils.isNotNull(getResp.data[0]?.responseText)) { let errorData = utils.toJSON(getResp.data[0].responseText); log.error(["坚果云", errorData]); if (errorData["errorCode"] === "UnAuthorized") { that.gotoLogin(); } else { Qmsg.error(errorData["detailMsg"]); } } else { Qmsg.error("请求异常"); } return; } let respData = getResp.data; log.info(["请求信息", respData]); let resultJSON = utils.toJSON(respData.responseText); log.info(["解析JSON", resultJSON]); if (resultJSON.hasOwnProperty("errorCode")) { Qmsg.error("坚果云: " + resultJSON["detailMsg"]); return; } else if (resultJSON.hasOwnProperty("url")) { return resultJSON["url"]; } else { Qmsg.error("坚果云: 处理下载链接异常"); } }; /** * 获取文件夹下的文件下载链接 * @param {string} fileHash * @param {string} fileName * @param {string} filePath * @returns {Promise} */ this.getDirLink = async function ( fileHash = "", fileName = "", filePath = "/" ) { fileName = encodeURIComponent(fileName); let getResp = await httpx.get({ url: `https://www.jianguoyun.com/d/ajax/dirops/pubDIRLink?k=${fileHash}&dn=${fileName}&p=${filePath}&forwin=1&_=${new Date().getTime()}`, responseType: "json", headers: { "User-Agent": utils.getRandomPCUA(), }, onerror: function () {}, }); if (!getResp.status) { if (utils.isNotNull(getResp.data[0]?.responseText)) { let errorData = utils.toJSON(getResp.data[0].responseText); log.error(["坚果云", errorData]); if (errorData["errorCode"] === "UnAuthorized") { that.gotoLogin(); } else { Qmsg.error(errorData["detailMsg"]); } } else { Qmsg.error("请求异常"); } return; } let respData = getResp.data; log.info(["请求信息", respData]); let resultJSON = utils.toJSON(respData.responseText); log.info(resultJSON); if (resultJSON.hasOwnProperty("errorCode")) { Qmsg.error("坚果云: " + resultJSON["detailMsg"]); return; } else if (resultJSON.hasOwnProperty("url")) { return resultJSON["url"]; } else { Qmsg.error("坚果云: 处理下载链接异常"); } }; /** * 获取文件夹信息 * @param {string} hash * @returns */ this.getFolderInfo = async function (hash = "") { let getResp = await httpx.get({ url: `https://www.jianguoyun.com/d/ajax/dirops/pubDIRBrowse?hash=${hash}&relPath=%2F&_=${new Date().getTime()}`, responseType: "json", headers: { "User-Agent": utils.getRandomPCUA(), }, }); if (!getResp.status) { return; } let respData = getResp.data; log.info(["请求信息", respData]); let resultJSON = utils.toJSON(respData.responseText); log.info(resultJSON); if ("objects" in resultJSON) { return resultJSON["objects"]; } else { Qmsg.error("坚果云: 处理多文件信息异常"); } }; /** * 前往登录 */ this.gotoLogin = function () { pops.confirm({ mask: true, title: { text: "提示", position: "center", }, content: { text: `解析失败,原因:当前尚未登录坚果云,是否前往登录?`, }, btn: { reverse: true, position: "end", ok: { text: "前往", callback: function (_event_) { window.open( "https://www.jianguoyun.com/d/login#from=https%3A%2F%2Fwww.jianguoyun.com%2F", "_blank" ); }, }, }, }); }; return this; }, /** * 奶牛快传 * 感谢:https://github.com/qaiu/netdisk-fast-download * @constructor * @returns {object} */ nainiu: function () { let that = this; this.default = async function (netDiskIndex, shareCode, accessCode) { log.info([netDiskIndex, shareCode, accessCode]); that.netDiskIndex = netDiskIndex; that.shareCode = shareCode; that.accessCode = accessCode; that.panelList = []; that.panelContent = ""; let checkLinkValidityInfo = await that.checkLinkValidity(); if (!checkLinkValidityInfo) { return; } let downloadUrl = null; if (checkLinkValidityInfo["zipDownload"]) { downloadUrl = await that.getZipFileDownloadUrl( checkLinkValidityInfo["guid"], checkLinkValidityInfo["fileName"] ); } else { downloadUrl = await that.getDownloadUrl( checkLinkValidityInfo["guid"], checkLinkValidityInfo["id"] ); } if (!downloadUrl) { return; } downloadUrl = NetDiskFilterScheme.handleUrl( "nainiu-static-scheme-enable", "nainiu-static-scheme-forward", downloadUrl ); NetDiskUI.staticView.oneFile({ title: "奶牛快传单文件直链", fileName: checkLinkValidityInfo["fileName"], fileType: checkLinkValidityInfo["fileType"], fileSize: checkLinkValidityInfo["fileSize"], downloadUrl: downloadUrl, fileUploadTime: checkLinkValidityInfo["fileUploadTime"], fileLatestTime: checkLinkValidityInfo["fileLatestTime"], clickCallBack: (_fileDetails_) => { Qmsg.info( `调用【GM_download】下载:${checkLinkValidityInfo["fileName"]}` ); if (typeof GM_download === "undefined") { Qmsg.error("当前脚本环境缺失API 【GM_download】"); return; } GM_download({ url: downloadUrl, name: _fileDetails_["fileName"], headers: { Referer: "https://cowtransfer.com/", }, onload: () => { Qmsg.success( `下载 ${checkLinkValidityInfo["fileName"]} 已完成` ); }, onerror: function (error) { log.error(["下载失败error👉", error]); if (typeof error === "object" && error["error"]) { Qmsg.error( `下载 ${checkLinkValidityInfo["fileName"]} 失败或已取消 原因:${error["error"]}`, { timeout: 6000, } ); } else { Qmsg.error( `下载 ${checkLinkValidityInfo["fileName"]} 失败或已取消` ); } }, ontimeout: () => { Qmsg.error( `下载 ${checkLinkValidityInfo["fileName"]} 请求超时` ); }, }); }, }); }; /** * 校验链接有效性并解析获取信息 * @returns {boolean| { * zipDownload: boolean, * guid:string, * fileSize: string, * fileName: string, * fileUploadTime: number, * fileLatestTime: number, * } | { * zipDownload: boolean, * guid:string, * id: string, * fileSize: string, * fileType: string, * fileName: string, * fileUploadTime: number, * fileLatestTime: number, * * }} */ this.checkLinkValidity = async function () { let url = `https://cowtransfer.com/core/api/transfer/share?uniqueUrl=${that.shareCode}`; let getResp = await httpx.get({ url: url, headers: { "user-agent": utils.getRandomPCUA(), referer: "`https://cowtransfer.com", }, }); log.info(getResp); if (!getResp.status) { return false; } let respData = getResp.data; let resultJSON = utils.toJSON(respData.responseText); log.info(["转换的JSON", resultJSON]); let code = resultJSON["code"]; let message = resultJSON["message"]; if (code !== "0000") { Qmsg.error(message); return false; } else { let needPassword = resultJSON["data"]["needPassword"]; let zipDownload = resultJSON["data"]["zipDownload"]; if (needPassword && utils.isNull(that.accessCode)) { Qmsg.error("密码缺失!"); NetDiskUI.newAccessCodeView( "密码缺失", "nainiu", that.netDiskIndex, that.shareCode, (userInputAccessCode) => { that.default( that.netDiskIndex, that.shareCode, userInputAccessCode ); } ); return false; } else if (zipDownload) { /* 压缩包下载 */ Qmsg.success("该文件为压缩包"); return { zipDownload: zipDownload, guid: resultJSON["data"]["guid"], fileSize: utils.formatByteToSize( resultJSON["data"]["firstFolder"]["size"] ), fileName: resultJSON["data"]["firstFolder"]["title"], fileUploadTime: utils.formatTime( resultJSON["data"]["firstFolder"]["created_at"] ), fileLatestTime: utils.formatTime( resultJSON["data"]["firstFolder"]["updated_at"] ), }; } else if (resultJSON["data"]["firstFile"] == null) { /* 文件夹类型 */ Qmsg.error("该链接为文件夹类型"); NetDiskParse.blank( NetDiskParse.getBlankUrl( "nainiu", that.netDiskIndex, that.shareCode, that.accessCode ), "nainiu", that.shareCode, that.accessCode ); return false; } { return { zipDownload: zipDownload, guid: resultJSON["data"]["guid"], id: resultJSON["data"]["firstFile"]["id"], fileSize: utils.formatByteToSize( resultJSON["data"]["firstFile"]["file_info"]["size"] ), fileName: resultJSON["data"]["firstFile"]["file_info"]["title"], fileType: resultJSON["data"]["firstFile"]["file_info"]["format"], fileUploadTime: utils.formatTime( resultJSON["data"]["firstFile"]["created_at"] ), fileLatestTime: utils.formatTime( resultJSON["data"]["firstFile"]["updated_at"] ), }; } } }; /** * 获取下载链接 * @param {string} guid * @param {string} id * @returns {string|undefined} */ this.getDownloadUrl = async function (guid = "", id = "") { let url = `https://cowtransfer.com/core/api/transfer/share/download?transferGuid=${guid}&fileId=${id}`; let getResp = await httpx.get({ url: url, headers: { "user-agent": utils.getRandomPCUA(), referer: "`https://cowtransfer.com", }, }); log.info(getResp); if (!getResp.status) { return; } let respData = getResp.data; let resultJSON = utils.toJSON(respData.responseText); log.info(["转换的JSON", resultJSON]); if (resultJSON["code"] === "0000") { return resultJSON["data"]["downloadUrl"]; } else { Qmsg.error(`奶牛快传-获取直链:${resultJSON["message"]}`); return; } }; /** * 获取zip文件的下载链接 * @param {string} guid * @param {string} title 标题 * @returns {string|undefined} */ this.getZipFileDownloadUrl = async function (guid = "", title = "") { let url = `https://cowtransfer.com/core/api/transfer/share/download?transferGuid=${guid}&title=${title}`; let getResp = await httpx.get({ url: url, headers: { "user-agent": utils.getRandomPCUA(), referer: "`https://cowtransfer.com", }, }); log.info(getResp); if (!getResp.status) { return; } let respData = getResp.data; let resultJSON = utils.toJSON(respData.responseText); log.info(["转换的JSON", resultJSON]); if (resultJSON["code"] === "0000") { return resultJSON["data"]["downloadUrl"]; } else { Qmsg.error(`奶牛快传-获取直链:${resultJSON["message"]}`); return; } }; return this; }, }, /** * 网盘链接解析 * @param {string} netDiskName 网盘名称 * @param {number} netDiskIndex 网盘名称索引下标 * @param {string} shareCode * @param {string} accessCode */ async parse(netDiskName, netDiskIndex, shareCode, accessCode) { Qmsg.info("正在获取直链"); if (this.netDisk[netDiskName]) { var parseObj = new this.netDisk[netDiskName](); await parseObj.default(netDiskIndex, shareCode, accessCode); } else { log.error(`${netDiskName} 不存在解析`); Qmsg.error("该链接不存在解析功能"); } }, /** * 复制到剪贴板 * @param {string} netDiskName * @param {string} shareCode * @param {string} accessCode * @param {string} toastText 提示的文字 */ setClipboard( netDiskName, shareCode, accessCode, toastText = "提取码已复制" ) { utils.setClip(accessCode); GM_setValue("tempNetDiskInfo", { shareCode: shareCode, accessCode: accessCode, netDiskName: netDiskName, }); Qmsg.success(toastText); }, /** * 复制到剪贴板 * @param {string} netDiskName * @param {number} netDiskIndex * @param {string} shareCode * @param {string} accessCode * @param {string} toastText 提示的文字 */ copyText( netDiskName, netDiskIndex, shareCode, accessCode, toastText = "已复制" ) { utils.setClip( NetDiskParse.getCopyUrlInfo( netDiskName, netDiskIndex, shareCode, accessCode ) ); Qmsg.success(toastText); }, /** * 新标签页打开 * @param {string} url * @param {string} netDiskName * @param {string} shareCode * @param {string} accessCode */ blank(url, netDiskName, shareCode, accessCode) { if (accessCode) { NetDiskParse.setClipboard(netDiskName, shareCode, accessCode); } log.success(["新标签页打开", [...arguments]]); document .querySelector("meta[name='referrer']") ?.setAttribute( "content", "no-referrer" ); /* 百度网盘会拒绝referrer不安全访问 */ window.open(url, "_blank"); }, /** * 将链接转为Scheme格式并打开 * @param {string} netDiskName 网盘名称 * @param {number} netDiskIndex 网盘名称索引下标 * @param {string} shareCode * @param {string} accessCode */ openScheme(netDiskName, netDiskIndex, shareCode, accessCode) { let url = NetDiskParse.getBlankUrl( netDiskName, netDiskIndex, shareCode, accessCode ); url = NetDiskFilterScheme.handleUrl( `${netDiskName}-scheme-enable`, `${netDiskName}-scheme-forward`, url ); window.open(url, "_blank"); }, /** * 获取重定向后的直链 * @param {string} url * @param {string} userAgent 用户代理字符串 * @returns {Promise} */ async getRedirectFinalUrl(url, userAgent) { if (!GM_getValue("getTheDirectLinkAfterRedirection", true)) { return url; } Qmsg.success("获取重定向后的直链"); log.info("开始获取重定向后的直链"); let headResp = await httpx.head({ url: url, headers: { "user-agent": userAgent, referer: window.location.origin, }, }); if (headResp.status) { return headResp.data.finalUrl; } else { return url; } }, /** * 获取用于跳转的url * @param {string} netDiskName * @param {number} netDiskIndex * @param {string|undefined} shareCode * @param {string|undefined} accessCode * @returns {string} */ getBlankUrl(netDiskName, netDiskIndex, shareCode, accessCode) { let blankUrl = NetDisk.regular[netDiskName][netDiskIndex]["blank"]; if (shareCode) { blankUrl = blankUrl.replaceAll("{#shareCode#}", shareCode); } if (accessCode && accessCode !== "") { blankUrl = blankUrl.replaceAll("{#accessCode#}", accessCode); } else { blankUrl = blankUrl.replace(/( |提取码:|{#accessCode#}|\?pwd=)/gi, ""); } return blankUrl; }, /** * 获取用于复制到剪贴板的网盘信息 * @param {string} netDiskName * @param {number} netDiskIndex * @param {string|undefined} shareCode * @param {string|undefined} accessCode * @returns {string} */ getCopyUrlInfo(netDiskName, netDiskIndex, shareCode, accessCode) { let copyUrl = NetDisk.regular[netDiskName][netDiskIndex]["copyUrl"]; if (shareCode) { copyUrl = copyUrl.replaceAll("{#shareCode#}", shareCode); } if (accessCode && accessCode !== "") { copyUrl = copyUrl.replaceAll("{#accessCode#}", accessCode); } else { copyUrl = copyUrl.replace("\n密码:{#accessCode#}", ""); } return copyUrl; }, /** * 在iframe内访问资源,但是可能页面存在同源策略,会导致iframe不生效 * @param {string} url */ iframeDownload(url = "") { let downloadIframe = document.createElement("iframe"); downloadIframe.onload = function () { downloadUrl.onload = null; downloadIframe.remove(); }; downloadIframe.src = url; downloadIframe.style.display = "none"; downloadIframe.style.height = "0"; document.body.appendChild(downloadIframe); }, }; /** * 网盘鉴权处理获取 */ const NetDiskAuthorization = { netDisk: { /** * 123网盘,一般用于>100MB的文件直链获取 */ _123pan: function () { if (window.location.hostname !== "www.123pan.com") { return; } /* 没在设置中开启直链获取就不获取鉴权信息 */ if (!GM_getValue("_123pan-static-enable")) { return; } let authorToken = unsafeWindow.localStorage.getItem("authorToken"); if (utils.isNull(authorToken)) { return; } /* 去除左右的引号 */ authorToken = authorToken.replace(/^\"/, "").replace(/\"$/, ""); log.success("获取123网盘已登录用户的authorToken值👇"); log.success(authorToken); GM_setValue("_123pan_User_Authorization", authorToken); }, }, default() { Object.keys(NetDiskAuthorization.netDisk).forEach((keyName) => { this.netDisk[keyName](); }); }, }; /** * android scheme调用 */ const NetDiskFilterScheme = { defaultScheme: "jumpwsv://go?package=idm.internet.download.manager.plus&activity=idm.internet.download.manager.UrlHandlerDownloader&intentAction=android.intent.action.VIEW&intentData={#intentData#}&intentExtra=", packageIDM: "idm.internet.download.manager.plus", activityIDM: "idm.internet.download.manager.UrlHandlerDownloader", defaultAction: "android.intent.action.VIEW", defaultExtra: "", /** * * @param {string} enable_key 是否启用key * @param {string} forward_key 转发的scheme * @param {string} url 需要转发的url * @returns {string} */ handleUrl(enable_key, forward_key, url) { if (!GM_getValue(enable_key, false)) { return url; } url = url.replace(/&/g, "{-and-}"); url = url.replace(/#/g, "{-number-}"); let thisScheme = GM_getValue(forward_key, this.defaultScheme); thisScheme = thisScheme.replace("{#intentData#}", url); return thisScheme; }, }; /** * 自动填入访问码 */ const NetDiskAutoFillAccessCode = { /** * 临时数据 { "shareCode": "", "accessCode": "", "netDiskName": "" } * @type {object|undefined} */ tempData: GM_getValue("tempNetDiskInfo"), /** * @type {boolean|undefined} 自动输入访问码是否开启 */ enable: GM_getValue("autoFillAccessCode"), shareCode: null, accessCode: null, netDiskName: null, /** * 入口 */ default() { if (!this.tempData) { return; } if (!this.enable) { return; } this.shareCode = this.tempData["shareCode"]; this.accessCode = this.tempData["accessCode"]; this.netDiskName = this.tempData["netDiskName"]; if (utils.isNull(this.accessCode)) { return; } /* 百度如果shareCode第一位是1的话,新版本会在href中去除这个1 */ if (this.netDiskName === "baidu" && this.shareCode.startsWith("1")) { if ( !window.location.href.includes( this.shareCode.slice(1, this.shareCode.length) ) ) { return; } } else if (!window.location.href.includes(this.shareCode)) { return; } if (this.netDiskName in NetDiskAutoFillAccessCode) { NetDiskAutoFillAccessCode[this.netDiskName](); } }, /** * 百度网盘 */ baidu() { if ( window.location.hostname === "pan.baidu.com" && window.location.pathname === "/share/init" && window.location.search.startsWith("?surl=") ) { log.success(["自动填写链接", this.tempData]); utils.waitNode("div.verify-form #accessCode").then((nodeList) => { if (!utils.isVisible(nodeList[0])) { log.error("输入框不可见,不输入密码"); return; } Qmsg.success("自动填入访问码"); nodeList[0].value = this.accessCode; utils.dispatchEvent(nodeList[0], "input"); document.querySelector("div.verify-form #submitBtn")?.click(); }); } }, /** * 蓝奏云 */ lanzou() { if (window.location.hostname.match(/lanzou[a-z]{1}.com/gi)) { log.success(["自动填写链接", this.tempData]); utils.waitNode("#pwd").then((nodeList) => { if (!utils.isVisible(nodeList[0])) { log.error("输入框不可见,不输入密码"); return; } Qmsg.success("自动填入访问码"); nodeList[0].value = this.accessCode; utils.dispatchEvent(nodeList[0], "input"); document .querySelector("#passwddiv > div > div.passwddiv-input > div") ?.click(); document.querySelector("#sub")?.click(); }); utils.waitNode("#f_pwd").then((nodeList) => { utils.mutationObserver(nodeList[0], { config: { attributes: true, attributeFilter: ["style"], }, callback: (mutations, observer) => { let inputElement = document.querySelector("#f_pwd #pwd"); if (!utils.isVisible(inputElement)) { log.error("输入框不可见,不输入密码"); return; } observer.disconnect(); log.success("自动填入访问码并关闭观察者"); Qmsg.success("自动填入访问码"); inputElement.value = this.accessCode; utils.dispatchEvent(inputElement, "input"); document.querySelector("#f_pwd #sub")?.click(); }, }); }); } }, /** * 天翼云 */ tianyiyun() { if (window.location.hostname === "cloud.189.cn") { /* 桌面端 */ log.success(["自动填写链接", this.tempData]); utils.waitNode("input#code_txt").then((nodeList) => { setTimeout(() => { let codeTxt = nodeList[0]; let visitBtn = document.querySelector(".btn.btn-primary.visit"); if (!utils.isVisible(codeTxt)) { log.error("输入框不可见,不输入密码"); return; } Qmsg.success("自动填入访问码"); codeTxt.value = this.accessCode; codeTxt._value = this.accessCode; utils.dispatchEvent(codeTxt, "input"); utils.dispatchEvent(visitBtn, "click"); }, 500); }); } if (window.location.hostname === "h5.cloud.189.cn") { /* 移动端 */ log.success(["自动填写链接", this.tempData]); utils.waitNode("input.access-code-input").then((nodeList) => { setTimeout(() => { let accessInput = nodeList[0]; if (!utils.isVisible(accessInput)) { log.error("输入框不可见,不输入密码"); return; } Qmsg.success("自动填入访问码"); accessInput.value = this.accessCode; accessInput._value = this.accessCode; utils.dispatchEvent(accessInput, "input"); utils.dispatchEvent(document.querySelector("div.button"), "click"); }, 500); }); } }, /** * 中国移动云盘 */ hecaiyun() { if (window.location.hostname === "caiyun.139.com") { /* 桌面端 */ log.success(["自动填写链接", this.tempData]); utils.waitNode("#token-input").then((nodeList) => { if (!utils.isVisible(nodeList[0])) { log.error("输入框不可见,不输入密码"); return; } Qmsg.success("自动填入访问码"); nodeList[0].value = this.accessCode; utils.dispatchEvent(nodeList[0], "input"); document .querySelector("#homepage div.token div.token-form a") .click(); }); /* 移动端 */ utils .waitNode("#app div.token-form input[type=text]") .then((nodeList) => { if (!utils.isVisible(nodeList[0])) { log.error("输入框不可见,不输入密码"); return; } Qmsg.success("自动填入访问码"); nodeList[0].value = this.accessCode; utils.dispatchEvent(nodeList[0], "input"); document.querySelector("div.token-form a.btn-token").click(); }); } }, /** * 阿里云盘 */ aliyun() { if (window.location.hostname === "www.aliyundrive.com") { /* 桌面端 */ log.success(["自动填写链接", this.tempData]); utils.waitNode("#root input.ant-input").then((nodeList) => { if (!utils.isVisible(nodeList[0])) { log.error("输入框不可见,不输入密码"); return; } Qmsg.success("自动填入访问码"); nodeList[0].value = this.accessCode; utils.getReactObj(nodeList[0]).reactFiber.memoizedProps.onChange({ currentTarget: nodeList[0], target: nodeList[0], }); document.querySelector('#root button[type="submit"]').click(); }); /* ------------------------------------ */ /* 移动端 */ utils.waitNode("#root input[name=pwd]").then((nodeList) => { if (!utils.isVisible(nodeList[0])) { log.error("输入框不可见,不输入密码"); return; } Qmsg.success("自动填入访问码"); nodeList[0].value = this.accessCode; utils.getReactObj(nodeList[0]).reactFiber.memoizedProps.onChange({ currentTarget: nodeList[0], target: nodeList[0], }); document.querySelector('#root button[type="submit"]').click(); }); } }, /** * 文叔叔 */ wenshushu() { /* 暂时没找到有密码的链接 */ }, /** * 奶牛 */ nainiu() { /* 暂时没找到有密码的链接 */ }, /** * 123云盘 */ _123pan() { if (window.location.hostname === "www.123pan.com") { /* 桌面端 */ log.success(["自动填写链接", this.tempData]); utils .waitNode("#app .ca-fot input.ant-input[type=text]") .then((nodeList) => { if (!utils.isVisible(nodeList[0])) { log.error("输入框不可见,不输入密码"); return; } Qmsg.success("自动填入访问码"); utils.getReactObj(nodeList[0]).reactProps.onChange({ target: { value: this.accessCode, }, }); nodeList[0].nextSibling.click(); }); /* ------------------------------------ */ /* 移动端 */ utils .waitNode("#app .appinput input.ant-input[type=text]") .then((nodeList) => { if (!utils.isVisible(nodeList[0])) { log.error("输入框不可见,不输入密码"); return; } Qmsg.success("自动填入访问码"); utils.getReactObj(nodeList[0]).reactProps.onChange({ target: { value: this.accessCode, }, }); nodeList[0].nextSibling.click(); }); } }, /** * 腾讯微云 */ weiyun() { if (window.location.hostname === "share.weiyun.com") { /* 桌面端 */ log.success(["自动填写链接", this.tempData]); utils.waitNode("#app input.input-txt").then((nodeList) => { if (!utils.isVisible(nodeList[0])) { log.error("输入框不可见,不输入密码"); return; } Qmsg.success("自动填入访问码"); nodeList[0].value = this.accessCode; utils.dispatchEvent(nodeList[0], "input"); utils.dispatchEvent(nodeList[0], "change"); setTimeout(() => { document.querySelector(".form-item button.btn-main").click(); }, 500); }); /* ------------------------------------ */ /* 移动端 */ utils.waitNode(".input-wrap input.pw-input").then((nodeList) => { if (!utils.isVisible(nodeList[0])) { log.error("输入框不可见,不输入密码"); return; } Qmsg.success("自动填入访问码"); nodeList[0].value = this.accessCode; utils.dispatchEvent(nodeList[0], "input"); utils.dispatchEvent(nodeList[0], "change"); setTimeout(() => { document.querySelector(".pw-btn-wrap button.btn").click(); }, 500); }); } }, /** * 云雷 */ xunlei() { if (window.location.hostname === "pan.xunlei.com") { /* 桌面端 */ log.success(["自动填写链接", this.tempData]); utils .waitNode("#__layout div.pass-input-wrap input.td-input__inner") .then((nodeList) => { if (!utils.isVisible(nodeList[0])) { log.error("输入框不可见,不输入密码"); return; } log.error("输入框不可见,不输入密码"); nodeList[0].value = this.accessCode; utils.dispatchEvent(nodeList[0], "input"); utils.dispatchEvent(nodeList[0], "change"); setTimeout(() => { document .querySelector("#__layout div.pass-input-wrap button.td-button") .click(); }, 500); }); /* ------------------------------------ */ /* 移动端 */ utils .waitNode("#__layout div.pass-wrapper input.td-input__inner") .then((nodeList) => { if (!utils.isVisible(nodeList[0])) { log.error("输入框不可见,不输入密码"); return; } log.error("输入框不可见,不输入密码"); nodeList[0].value = this.accessCode; utils.dispatchEvent(nodeList[0], "input"); utils.dispatchEvent(nodeList[0], "change"); setTimeout(() => { document .querySelector("#__layout div.pass-wrapper button.td-button") .click(); }, 500); }); } }, /** * 115网盘 */ _115pan() { if (window.location.hostname === "115.com") { log.success(["自动填写链接", this.tempData]); utils.waitNode("input.text").then((nodeList) => { if (!utils.isVisible(nodeList[0])) { log.error("输入框不可见,不输入密码"); return; } Qmsg.success("自动填入访问码"); nodeList[0].value = this.accessCode; utils.dispatchEvent(nodeList[0], "input"); document .querySelector("#js-share_code div.form-decode div.submit a") .click(); }); } }, /** * 城通网盘 */ chengtong() { if ( window.location.hostname === "url95.ctfile.com" || window.location.hostname === "pan.jc-box.com" || window.location.hostname === "download.jamcz.com" || window.location.hostname === "u062.com" || window.location.hostname === "down.jc-box.com" || window.location.hostname === "download.cx05.cc" || window.location.hostname === "089u.com" ) { log.success(["自动填写链接", this.tempData]); utils.waitNode("#passcode").then((nodeList) => { if (!utils.isVisible(nodeList[0])) { log.error("输入框不可见,不输入密码"); return; } Qmsg.success("自动填入访问码"); nodeList[0].value = this.accessCode; utils.dispatchEvent(nodeList[0], "input"); document .querySelector("#main-content .form-group button.btn[type=button]") .click(); }); } }, /** * 夸克网盘 */ kuake() { if (window.location.hostname === "pan.quark.cn") { log.success(["自动填写链接", this.tempData]); utils .waitNode("#ice-container input.ant-input[class*=ShareReceive]") .then((nodeList) => { if (!utils.isVisible(nodeList[0])) { log.error("输入框不可见,不输入密码"); return; } Qmsg.success("自动填入访问码"); ( utils.getReactObj(nodeList[0]).reactProps || utils.getReactObj(nodeList[0]).reactEventHandlers ).onChange({ target: { value: this.accessCode, }, }); }); } }, /** * 坚果云 */ jianguoyun() { /* 暂时没找到有密码的链接 */ }, /** * OneDrive */ onedrive() { /* 暂时没找到有密码的链接 */ }, }; const NetDiskWorker = { blobUrl: "", GM_matchWorker: null, /** * 初始化Worker的Blob链接 */ initWorkerBlobLink() { const handleMatch = ` (() => { this.addEventListener( "message", function (event) { let data = event.data; let link_regexp = data["regexp"]; let pageText = data["pageText"]; let netDiskName = data["netDiskName"]; let netDiskIndex = data["netDiskIndex"]; let matchData = pageText.match(link_regexp); matchData = matchData ? matchData : []; this.postMessage({ msg: matchData.length ? "workercallback: success! " + matchData.length.toString() : "workercallback: none", netDiskName: netDiskName, netDiskIndex: netDiskIndex, data: matchData, }); }, false ); })(); `; var blob = new Blob([handleMatch]); NetDiskWorker.blobUrl = window.URL.createObjectURL(blob); log.info(`Worker Blobk Link ===> ${NetDiskWorker.blobUrl}`); }, /** * 初始化Worker对象 */ initWorker() { try { NetDiskWorker.GM_matchWorker = new Worker(NetDiskWorker.blobUrl); NetDiskWorker.GM_matchWorker.onmessage = function (event) { NetDiskWorker.successCallBack( event.data["data"], event.data["netDiskName"], event.data["netDiskIndex"] ); }; NetDiskWorker.GM_matchWorker.onerror = function (error) { NetDiskWorker.errorCallBack(error); }; } catch (error) { log.error(error); log.error( "初始化Worker失败,可能页面使用了Content-Security-Policy策略,使用另类方法" ); this.GM_matchWorker = { postMessage(data) { try { let link_regexp = data["regexp"]; let pageText = data["pageText"]; let netDiskName = data["netDiskName"]; let netDiskIndex = data["netDiskIndex"]; let matchData = pageText.match(link_regexp); matchData = matchData ? matchData : []; NetDiskWorker.successCallBack( matchData, netDiskName, netDiskIndex ); } catch (error) { NetDiskWorker.errorCallBack(error); } }, }; } }, /** * worker处理文件匹配后的回调 * @param {string} matchLink * @param {string} netDiskName * @param {number} netDiskIndex */ successCallBack(matchLink, netDiskName, netDiskIndex) { /* 匹配为空,释放锁 */ if (!matchLink.length) { setTimeout(() => { NetDiskUI.isHandling = false; }, parseFloat(GM_getValue("delaytime", 0.8)) * 1000); return; } /* 已匹配到的网盘,用于显示图标 */ NetDisk.matchLink.add(netDiskName); /* 匹配到的可能很多,使用集合去重 */ let matchLinkSet = new Set(); matchLink.forEach((item) => { matchLinkSet.add(item); }); matchLinkSet.forEach((item) => { /* console.log("处理中"); */ NetDisk.handleLink(netDiskName, netDiskIndex, item); }); if (NetDisk.hasMatchLink) { NetDiskUI.suspension.show(); } setTimeout(() => { NetDiskUI.isHandling = false; }, parseFloat(GM_getValue("delaytime", 0.8)) * 1000); }, /** * Worker失败回调 * @param {object} error */ errorCallBack(error) { NetDiskUI.isHandling = false; log.error(["Worker Error", error]); }, }; const NetDiskUI = { matchIcon: new Set() /* 已匹配到的网盘图标字典 */, size: parseInt(GM_getValue("size", 50)) /* 高度和宽度 */, opacity: parseFloat(GM_getValue("opacity", 1)) /* 按钮透明度 */, isCreatedUISetting: false /* 是否 已创建设置界面 */, isHandling: false /* 是否 在处理页面链接中标识 */, isRandBg: false /* 是否 正在循环切换按钮背景 */, uiLinkAlias: null /* 链接层唯一标识 */, uiSettingAlias: null /* 设置层唯一标识 */, uiLinkParseAlias: "单文件直链层" /* 单文件直链层唯一标识 */, uiLinkParseMoreAlias: "多文件直链层" /* 多文件直链层唯一标识 */, uiPasswordAlias: "重输密码层" /* 重输密码层唯一标识 */, popsStyle: { /** * 桌面端 天翼云需要登录提示 */ tianyiyunNeedLoginTip_PC: { width: "30vw", height: "280px", }, /** * 移动端 天翼云需要登录提示 */ tianyiyunNeedLoginTip_Phone: { width: "80vw", height: "250px", }, /** * 桌面端 设置界面 */ setting_PC: { width: "50vw", height: "65vh", }, /** * 移动端 设置界面 */ setting_Phone: { width: "88vw", height: "60vh", }, /** * 桌面端 (主)网盘链接界面 */ netDiskView_PC: { width: "50vw", height: "65vh", }, /** * 移动端 (主)网盘链接界面 */ netDiskView_Phone: { width: "88vw", height: "50vh", }, /** * 桌面端 单文件弹窗 */ oneFileStaticView_PC: { width: "50vw", height: "240px", }, /** * 移动端 单文件弹窗 */ oneFileStaticView_Phone: { width: "88vw", height: "240px", }, /** * 桌面端 多文件弹窗 */ moreFileStaticView_PC: { width: "50vw", height: "400px", }, /** * 移动端 多文件弹窗 */ moreFileStaticView_Phone: { width: "88vw", height: "400px", }, /** * 桌面端 新密码、错误密码输入弹窗 */ newAccessCodeView_PC: { width: "50vw", height: "160px", }, /** * 移动端 新密码、错误密码输入弹窗 */ newAccessCodeView_Phone: { width: "88vw", height: "160px", }, /** * 桌面端 历史存储记录弹窗 */ netDiskHistoryMatchView_PC: { width: "50vw", height: "65vh", }, /** * 移动端 历史存储记录弹窗 */ netDiskHistoryMatchView_Phone: { width: "88vw", height: "60vh", }, }, src: { /* 图标 */ icon: { baidu: RESOURCE_ICON.baidu, lanzou: RESOURCE_ICON.lanzou, tianyiyun: RESOURCE_ICON.tianyiyun, hecaiyun: RESOURCE_ICON.hecaiyun, aliyun: RESOURCE_ICON.aliyun, wenshushu: RESOURCE_ICON.wenshushu, nainiu: RESOURCE_ICON.nainiu, _123pan: RESOURCE_ICON._123pan, weiyun: RESOURCE_ICON.weiyun, xunlei: RESOURCE_ICON.xunlei, _115pan: RESOURCE_ICON._115pan, chengtong: RESOURCE_ICON.chengtong, kuake: RESOURCE_ICON.kuake, magnet: RESOURCE_ICON.magnet, jianguoyun: RESOURCE_ICON.jianguoyun, onedrive: RESOURCE_ICON.onedrive, } /* icon结尾处 */, }, suspension: { /* 悬浮按钮 双击打开主界面,长按打开设置(不能移动,移动就不打开,只是移动按钮) */ isShow: false, show() { if (!NetDiskUI.suspension.isShow) { this.createUI(); this.initPop(); this.setSuspensionEvent(); this.setSuspensionDefaultPositionEvent(); NetDiskUI.suspension.isShow = true; } this.backgroundSwitch(); }, createUI() { if (NetDiskUI.size < 15) { /* 大小不能小于 15px */ GM_setValue("size", 15); NetDiskUI.size = 15; } if (NetDiskUI.size > 250) { /* 大小不能大于 250px */ GM_setValue("size", 250); NetDiskUI.size = 250; } if (NetDiskUI.opacity < 0.1) { /* 透明度不能小于 0.1 */ GM_setValue("opacity", 0.1); NetDiskUI.opacity = 0.1; } if (NetDiskUI.opacity > 1.0) { /* 透明度不能大于 1.0 */ GM_setValue("opacity", 1); NetDiskUI.opacity = 1; } this.loadCSS(); let suspensionNode = DOMUtils.createElement("div", { class: "whitesevSuspension", id: "whitesevSuspensionId", style: `width: ${NetDiskUI.size}px; height: ${NetDiskUI.size}px; opacity: ${NetDiskUI.opacity}`, innerHTML: `<div class="whitesevSuspensionMain"> <div class="whitesevSuspensionFloor"> <div class="netdisk"></div> </div> </div>`, }); document.body.appendChild(suspensionNode); }, /** * 所有的弹窗初始化设置 */ initPop() { Qmsg.config({ position: GM_getValue("qmsg-position", "top"), html: true, maxNums: parseInt(GM_getValue("qmsg-maxnums", 3)), autoClose: true, showClose: false, showReverse: GM_getValue("qmsg-showreverse", false), }); GM_addStyle(` .whitesevPop{ user-select: unset; } .whitesevPop .pops-alert-content{ padding: 15px; } .whitesevPop-whitesevPopSetting .whitesevPop-buttonSpcl{ display: none; } .whitesevPop-whitesevPopSetting .whitesevPop-content{ overflow: auto; } .whitesevPopSetting .netdisk-setting-main{ padding: 6px 20px 6px 20px; } .whitesevPopSetting details.netdisk-setting-menu { margin: 10px 0px; } .whitesevPopSetting details.netdisk-setting-menu summary{ background-color: #f0f0f0; color: #333; font-size: 18px; padding: 10px; border: 1px solid #ccc; } .whitesevPopSetting details.netdisk-setting-menu summary:hover{ background-color: #dedede; } .netdisk-setting-menu-item{ display:flex; justify-content: space-between; display: flex; align-items: center; } .netdisk-setting-menu-item label{ width:150px; padding-right: 15px; } .netdisk-setting-menu-item[type=checkbox]{ align-items: flex-start; } .netdisk-setting-menu-item[type=checkbox], .netdisk-setting-menu-item[type="scheme"]{ display: flex; height: 50px; } .netdisk-setting-menu-item[type=checkbox] p, .netdisk-setting-menu-item[type="scheme"] p{ align-self: center; width: 150px; } .netdisk-setting-menu-item input[type=text], .netdisk-setting-menu-item input[type=number], .netdisk-setting-menu-item input[type=range]{ border: none; border-bottom: 1px solid #8f8e8e; width: 60%; padding: 0px 2px; } .netdisk-setting-menu-item input[type=text]:focus, .netdisk-setting-menu-item input[type=number]:focus{ outline: none; border-bottom: 1px solid #2196f3; } .netdisk-setting-menu[type='百度'] .netdisk-setting-menu-item, .netdisk-setting-menu[type='总设置'] .netdisk-setting-menu-item{ margin: 12px 0px; } .netdisk-setting-menu[type='总设置'] .netdisk-setting-menu-item{ align-items: center; display: flex; justify-content: space-between; } .netdisk-setting-menu-item select{ background-color: #fff; } /*checkbox美化*/ /* CSS规则保持重复,以便您可以轻松获取每个按钮的CSS规则 :) */ .netdisk-checkbox .knobs, .netdisk-checkbox .layer{ position: absolute; top: 0; right: 0; bottom: 0; left: 0; } .netdisk-checkbox{ position: relative; top: 50%; width: 56px; height: 28px; margin: 0px auto 0 auto; overflow: hidden; transform: translateY(-50%); } .netdisk-checkbox input[type="checkbox"]{ position: relative; width: 100%; height: 100%; padding: 0; margin: 0; opacity: 0; cursor: pointer; z-index: 3; } .netdisk-checkbox .knobs{ z-index: 2; } .netdisk-checkbox .layer{ width: 100%; background-color: #fcebeb; transition: 0.3s ease all; z-index: 1; } .netdisk-checkbox .knobs:before, .netdisk-checkbox .knobs span{ position: relative; display: block; top: 50%; left: 30%; width: 35%; height: 65%; color: #fff; font-size: 10px; font-weight: bold; text-align: center; line-height: 1; padding: 9px 4px; transform: translate(-50%,-50%); } .netdisk-checkbox .knobs span{ background-color: #F44336; border-radius: 2px; transition: 0.3s ease all, left 0.3s cubic-bezier(0.18, 0.89, 0.35, 1.15); z-index: 1; } .netdisk-checkbox .knobs:before{ transition: 0.3s ease all, left 0.5s cubic-bezier(0.18, 0.89, 0.35, 1.15); z-index: 2; } .netdisk-checkbox input[type="checkbox"]:checked + .knobs span{ left: 70%; background-color: #03A9F4; } .netdisk-checkbox input[type="checkbox"]:checked ~ .layer{ background-color: #ebf7fc; } /*range美化*/ .netdisk-setting-menu-item input[type=range] { background-size: 98% 3px; background: linear-gradient(to right, #ccc 0%, #ccc 100%); outline: none; -webkit-appearance: none; /*清除系统默认样式*/ height: 1px; /*横条的高度*/ } .netdisk-setting-menu-item input[type=range]::-webkit-slider-thumb { width: 15px; height: 15px; border-radius: 50%; background-color: #fff; box-shadow: 0 0 2px rgba(0, 0, 0, 0.3), 0 3px 5px rgba(0, 0, 0, 0.2); cursor: pointer; -webkit-appearance: none; border: 0; } /* select美化 无法美化option*/ .netdisk-setting-menu-item select{ height: 32px; line-height: 32px; font-size: 14px; width: 200px; border: 1px solid #5c5c5c; border-radius: 5px; text-align: center; outline: 0; } .netdisk-setting-menu-item select:focus{ border: 1px solid #002bff; } /* select美化*/ `); /* 给PC端的滚动条进行美化 */ if (!pops.isPhone()) { GM_addStyle(` .whitesevPop ::-webkit-scrollbar { width: 11px; height: 16px; background-color: #ffffff; } /*定义滚动条轨道 内阴影+圆角*/ .whitesevPop ::-webkit-scrollbar-track { -webkit-box-shadow: inset 0 0 6px rgb(0 0 0 / 25%); border-radius:10px; background-color: #f2f2f2; } /*定义滑块 内阴影+圆角*/ .whitesevPop ::-webkit-scrollbar-thumb { border-radius: 16px; -webkit-box-shadow:inset 0 0 6px rgba(0,0,0,.3); background-color: #3597ff; } `); } }, /** * 显示设置界面 */ showSettingView() { /** * 获取设置界面的html * @returns {string} */ function getPopsSettingHTML() { let netDiskSettingHTML = ""; let netDiskDetailsList = [ { type: "百度网盘", key: "baidu", checkbox_oneStatic: false, checkbox_oneOrMoreStatic: false, checkbox_openBlank: true, checkbox_static_scheme: false, text_static_scheme_forward: false, range_innerText: true, range_innerText_default_value: 20, range_innerHTML: true, range_innerHTML_default_value: 300, firstHTML: ` <div class="netdisk-setting-menu-item"> <label>网址-Url</label> <input type="text" data-key="bdurl" placeholder="如:https://www.example.com/"> </div> <div class="netdisk-setting-menu-item"> <label>参数-Key</label> <input type="text" data-key="paramSurl" placeholder="如:surl"> </div> <div class="netdisk-setting-menu-item"> <label>密码-Key</label> <input type="text" data-key="paramPwd" placeholder="如:pwd"> </div> <div class="netdisk-setting-menu-item"> <label>密钥-Key</label> <input type="text" data-key="paramKey" placeholder="如:Password"> </div> <div class="netdisk-setting-menu-item"> <label>密钥-Value</label> <input type="text" data-key="paramWebSiteKey" placeholder="密钥,有就填"> </div> <div class="netdisk-setting-menu-item" type="checkbox"> <p>第三方解析站启用密钥验证</p> <div class="netdisk-checkbox"> <input type="checkbox" data-key="baidu-website-key-enable"> <div class="knobs"><span></span></div><div class="layer"></div> </div> </div> <div class="netdisk-setting-menu-item" type="checkbox"> <p>启用第三方解析</p> <div class="netdisk-checkbox"> <input type="checkbox" data-key="baidu-static-enable" mutex=".netdisk-checkbox input[data-key='baidu-open-enable']"> <div class="knobs"><span></span></div><div class="layer"></div> </div> </div>`, endHTML: "", }, { type: "蓝奏云", key: "lanzou", checkbox_oneStatic: false, checkbox_oneOrMoreStatic: true, checkbox_openBlank: true, checkbox_static_scheme: true, text_static_scheme_forward: true, range_innerText: true, range_innerText_default_value: 20, range_innerHTML: true, range_innerHTML_default_value: 300, firstHTML: "", endHTML: "", }, { type: "天翼云", key: "tianyiyun", checkbox_oneStatic: true, checkbox_oneOrMoreStatic: false, checkbox_openBlank: true, checkbox_static_scheme: true, text_static_scheme_forward: true, range_innerText: true, range_innerText_default_value: 20, range_innerHTML: true, range_innerHTML_default_value: 300, firstHTML: "", endHTML: "", }, { type: "中国移动云盘(原:和彩云)", key: "hecaiyun", checkbox_oneStatic: false, checkbox_oneOrMoreStatic: false, checkbox_openBlank: true, checkbox_static_scheme: false, text_static_scheme_forward: false, range_innerText: true, range_innerText_default_value: 20, range_innerHTML: true, range_innerHTML_default_value: 300, firstHTML: "", endHTML: "", }, { type: "阿里云", key: "aliyun", checkbox_oneStatic: false, checkbox_oneOrMoreStatic: false, checkbox_openBlank: true, checkbox_static_scheme: false, text_static_scheme_forward: false, range_innerText: true, range_innerText_default_value: 20, range_innerHTML: true, range_innerHTML_default_value: 300, firstHTML: "", endHTML: "", }, { type: "文叔叔", key: "wenshushu", checkbox_oneStatic: true, checkbox_oneOrMoreStatic: false, checkbox_openBlank: true, checkbox_static_scheme: true, text_static_scheme_forward: true, range_innerText: true, range_innerText_default_value: 20, range_innerHTML: true, range_innerHTML_default_value: 300, firstHTML: "", endHTML: "", }, { type: "奶牛", key: "nainiu", checkbox_oneStatic: true, checkbox_oneOrMoreStatic: false, checkbox_openBlank: true, checkbox_static_scheme: true, text_static_scheme_forward: true, range_innerText: true, range_innerText_default_value: 20, range_innerHTML: true, range_innerHTML_default_value: 300, firstHTML: "", endHTML: "", }, { type: "123盘", key: "_123pan", checkbox_oneStatic: false, checkbox_oneOrMoreStatic: true, checkbox_openBlank: true, checkbox_static_scheme: true, text_static_scheme_forward: true, range_innerText: true, range_innerText_default_value: 20, range_innerHTML: true, range_innerHTML_default_value: 300, firstHTML: "", endHTML: "", }, { type: "微云", key: "weiyun", checkbox_oneStatic: false, checkbox_oneOrMoreStatic: false, checkbox_openBlank: true, checkbox_static_scheme: false, text_static_scheme_forward: false, range_innerText: true, range_innerText_default_value: 20, range_innerHTML: true, range_innerHTML_default_value: 300, firstHTML: "", endHTML: "", }, { type: "迅雷云盘", key: "xunlei", checkbox_oneStatic: false, checkbox_oneOrMoreStatic: false, checkbox_openBlank: true, checkbox_static_scheme: false, text_static_scheme_forward: false, range_innerText: true, range_innerText_default_value: 20, range_innerHTML: true, range_innerHTML_default_value: 300, firstHTML: "", endHTML: "", }, { type: "115盘", key: "_115pan", checkbox_oneStatic: false, checkbox_oneOrMoreStatic: false, checkbox_openBlank: true, checkbox_static_scheme: false, text_static_scheme_forward: false, range_innerText: true, range_innerText_default_value: 20, range_innerHTML: true, range_innerHTML_default_value: 300, firstHTML: "", endHTML: "", }, { type: "城通网盘", key: "chengtong", checkbox_oneStatic: false, checkbox_oneOrMoreStatic: false, checkbox_openBlank: true, checkbox_static_scheme: false, text_static_scheme_forward: false, range_innerText: true, range_innerText_default_value: 20, range_innerHTML: true, range_innerHTML_default_value: 300, firstHTML: "", endHTML: "", }, { type: "夸克网盘", key: "kuake", checkbox_oneStatic: false, checkbox_oneOrMoreStatic: false, checkbox_openBlank: true, checkbox_static_scheme: false, text_static_scheme_forward: false, range_innerText: true, range_innerText_default_value: 20, range_innerHTML: true, range_innerHTML_default_value: 300, firstHTML: "", endHTML: "", }, { type: "BT磁力", key: "magnet", checkbox_oneStatic: false, checkbox_oneOrMoreStatic: false, checkbox_openBlank: true, checkbox_static_scheme: false, text_static_scheme_forward: false, range_innerText: false, range_innerText_default_value: 0, range_innerHTML: false, range_innerHTML_default_value: 0, firstHTML: "", endHTML: ` <div class="netdisk-setting-menu-item" type="checkbox"> <p>Scheme转发</p> <div class="netdisk-checkbox"> <input type="checkbox" data-key="magnet-scheme-enable"> <div class="knobs"><span></span></div><div class="layer"></div> </div> </div> <div class="netdisk-setting-menu-item" type="scheme"> <p>Scheme链接</p> <input type="text" data-key="magnet-scheme-forward" placeholder="如: jumpwsv://go?package=xx&activity=xx&intentAction=xx&intentData=xx&intentExtra=xx"> </div> `, }, { type: "坚果云", key: "jianguoyun", checkbox_oneStatic: true, checkbox_oneOrMoreStatic: false, checkbox_openBlank: true, checkbox_static_scheme: true, text_static_scheme_forward: true, range_innerText: true, range_innerText_default_value: 20, range_innerHTML: true, range_innerHTML_default_value: 300, firstHTML: "", endHTML: "", }, { type: "OneDrive", key: "onedrive", checkbox_oneStatic: false, checkbox_oneOrMoreStatic: false, checkbox_openBlank: true, checkbox_static_scheme: false, text_static_scheme_forward: false, range_innerText: true, range_innerText_default_value: 20, range_innerHTML: true, range_innerHTML_default_value: 300, firstHTML: "", endHTML: "", }, ]; netDiskDetailsList.forEach((item) => { netDiskSettingHTML += ` <details class="netdisk-setting-menu" type="${item.type}"> <summary>${item.type}</summary> ${item.firstHTML} ${ item.checkbox_oneStatic ? ` <div class="netdisk-setting-menu-item" type="checkbox"> <p>单文件直链获取</p> <div class="netdisk-checkbox"> <input type="checkbox" data-key="${item.key}-static-enable" mutex=".netdisk-checkbox input[data-key='${item.key}-open-enable']"> <div class="knobs"><span></span></div><div class="layer"></div> </div> </div> ` : "" } ${ item.checkbox_oneOrMoreStatic ? ` <div class="netdisk-setting-menu-item" type="checkbox"> <p>单/多文件直链获取</p> <div class="netdisk-checkbox"> <input type="checkbox" data-key="${item.key}-static-enable" mutex=".netdisk-checkbox input[data-key='${item.key}-open-enable']"> <div class="knobs"><span></span></div><div class="layer"></div> </div> </div> ` : "" } ${ item.checkbox_openBlank ? ` <div class="netdisk-setting-menu-item" type="checkbox"> <p>新标签页打开</p> <div class="netdisk-checkbox"> <input type="checkbox" data-key="${item.key}-open-enable" mutex=".netdisk-checkbox input[data-key='${item.key}-static-enable']"> <div class="knobs"><span></span></div> <div class="layer"></div> </div> </div> ` : "" } ${ item.checkbox_static_scheme ? ` <div class="netdisk-setting-menu-item" type="checkbox"> <p>Scheme转发直链</p> <div class="netdisk-checkbox"> <input type="checkbox" data-key="${item.key}-static-scheme-enable"> <div class="knobs"><span></span></div><div class="layer"></div> </div> </div> ` : "" } ${ item.text_static_scheme_forward ? ` <div class="netdisk-setting-menu-item" type="scheme"> <p>Scheme链接</p> <input type="text" data-key="${item.key}-static-scheme-forward" placeholder="如: jumpwsv://go?package=xx&activity=xx&intentAction=xx&intentData=xx&intentExtra=xx"> </div> ` : "" } ${ item.range_innerText ? ` <div class="netdisk-setting-menu-item"> <label data-id="netdisk-innerText_${ item.key }">提取码间隔(Text)${GM_getValue( `innerText_${item.key}`, parseInt(item.range_innerText_default_value) )}</label> <input type="range" data-key="innerText_${item.key}" data-content="提取码间隔(Text)" min="0" max="100" data-default="20"> </div> ` : "" } ${ item.range_innerHTML ? ` <div class="netdisk-setting-menu-item"> <label data-id="netdisk-innerHTML_${ item.key }">提取码间隔(HTML)${GM_getValue( `innerHTML_${item.key}`, parseInt(item.range_innerHTML_default_value) )}</label> <input type="range" data-key="innerHTML_${item.key}" data-content="提取码间隔(HTML)" min="0" max="500" data-default="300"> </div> ` : "" } ${item.endHTML} </details> `; }); netDiskSettingHTML = ` <div class="netdisk-setting-body"> <div class="netdisk-setting"> <div class="netdisk-setting-main"> <details class="netdisk-setting-menu" type="总设置"> <summary>总设置</summary> <div class="netdisk-setting-menu-item"> <label data-id="netdisk-size">大小 ${GM_getValue( "size", 50 )}</label> <input type="range" data-key="size" data-content="大小 " min="15" max="250" data-default="50"> </div> <div class="netdisk-setting-menu-item"> <label data-id="netdisk-opacity" content="透明度 ">透明度 ${GM_getValue( "opacity", 1 )}</label> <input type="range" data-key="opacity" data-content="透明度 " min="0.1" max="1" step="0.1" data-default="1"> </div> <div class="netdisk-setting-menu-item"> <label data-id="netdisk-randbg-time" content="按钮背景切换时间(毫秒) ">按钮背景切换时间(毫秒) ${GM_getValue( "randbg-time", 1500 )}</label> <input type="range" data-key="randbg-time" data-content="按钮背景切换时间(毫秒) " min="0" max="10000" step="100" data-default="1500"> </div> <div class="netdisk-setting-menu-item"> <label data-id="netdisk-randbg-show-time" content="按钮背景停留时间(毫秒) ">按钮背景停留时间(毫秒) ${GM_getValue( "randbg-show-time", 1200 )}</label> <input type="range" data-key="randbg-show-time" data-content="按钮背景停留时间(毫秒) " min="0" max="10000" step="100" data-default="1200"> </div> <div class="netdisk-setting-menu-item"> <label data-id="netdisk-delaytime">文本延迟match(秒) ${GM_getValue( "delaytime", 0.8 )}</label> <input type="range" data-key="delaytime" data-content="文本延迟match(秒) " min="0.6" step="0.1" max="5.0" data-default="0.8"> </div> <div class="netdisk-setting-menu-item"> <label>匹配类型</label> <select data-key="pageMatchRange" data-default="all"> <option data-value="all">全部</option> <option data-value="innerText">普通文本</option> <option data-value="innerHTML">超文本</option> </select> </div> <div class="netdisk-setting-menu-item"> <label>弹窗动画</label> <select data-key="popsAnimation" data-default="pops-anim-fadein-zoom"> <option data-value="pops-anim-spread">spread</option> <option data-value="pops-anim-shake">shake</option> <option data-value="pops-anim-rolling-left">rolling-left</option> <option data-value="pops-anim-rolling-right">rolling-right</option> <option data-value="pops-anim-slide-top">slide-top</option> <option data-value="pops-anim-slide-bottom">slide-bottom</option> <option data-value="pops-anim-slide-left">slide-left</option> <option data-value="pops-anim-slide-right">slide-right</option> <option data-value="pops-anim-fadein">fadein</option> <option data-value="pops-anim-fadein-zoom">fadein-zoom</option> <option data-value="pops-anim-fadein-alert">fadein-alert</option> <option data-value="pops-anim-don">don</option> <option data-value="pops-anim-roll">roll</option> <option data-value="pops-anim-sandra">sandra</option> <option data-value="pops-anim-gather">gather</option> </select> </div> <div class="netdisk-setting-menu-item"> <label>Toast位置</label> <select data-key="qmsg-position" data-default="top"> <option data-value="topleft">左上角</option> <option data-value="top">顶部</option> <option data-value="topright">右上角</option> <option data-value="left">左边</option> <option data-value="center">中间</option> <option data-value="right">右边</option> <option data-value="bottomleft">左下角</option> <option data-value="bottom">底部</option> <option data-value="bottomright">右下角</option> </select> </div> <div class="netdisk-setting-menu-item"> <label>Toast同时显示最多数量</label> <select data-key="qmsg-maxnums" data-default="3"> <option data-value="1">1</option> <option data-value="2">2</option> <option data-value="3">3</option> <option data-value="4">4</option> <option data-value="5">5</option> </select> </div> <div class="netdisk-setting-menu-item"> <label>历史记录排序规则</label> <select data-key="netdisk-history-match-ordering-rule" data-default="按 更新时间 - 降序"> <option data-value="按 记录时间 - 升序">按 记录时间 - 升序</option> <option data-value="按 记录时间 - 降序">按 记录时间 - 降序</option> <option data-value="按 更新时间 - 升序">按 更新时间 - 升序</option> <option data-value="按 更新时间 - 降序">按 更新时间 - 降序</option> </select> </div> <div class="netdisk-setting-menu-item" type="checkbox"> <p>Toast逆序弹出</p> <div class="netdisk-checkbox" style="position: inherit;top: unset;transform: matrix(1, 0, 0, 1, 0, 0);"> <input type="checkbox" data-key="qmsg-showreverse"> <div class="knobs"><span></span></div><div class="layer"></div> </div> </div> <div class="netdisk-setting-menu-item" type="checkbox"> <p>读取剪贴板</p> <div class="netdisk-checkbox" style="position: inherit;top: unset;transform: matrix(1, 0, 0, 1, 0, 0);"> <input type="checkbox" data-key="readClipboard"> <div class="knobs"><span></span></div><div class="layer"></div> </div> </div> <div class="netdisk-setting-menu-item" type="checkbox"> <p>PC端拖拽窗口</p> <div class="netdisk-checkbox" style="position: inherit;top: unset;transform: matrix(1, 0, 0, 1, 0, 0);"> <input type="checkbox" data-key="pcDrag"> <div class="knobs"><span></span></div><div class="layer"></div> </div> </div> <div class="netdisk-setting-menu-item" type="checkbox"> <p>存储匹配记录</p> <div class="netdisk-checkbox" style="position: inherit;top: unset;transform: matrix(1, 0, 0, 1, 0, 0);"> <input type="checkbox" data-key="saveMatchNetDisk"> <div class="knobs"><span></span></div><div class="layer"></div> </div> </div> <div class="netdisk-setting-menu-item" type="checkbox"> <p>自动输入访问码</p> <div class="netdisk-checkbox" style="position: inherit;top: unset;transform: matrix(1, 0, 0, 1, 0, 0);"> <input type="checkbox" data-key="autoFillAccessCode"> <div class="knobs"><span></span></div><div class="layer"></div> </div> </div> <div class="netdisk-setting-menu-item" type="checkbox"> <p>获取重定向后的直链</p> <div class="netdisk-checkbox" style="position: inherit;top: unset;transform: matrix(1, 0, 0, 1, 0, 0);"> <input type="checkbox" data-key="getTheDirectLinkAfterRedirection" data-default="true"> <div class="knobs"><span></span></div><div class="layer"></div> </div> </div> </details> ${netDiskSettingHTML} </div> </div> </div>`; return netDiskSettingHTML; } /** * 设置input checkbox 复选框 是否选中事件 */ function setSettingInputEvent() { document .querySelectorAll(".netdisk-setting input") .forEach((item) => { let data_key = item.getAttribute("data-key"); let data_default = item.getAttribute("data-default"); switch (item.getAttribute("type")) { case "checkbox": let defaultChecked = false; if ( typeof data_default === "string" && data_default === "true" ) { defaultChecked = true; } item.checked = GM_getValue(data_key, defaultChecked); let mutex = item.getAttribute("mutex"); item.addEventListener("click", function () { GM_setValue(data_key, item.checked); let mutexNode = document.querySelector(mutex); if (mutexNode) { /* 存在互斥的元素DOM,且当前checked为true,把互斥的DOM元素Checked设置为false */ let mutex_data_key = mutexNode.getAttribute("data-key"); if (item.checked) { mutexNode.checked = false; GM_setValue(mutex_data_key, false); } } }); break; case "range": item.value = GM_getValue(data_key, data_default) ? GM_getValue(data_key, data_default) : ""; DOMUtils.on(item, "input propertychange", function () { document.querySelector( `.netdisk-setting label[data-id=netdisk-${data_key}]` ).innerHTML = `${item.getAttribute("data-content")}${ item.value }`; let itSize = document.querySelector( ".netdisk-setting input[data-key=size]" ).value; let whitesevSuspensionIdElement = document.querySelector( "#whitesevSuspensionId" ); whitesevSuspensionIdElement.style.setProperty( "width", `${itSize}px` ); whitesevSuspensionIdElement.style.setProperty( "height", `${itSize}px` ); whitesevSuspensionIdElement.style.setProperty( "opacity", document.querySelector( ".netdisk-setting input[data-key=opacity]" ).value ); NetDiskUI.size = itSize; NetDiskUI.suspension.setSuspensionDefaultPositionEvent(); GM_setValue(data_key, item.value); }); default: item.value = GM_getValue(data_key, data_default) ? GM_getValue(data_key, data_default) : ""; DOMUtils.on(item, "input propertychange", function () { GM_setValue(data_key, item.value); }); } }); } /** * 设置 select元素 下拉列表的默认选项值 */ function setSettingSelectEvent() { document .querySelectorAll(".netdisk-setting select") .forEach((item) => { DOMUtils.on(item, "change", function (event) { let data_key = event.target.getAttribute("data-key"); let data_value = event.target[event.target.selectedIndex].getAttribute( "data-value" ); GM_setValue(data_key, data_value); }); }); document .querySelectorAll(".netdisk-setting-menu-item select") .forEach((item) => { let dataKey = item.getAttribute("data-key"); let dataDefaultValue = item.getAttribute("data-default"); let getDataValue = GM_getValue(dataKey); if (getDataValue == null && dataDefaultValue != null) { /* 存储中不存在该值,设置默认值 */ log.success( `存储中不存在该值,设置默认值 key::${dataKey} value:${dataDefaultValue}` ); GM_setValue(dataKey, dataDefaultValue); getDataValue = GM_getValue(dataKey); } item .querySelector(`option[data-value='${getDataValue}']`) .setAttribute("selected", true); }); } /** * 设置 点击 label 弹出设置input range的默认值 事件 */ function setSettingLabelEvent() { NetDiskUI.uiSettingAlias.popsElement .querySelectorAll("label[data-id*=netdisk-]") .forEach((item) => { item.style.setProperty("cursor", "pointer"); DOMUtils.on(item, "click", function (event) { let obj = event.target; let nextObj = DOMUtils.next(obj); let dataKey = nextObj.getAttribute("data-key"); let dataDefaultValue = nextObj.getAttribute("data-default"); let currentValue = nextObj.value; pops.confirm({ mask: true, title: { text: "提示", position: "center", }, content: { text: `当前设置的值为:${currentValue},是否修改为默认值:${dataDefaultValue} ?`, }, btn: { ok: { callback: function (_event_) { log.info( `当前 ==> ${currentValue},默认值 ==> ${dataDefaultValue}` ); GM_setValue(dataKey, dataDefaultValue); DOMUtils.val(nextObj, dataDefaultValue); DOMUtils.trigger(nextObj, "propertychange"); _event_.close(); }, }, }, forbiddenScroll: true, }); }); }); } NetDiskUI.uiSettingAlias = pops.alert({ title: { text: "设置", position: "center", }, content: { text: getPopsSettingHTML(), html: true, }, btn: { ok: { enable: true, callback: function (event) { event.close(); }, }, close: { callback: function (event) { event.close(); }, }, }, animation: GM_getValue("popsAnimation", "pops-anim-fadein-zoom"), class: "whitesevPopSetting", height: pops.isPhone() ? NetDiskUI.popsStyle.setting_Phone.height : NetDiskUI.popsStyle.setting_PC.height, width: pops.isPhone() ? NetDiskUI.popsStyle.setting_Phone.width : NetDiskUI.popsStyle.setting_PC.width, drag: GM_getValue("pcDrag", false), mask: true, forbiddenScroll: true, }); setSettingInputEvent(); setSettingSelectEvent(); setSettingLabelEvent(); }, /** * 设置 悬浮按钮所有事件 */ setSuspensionEvent() { let needDragEle = document.querySelector("#whitesevSuspensionId"); let that = this; let dragNode = new AnyTouch(needDragEle); let timerID = null; let isClicked = false; let isDouble = false; /* 是否双击 */ let clickDeviation_X = 0; /* 点击元素,距离元素左上角的X轴偏移 */ let clickDeviation_Y = 0; /* 点击元素,距离元素左上角的Y轴偏移 */ /** * 设置悬浮按钮 按下事件 */ dragNode.on("pan", function (event) { if (!isClicked) { isClicked = true; if (event.nativeEvent.offsetX) { clickDeviation_X = parseInt(event.nativeEvent.offsetX); } else { clickDeviation_X = parseInt(event.getOffset().x); } if (event.nativeEvent.offsetY) { clickDeviation_Y = parseInt(event.nativeEvent.offsetY); } else { clickDeviation_Y = parseInt(event.getOffset().y); } DOMUtils.css(needDragEle, { cursor: "move", transition: "none", }); } /** * 移动 */ if (event.phase === "move") { /* 悬浮按钮大小不能超过250px */ if (clickDeviation_X > 250 || clickDeviation_Y > 250) { return; } var clientMax_X = DOMUtils.width(globalThis) - NetDiskUI.size; /* 最大的X轴 指从左至右*/ var clientMax_Y = DOMUtils.height(globalThis) - NetDiskUI.size; /* 最大的Y轴 指从上至下 */ var clientMove_X = event.x - clickDeviation_X; /* 当前移动的X轴 */ var clientMove_Y = event.y - clickDeviation_Y; /* 当前移动的Y轴 */ clientMove_X = clientMove_X < clientMax_X ? clientMove_X : clientMax_X; /* 不允许超过最大X轴 */ clientMove_Y = clientMove_Y < clientMax_Y ? clientMove_Y : clientMax_Y; /* 不允许超过最大Y轴 */ clientMove_X = clientMove_X < 0 ? 0 : clientMove_X; /* 不允许小于0 */ clientMove_Y = clientMove_Y < 0 ? 0 : clientMove_Y; /* 不允许小于0 */ if (top.window == self.window) { GM_setValue("suspensionX", clientMove_X); GM_setValue("suspensionY", clientMove_Y); } DOMUtils.css(needDragEle, { left: clientMove_X + "px", top: clientMove_Y + "px", }); } /** * 停止移动 */ if (event.phase === "end") { isClicked = false; DOMUtils.css(needDragEle, { cursor: "auto", }); let left_px = parseInt( DOMUtils.css(needDragEle, "left").replace("px", "") ); let setCSSLeft = 0; if (left_px >= DOMUtils.width(globalThis) / 2) { setCSSLeft = DOMUtils.width(globalThis) - NetDiskUI.size; if (top.window == self.window) { GM_setValue("isRight", true); } } else { if (top.window == self.window) { GM_setValue("isRight", false); } } if (top.window == self.window) { GM_setValue("suspensionX", setCSSLeft); } DOMUtils.css(needDragEle, { left: setCSSLeft + "px", transition: "left 300ms ease 0s", }); } }); /** * 设置悬浮按钮 点击/按下事件 */ dragNode.on(["click", "tap"], function (event) { if (isDouble) { /* 判定为双击 */ clearTimeout(timerID); that.showSettingView(); isDouble = false; } else { isDouble = true; timerID = setTimeout(function () { isDouble = false; NetDiskUI.view.show(); }, 200); } }); DOMUtils.on(needDragEle, "contextmenu", function (event) { NetDiskUI.view.showContextMenu(event, undefined, [ { text: "设置", callback: function () { log.info("打开设置界面"); NetDiskUI.suspension.showSettingView(); }, }, { text: "历史匹配记录", callback: function () { log.info("打开历史匹配记录界面"); NetDiskUI.netDiskHistoryMatch.show(); }, }, ]); }); }, /** * 设置悬浮按钮位置 */ setSuspensionDefaultPositionEvent() { let clientMax_X = DOMUtils.width(globalThis) - NetDiskUI.size; /* 最大的X轴 指从左至右*/ let clientMax_Y = DOMUtils.height(globalThis) - NetDiskUI.size; /* 最大的Y轴 指从上至下 */ let clientDefault_X = clientMax_X; /* 默认值 X轴 */ let clientDefault_Y = DOMUtils.height(globalThis) / 2 - NetDiskUI.size; /* 默认值 Y轴 */ let userSetClient_X = GM_getValue("suspensionX", clientDefault_X); /* 用户自己移动的X轴 */ let userSetClient_Y = GM_getValue( "suspensionY", clientDefault_Y ); /* 用户自己移动的Y轴 */ /* 如果存在isRight 悬浮按钮放到最右边,否则最左边 */ if (GM_getValue("isRight")) { userSetClient_X = clientMax_X; } else { userSetClient_X = 0; } /* 如果超出最大的Y轴,以Y轴为默认值 */ if (userSetClient_Y > clientMax_Y) { userSetClient_Y = clientMax_Y; } else if (userSetClient_Y < 0) { /* 如果用户设置的Y轴小于0,那设置0 */ userSetClient_Y = 0; } if (top.window == self.window) { /* 不在iframe内修改 */ GM_setValue("suspensionX", userSetClient_X); GM_setValue("suspensionY", userSetClient_Y); } DOMUtils.css("#whitesevSuspensionId", { left: userSetClient_X + "px", top: userSetClient_Y + "px", }); }, loadCSS() { GM_addStyle(` .whitesevSuspension{ top: 0; position:fixed; right:10px; border-radius: 12px; z-index:4000; } .whitesevSuspension .whitesevSuspensionMain{ background:#fff; border:1px solid #f2f2f2; box-shadow:0 0 15px #e4e4e4; box-sizing:border-box; border-radius: inherit; height: inherit; width: inherit; } .whitesevSuspension .whitesevSuspensionFloor{ border-bottom:1px solid #f2f2f2; position:relative; box-sizing:border-box; border-radius: inherit; height: inherit; width: inherit; } .whitesevSuspension .whitesevSuspensionFloor .netdisk{ background-position:center center; background-size:115% 115%; background-repeat:no-repeat; display:flex; align-items:center; justify-content:center; border-radius: inherit; height: inherit; width: inherit; } .whitesevSuspension .whitesevSuspensionFloor .netdisk:hover{ transition:all 300ms linear; background-color:#e4e4e4; transform:scale(1.1); } .whitesevPop-content p[pop]{ height: 100%; } `); }, /** * 悬浮按钮背景轮播 效果为淡入淡出 * @returns */ backgroundSwitch() { if (this.isRandBg) { return; } /** * 获取随机背景的数组 * @returns {Array} */ function getRandBgList() { let resultList = []; NetDiskUI.matchIcon.forEach((item) => { resultList = [...resultList, NetDiskUI.src.icon[item]]; }); return resultList; } /** * 进行切换 淡入淡出 * @param {number} fadeTime 淡入\淡出的时间 * @param {string} currentBackgroundSrc 当前的背景资源 */ function startSwitch(fadeTime, currentBackgroundSrc) { currentList = getRandBgList(); DOMUtils.fadeOut(randBgNode, fadeTime, function () { currentIndex++; currentIndex = currentIndex < currentList.length ? currentIndex : 0; currentBackgroundSrc = currentList[currentIndex]; DOMUtils.css( randBgNode, "background-image", `url(${currentBackgroundSrc})` ); DOMUtils.fadeIn(randBgNode, fadeTime, function () { setTimeout(() => { startSwitch( parseInt(GM_getValue("randbg-time", switchBgTime)), currentBackgroundSrc ); }, parseInt(GM_getValue("randbg-show-time", switchBgShowTime))); }); }); } let currentList = []; let currentIndex = 0; let switchBgTime = 1500; /* 淡入或淡出的持续时间 */ let switchBgShowTime = 1200; /* 淡入或淡出后的延迟切换时间 */ currentList = getRandBgList(); let randBgSrc = currentList[currentIndex]; let randBgNode = document.querySelector(".whitesevSuspension .netdisk"); DOMUtils.css(randBgNode, "background-image", `url(${randBgSrc})`); if ( currentList.length < 2 || GM_getValue("randbg-time", switchBgTime) <= 0 ) { /* 只有一个的话或淡入/淡出的时间<=0 就不进行背景切换 */ return; } this.isRandBg = true; startSwitch( parseInt(GM_getValue("randbg-time", switchBgTime)), randBgSrc ); }, }, /** * 视图 */ view: { show() { if (!NetDiskUI.uiLinkAlias) { this.addCSS(); this.createView(); this.registerIconGotoPagePosition(); this.registerNetDiskUrlContextMenu(); } else { NetDiskUI.uiLinkAlias.show(); } }, addCSS() { GM_addStyle(` .netdisk-url-box-all{ } .netdisk-url-box{ } .netdisk-url-box:last-child { padding: 0 0 10px 0; } .netdisk-url-div{ display: flex; align-items: center; width: 100%; margin: 10px 0px; } .netdisk-icon{ margin: 0px 4px; display: contents; } .netdisk-icon img{ width: 28px; height: 28px; font-size: 13px !important; } .netdisk-icon img, .netdisk-url a{ border-radius: 10px; box-shadow: 0 0.3px 0.6px rgb(0 0 0 / 6%), 0 0.7px 1.3px rgb(0 0 0 / 8%), 0 1.3px 2.5px rgb(0 0 0 / 10%), 0 2.2px 4.5px rgb(0 0 0 / 12%), 0 4.2px 8.4px rgb(0 0 0 / 14%), 0 10px 20px rgb(0 0 0 / 20%); } .whitesevPop .netdisk-url{ padding: 5px 0px; margin: 0px 10px; } .netdisk-url a{ color: #ff4848 !important; min-height: 28px; overflow-x: hidden; overflow-y: auto; font-size: 14px; border: none; display: flex; align-items: center; width: 100%; height: 100%; padding: 2px 10px; word-break: break-word; } .whitesevPop-whitesevPopSetting *:focus-visible { outline-offset: 0px; outline:0px; } .netdisk-url a[isvisited=true]{ color: #8b8888 !important; } .netdisk-url a:active{ box-shadow: 0 0 0 1px #616161 inset; } .netdisk-url a:focus-visible{ outline: none; } .whitesevPop-content p[pop]{ text-indent: 0px; } .whitesevPop-button[type="primary"] { border-color: #2d8cf0; background-color: #2d8cf0; } `); }, /** * 创建视图 */ createView() { let viewAddHTML = ""; NetDiskUI.matchIcon.forEach((netDiskName) => { let netDisk = NetDisk.linkDict.get(netDiskName); Object.keys(netDisk.getItems()).forEach((shareCode) => { let accessCodeDict = netDisk.getItems()[shareCode]; let uiLink = NetDisk.handleLinkShow( netDiskName, accessCodeDict["netDiskIndex"], shareCode, accessCodeDict["accessCode"] ); viewAddHTML = viewAddHTML + this.getViewHTML( NetDiskUI.src.icon[netDiskName], netDiskName, accessCodeDict["netDiskIndex"], shareCode, accessCodeDict["accessCode"], uiLink ); }); }); let viewHTML = ` <div class="netdisk-url-box-all"> ${viewAddHTML} </div>`; NetDiskUI.uiLinkAlias = pops.alert({ title: { text: "网盘", position: "center", }, content: { text: viewHTML, html: true, }, btn: { ok: { callback: function (event) { event.hide(); }, }, close: { callback: function (event) { event.hide(); }, }, }, class: "whitesevPop", animation: GM_getValue("popsAnimation", "pops-anim-fadein-zoom"), height: pops.isPhone() ? NetDiskUI.popsStyle.netDiskView_Phone.height : NetDiskUI.popsStyle.netDiskView_PC.height, width: pops.isPhone() ? NetDiskUI.popsStyle.netDiskView_Phone.width : NetDiskUI.popsStyle.netDiskView_PC.width, drag: GM_getValue("pcDrag", false), mask: true, forbiddenScroll: true, }); this.setNetDiskUrlClickEvent(".netdisk-url a"); }, /** * 获取视图html * @param {string} netDiskImgSrc 网盘图标src * @param {string} netDiskName 网盘名称 * @param {number} netDiskIndex 网盘名称索引下标 * @param {string} shareCode * @param {string} accessCode * @param {string} uiLinkText 显示出来的链接文本 * @returns {string} */ getViewHTML( netDiskImgSrc, netDiskName, netDiskIndex, shareCode, accessCode, uiLinkText ) { return ` <div class="netdisk-url-box"> <div class="netdisk-url-div"> <div class="netdisk-icon"> <img src="${netDiskImgSrc}" data-netdisk="${netDiskName}"> </div> <div class="netdisk-url"> <a href="javascript:;" isvisited="false" data-netdisk="${netDiskName}" data-netdisk-index="${netDiskIndex}" data-sharecode="${shareCode}" data-accesscode="${accessCode}" data-open-enable-key="${netDiskName}-open-enable" data-static-enable-key="${netDiskName}-static-enable" data-scheme-enable-key="${netDiskName}-scheme-enable">${uiLinkText}</a> </div> </div> </div>`; }, /** * 设置网盘链接点击事件,要求,它是<a>元素且存在以下属性 * isvisited string true|false * data-netdisk string * data-netdisk-index number * data-sharecode string * data-accesscode string * data-open-enable-key string * data-static-enable-key string * data-scheme-enable-key string * @param {string} clickNodeSelector - 元素选择器 */ setNetDiskUrlClickEvent(clickNodeSelector) { function clickEvent(event) { event.target.setAttribute("isvisited", "true"); let netDiskName = event.target.getAttribute("data-netdisk"); let netDiskIndex = parseInt( event.target.getAttribute("data-netdisk-index") ); let shareCode = event.target.getAttribute("data-sharecode"); let accessCode = event.target.getAttribute("data-accesscode"); let openEnable = GM_getValue( event.target.getAttribute("data-open-enable-key"), false ); let staticEnable = GM_getValue( event.target.getAttribute("data-static-enable-key"), false ); let schemeEnable = GM_getValue( event.target.getAttribute("data-scheme-enable-key"), false ); if (openEnable) { let url = NetDisk.regular[netDiskName][netDiskIndex].blank .replace(/{#shareCode#}/gi, shareCode) .replace(/{#accessCode#}/gi, accessCode); NetDiskParse.blank(url, netDiskName, shareCode, accessCode); } else if (staticEnable) { NetDiskParse.parse( netDiskName, netDiskIndex, shareCode, accessCode ); } else if (schemeEnable) { NetDiskParse.openScheme( netDiskName, netDiskIndex, shareCode, accessCode ); } else { NetDiskParse.copyText( netDiskName, netDiskIndex, shareCode, accessCode ); } } DOMUtils.on(document.body, "click", clickNodeSelector, clickEvent); }, /** * 显示右键菜单,调用方式 * @param {Event} event * @param {string} menuNodeId 右键菜单元素的id * @param {Array} showTextList 右键菜单的内容,如:[{"text":"","callback":()=>{}}] */ showContextMenu( event, menuNodeId = "whitesevSuspensionContextMenu", showTextList = [] ) { event.preventDefault(); DOMUtils.remove(`#${menuNodeId}`); let menuNode = DOMUtils.createElement("div", { id: menuNodeId, innerHTML: ` <style type="text/css"> #${menuNodeId}{ position: fixed; z-index: ${utils.getMaxZIndex()}; text-align: center; padding: 3px 0px; border-radius: 3px; font-size: 16px; font-weight: 500; background: #fff; box-shadow: 0px 1px 6px 1px #cacaca; } #${menuNodeId} li:hover{ background: #dfdfdf; cursor: pointer; } #${menuNodeId} ul{ margin: 0px; padding: 0px; display: flex; flex-direction: column; align-items: flex-start; justify-content: center; } #${menuNodeId} ul li{ padding: 5px 10px; display: unset; width: -webkit-fill-available; text-align: left; margin: 2.5px 5px; border-radius: 3px; } </style> <ul></ul> `, }); showTextList.forEach((item) => { let menuItem = DOMUtils.createElement("li", { innerHTML: item.text, }); DOMUtils.on(menuItem, "click", function () { item.callback && typeof item.callback === "function" && item.callback.apply(this, this.arguments); menuNode.remove(); }); DOMUtils.append(menuNode.querySelector("ul"), menuItem); }); DOMUtils.hide(menuNode); DOMUtils.append(document.body, menuNode); let view = menuNode.ownerDocument.defaultView; if (!view || !view.opener) { view = window; } let clientMax_X = DOMUtils.width(globalThis) - DOMUtils.width(menuNode) - 1; /* 最大的X轴 指从左至右*/ let clientMax_Y = DOMUtils.height(globalThis) - DOMUtils.height(menuNode) - 8; /* 最大的Y轴 指从上至下 */ let clientMove_X = event.clientX; let clientMove_Y = event.clientY; /* 不允许超出浏览器范围 */ clientMove_X = clientMove_X < 0 ? 0 : clientMove_X; clientMove_X = clientMove_X < clientMax_X ? clientMove_X : clientMax_X; clientMove_Y = clientMove_Y < 0 ? 0 : clientMove_Y; clientMove_Y = clientMove_Y < clientMax_Y ? clientMove_Y : clientMax_Y; DOMUtils.css(menuNode, { left: clientMove_X, top: clientMove_Y, }); DOMUtils.show(menuNode); let globalClickListen = function () { if (!utils.checkUserClickInNode(menuNode)) { menuNode?.remove(); DOMUtils.off(window, "click", globalClickListen); } }; DOMUtils.on(window, "click", globalClickListen); }, /** * 添加新的链接 * @param {string} netDiskName 网盘名称 * @param {number} netDiskIndex 网盘名称索引下标 * @param {string} shareCode * @param {string} accessCode */ addLinkView(netDiskName, netDiskIndex, shareCode, accessCode) { NetDiskUI.netDiskHistoryMatch.setNetDiskHistoryMatchData( netDiskName, netDiskIndex, shareCode, accessCode ); if (!NetDiskUI.uiLinkAlias) { return; } log.info([netDiskName, netDiskIndex, shareCode, accessCode]); let icon = NetDiskUI.src.icon[netDiskName]; let uiLink = NetDisk.handleLinkShow( netDiskName, netDiskIndex, shareCode, accessCode ); let insertDOM = this.getViewHTML( icon, netDiskName, netDiskIndex, shareCode, accessCode, uiLink ); DOMUtils.append( NetDiskUI.uiLinkAlias.popsElement.querySelector( ".netdisk-url-box-all" ), insertDOM ); }, /** * 修改已存在的view * @param {string} netDiskName 网盘名称 * @param {number} netDiskIndex 网盘名称索引下标 * @param {string} shareCode * @param {string} accessCode */ changeLinkView(netDiskName, netDiskIndex, shareCode, accessCode) { NetDiskUI.netDiskHistoryMatch.setNetDiskHistoryMatchData( netDiskName, netDiskIndex, shareCode, accessCode ); if (!NetDiskUI.uiLinkAlias) { return; } let uiLink = NetDisk.handleLinkShow( netDiskName, netDiskIndex, shareCode, accessCode ); let needChangeDOM = NetDiskUI.uiLinkAlias.popsElement.querySelector( `.netdisk-url a[data-sharecode='${shareCode}'][data-netdisk-index='${netDiskIndex}']` ); log.info("修改网盘链接视图"); log.info(needChangeDOM); needChangeDOM.setAttribute("data-accesscode", accessCode); DOMUtils.html(needChangeDOM, uiLink); }, /** * 设置点击图标按钮导航至该网盘链接所在网页中位置 */ registerIconGotoPagePosition() { DOMUtils.on( document, "click", ".whitesevPop .netdisk-icon img", function (event) { let dataSharecode = event.target.parentElement.nextElementSibling.firstElementChild.getAttribute( "data-sharecode" ); utils.findVisibleText(dataSharecode, true); } ); }, /** * 设置全局监听url的右击菜单事件 */ registerNetDiskUrlContextMenu() { DOMUtils.on( document, "contextmenu", ".whitesevPop .netdisk-url a", function (event) { NetDiskUI.view.showContextMenu(event, undefined, [ { text: "复制链接", callback: function () { let netDiskName = event.target.getAttribute("data-netdisk"); let netDiskIndex = event.target.getAttribute("data-netdisk-index"); let shareCode = event.target.getAttribute("data-sharecode"); let accessCode = event.target.getAttribute("data-accesscode"); NetDiskParse.copyText( netDiskName, netDiskIndex, shareCode, accessCode ); }, }, { text: "访问链接", callback: function () { let netDiskName = event.target.getAttribute("data-netdisk"); let netDiskIndex = event.target.getAttribute("data-netdisk-index"); let shareCode = event.target.getAttribute("data-sharecode"); let accessCode = event.target.getAttribute("data-accesscode"); let url = NetDisk.regular[netDiskName][netDiskIndex].blank .replace(/{#shareCode#}/gi, shareCode) .replace(/{#accessCode#}/gi, accessCode); NetDiskParse.blank(url, netDiskName, shareCode, accessCode); }, }, { text: "修改访问码", callback: function () { let netDiskName = event.target.getAttribute("data-netdisk"); let netDiskIndex = event.target.getAttribute("data-netdisk-index"); let shareCode = event.target.getAttribute("data-sharecode"); let accessCode = event.target.getAttribute("data-accesscode"); NetDiskUI.newAccessCodeView( "修改访问码", netDiskName, netDiskIndex, shareCode, (userInputAccessCode) => { event.target.setAttribute( "data-accesscode", userInputAccessCode ); Qmsg.success( `修改 ${accessCode} => ${userInputAccessCode}` ); } ); }, }, ]); } ); }, }, /** * 显示直链的弹窗 */ staticView: { isLoadCSS: false, addCSS() { if (!this.isLoadCSS) { this.isLoadCSS = true; GM_addStyle(` .netdisk-static-body{ flex-wrap: wrap; letter-spacing: 1px; text-decoration: none; width: 100%; padding: 5px 16px; text-align: left; } .netdisk-static-filename{ } .netdisk-static-filename a{ color: #233df8 !important; } .netdisk-static-body .netdisk-static-filename:before{ content: "文件: "; font-weight: bold; text-overflow: ellipsis; display: contents; position: inherit; } .netdisk-static-body .netdisk-static-filesize:before{ content: "大小: "; font-weight: bold; display: contents; position: inherit; } .netdisk-static-body .netdisk-static-fileuploadtime:before{ content: "时间: "; font-weight: bold; display: contents; position: inherit; } .netdisk-static-body .netdisk-static-filelatesttime:before{ content: "最新: "; font-weight: bold; display: contents; position: inherit; } `); } }, /** * 单文件直链弹窗 * @param {{ * title:string, * fileName:string, * fileType:?string, * fileSize:?string, * downloadUrl:string, * fileUploadTime:?string, * fileLatestTime:?string * clickCallBack: ?(_fileDetails_:{ * title:string, * fileName:string, * fileType:?string, * fileSize:?string, * downloadUrl:string, * fileUploadTime:?string, * fileLatestTime:?string, * })=>{} * }} fileDetails 配置 */ oneFile(fileDetails) { this.addCSS(); log.success(["成功获取单文件直链", fileDetails]); Qmsg.success("成功获取单文件直链"); let title = fileDetails["title"]; let fileName = fileDetails["fileName"]; let fileType = fileDetails["fileType"]; let fileSize = fileDetails["fileSize"]; let downloadUrl = fileDetails["downloadUrl"]; let fileUploadTime = fileDetails["fileUploadTime"]; let fileLatestTime = fileDetails["fileLatestTime"]; let clickCallBack = fileDetails["clickCallBack"]; fileUploadTime = fileUploadTime === "" ? null : fileUploadTime; fileLatestTime = fileLatestTime === "" ? null : fileLatestTime; if (fileType && !fileName.endsWith("." + fileType)) { fileName = fileName + "." + fileType; fileDetails["fileName"] = fileName; } let confirmElement = pops.confirm({ title: { text: title, position: "center", }, content: { text: ` <div class="netdisk-static-body"> <div class="netdisk-static-filename"> <a target="_blank" href="${downloadUrl}">${fileName}</a> </div> ${ fileSize ? `<div class="netdisk-static-filesize">${fileSize}</div>` : "" } ${ fileUploadTime ? `<div class="netdisk-static-fileuploadtime">${fileUploadTime}</div>` : "" } ${ fileLatestTime ? `<div class="netdisk-static-filelatesttime">${fileLatestTime}</div>` : "" } </div>`, html: true, }, btn: { reverse: true, position: "end", ok: { text: "下载", callback: (event) => { if (typeof clickCallBack === "function") { clickCallBack(fileDetails); } else { let downloadUrl = event.popsElement .querySelector(".netdisk-static-filename a") .getAttribute("href"); window.open(downloadUrl, "_blank"); } }, }, }, class: "whitesevPopOneFile", animation: GM_getValue("popsAnimation", "pops-anim-fadein-zoom"), height: pops.isPhone() ? NetDiskUI.popsStyle.oneFileStaticView_Phone.height : NetDiskUI.popsStyle.oneFileStaticView_PC.height, width: pops.isPhone() ? NetDiskUI.popsStyle.oneFileStaticView_Phone.width : NetDiskUI.popsStyle.oneFileStaticView_PC.width, mask: true, drag: GM_getValue("pcDrag", false), forbiddenScroll: true, }); if (clickCallBack) { let linkElement = confirmElement.element.querySelector( "div.netdisk-static-filename a" ); linkElement.setAttribute("href", "javascript:;"); linkElement.removeAttribute("target"); DOMUtils.on(linkElement, "click", function () { clickCallBack( fileName, fileType, fileSize, downloadUrl, fileUploadTime, fileLatestTime ); }); } }, /** * 多文件直链弹窗 * @param {string} title 标题 * @param {Array} [downloadInfoList=[]] 弹窗内容HTML或Text * @param {?Function} clickCallBack 超链接的点击事件 */ moreFile(title, downloadInfoList = [], clickCallBack) { this.addCSS(); Qmsg.success("成功获取多文件直链"); let showHTML = ""; log.success(["多文件直链信息", downloadInfoList]); downloadInfoList.forEach((info) => { /* 该链接是否是成功的 */ let success = info["success"]; /* 文件名 */ let fileName = info["fileName"]; /* 文件大小 */ let fileSize = info["fileSize"]; /* 文件链接 */ let downloadUrl = info["downloadUrl"]?.trim(); /* 文件上传时间 */ let fileUploadTime = info["fileUploadTime"]; /* 文件最新时间 */ let fileLatestTime = info["fileLatestTime"]; if (success) { showHTML += ` <div class="netdisk-static-body"> <div class="netdisk-static-filename"> <a target="${ downloadUrl === "javascript:;" ? "" : "_blank" }" href="${downloadUrl}" data-download='${JSON.stringify( info )}'>${fileName}</a> </div> ${ fileSize ? `<div class="netdisk-static-filesize">${fileSize}</div>` : "" } ${ fileUploadTime ? `<div class="netdisk-static-fileuploadtime">${fileUploadTime}</div>` : "" } ${ fileLatestTime ? `<div class="netdisk-static-filelatesttime">${fileLatestTime}</div>` : "" } </div> `; } else { showHTML += ` <div class="netdisk-static-body"> <div class="netdisk-static-filename"> <a href="javascript:;">${fileName}</a> </div> ${ fileSize ? `<div class="netdisk-static-filesize">${fileSize}</div>` : "" } </div>`; } }); let alertElement = pops.alert({ title: { text: title, position: "center", }, content: { text: showHTML, html: true, }, btn: { ok: { text: "关闭", }, }, class: "whitesevPopMoreFile", mask: true, animation: GM_getValue("popsAnimation", "pops-anim-fadein-zoom"), height: pops.isPhone() ? NetDiskUI.popsStyle.moreFileStaticView_Phone.height : NetDiskUI.popsStyle.moreFileStaticView_PC.height, width: pops.isPhone() ? NetDiskUI.popsStyle.moreFileStaticView_Phone.width : NetDiskUI.popsStyle.moreFileStaticView_PC.width, drag: GM_getValue("pcDrag", false), forbiddenScroll: true, }); if (clickCallBack) { log.success("设置当前直链弹窗超链接自定义点击事件"); alertElement.element .querySelectorAll("div.netdisk-static-filename a") .forEach((item) => { item.setAttribute("href", "javascript:;"); item.removeAttribute("target"); }); DOMUtils.on(alertElement.element, "click", "a", function (event) { /* 该链接是否是成功的 */ let dataDownload = utils.toJSON( event.target.getAttribute("data-download") ); clickCallBack(event, dataDownload); }); } }, }, /** * 需要重新输入新密码的弹窗 * @param {string} title 标题 * @param {string} netDiskName 网盘名称 * @param {number} netDiskIndex 网盘名称索引下标 * @param {string} shareCode * @param {Function} okCallBack */ newAccessCodeView( title = "密码错误", netDiskName = "", netDiskIndex, shareCode, okCallBack = () => {} ) { pops.prompt({ title: { text: title, }, btn: { reverse: true, position: "end", cancel: { text: "取消", }, ok: { callback: (event) => { /* 把输入的新密码去空格 */ let userInputAccessCode = event.text.replace(/[\s]*/gi, ""); /* 处理已显示的链接 */ let uiLink = NetDisk.handleLinkShow( netDiskName, netDiskIndex, shareCode, userInputAccessCode ); let currentItemSelector = `.netdisk-url a[data-netdisk=${netDiskName}][data-sharecode=${shareCode}]`; let currentHistoryItemSelector = `.netdiskrecord-link a[data-netdisk=${netDiskName}][data-sharecode=${shareCode}]`; let currentItemElement = document.querySelector(currentItemSelector); let currentHistoryItemElement = document.querySelector( currentHistoryItemSelector ); if (currentItemElement) { currentItemElement.setAttribute( "data-accesscode", userInputAccessCode ); DOMUtils.html(currentItemElement, uiLink); } /* 历史记录的弹出的 */ if (currentHistoryItemElement) { currentHistoryItemElement.setAttribute( "data-accesscode", userInputAccessCode ); DOMUtils.html(currentHistoryItemElement, uiLink); } log.info(`${netDiskName} 重新输入的密码:${userInputAccessCode}`); okCallBack(userInputAccessCode); event.close(); }, }, }, content: { placeholder: "请重新输入密码", focus: true, }, height: pops.isPhone() ? NetDiskUI.popsStyle.newAccessCodeView_Phone.height : NetDiskUI.popsStyle.newAccessCodeView_PC.height, width: pops.isPhone() ? NetDiskUI.popsStyle.newAccessCodeView_Phone.width : NetDiskUI.popsStyle.newAccessCodeView_PC.width, mask: true, animation: GM_getValue("popsAnimation", "pops-anim-fadein-zoom"), drag: GM_getValue("pcDrag", false), forbiddenScroll: true, }); /** * 注册键盘回车事件 */ utils.listenKeyPress( document.querySelector(".pops-prompt-content input"), (keyName, otherKey) => { if (keyName === "Enter") { document.querySelector(".pops-prompt-btn-ok")?.click(); } } ); }, /** * 网盘历史匹配到的记录弹窗 */ netDiskHistoryMatch: { storageKey: "netDiskHistoryMatch" /* 本地存储的keyName */, isAddCss: false /* 是否已添加CSS */, isSetSearchEvent: false /* 是否已设置DOM事件 */, isSetOtherEvent: false /* 是否已设置其它DOM事件 */, show() { this.addCSS(); let data = this.getNetDiskHistoryMatchData(); let dataHTML = ""; let that = this; data = this.orderNetDiskHistoryMatchData(data); for (let index = 0; index < 10; index++) { if (data[index]) { dataHTML += that.getTableHTML(data[index]); } } dataHTML = ` <div class="netdiskrecord-search"> <input type="text" placeholder="搜索链接/网址/网址标题,可正则搜索"> </div> <div class="netdiskrecord-table"><ul>${dataHTML}</ul></div> <div class="netdiskrecord-page"> </div>`; pops.confirm({ title: { text: "历史匹配记录", position: "center", }, content: { text: dataHTML, html: true, }, btn: { reverse: true, position: "space-between", ok: { enable: true, callback: function (event) { event.close(); }, }, close: { callback: function (event) { event.close(); }, }, cancel: { enable: false, }, other: { enable: true, text: `清空所有(${data.length})`, type: "xiaomi-primary", callback: (event) => { pops.confirm({ title: { text: "删除", position: "center", }, content: { text: "确定清空所有的记录?", html: false, }, btn: { ok: { enable: true, callback: function (okEvent) { that.clearNetDiskHistoryMatchData(); DOMUtils.remove( ".whitesevPopNetDiskHistoryMatch .pops-confirm-content ul li" ); okEvent.close(); DOMUtils.html( ".whitesevPopNetDiskHistoryMatch .netdiskrecord-page", "" ); DOMUtils.text( ".whitesevPopNetDiskHistoryMatch .pops-confirm-btn-other", DOMUtils.text( document.querySelector( ".whitesevPopNetDiskHistoryMatch .pops-confirm-btn-other" ) ).replace(/[\d]+/gi, "0") ); }, }, cancel: { enable: true, }, }, mask: true, }); }, }, }, class: "whitesevPopNetDiskHistoryMatch", animation: GM_getValue("popsAnimation", "pops-anim-fadein-zoom"), height: pops.isPhone() ? NetDiskUI.popsStyle.netDiskHistoryMatchView_Phone.height : NetDiskUI.popsStyle.netDiskHistoryMatchView_PC.height, width: pops.isPhone() ? NetDiskUI.popsStyle.netDiskHistoryMatchView_Phone.width : NetDiskUI.popsStyle.netDiskHistoryMatchView_PC.height, mask: true, drag: GM_getValue("pcDrag", false), forbiddenScroll: true, }); this.setDataPaging(data); this.setEvent(); this.setSearchEvent(); this.setContextMenuEvent(); }, addCSS() { if (this.isAddCss) { return; } this.isAddCss = true; GM_addStyle(` .whitesevPopNetDiskHistoryMatch .pops-confirm-content ul{ } .whitesevPopNetDiskHistoryMatch .pops-confirm-content li{ display: flex; flex-direction: column; justify-content: center; border-radius: 10px; box-shadow: 0 0.3px 0.6px rgb(0 0 0 / 6%), 0 0.7px 1.3px rgb(0 0 0 / 8%), 0 1.3px 2.5px rgb(0 0 0 / 10%), 0 2.2px 4.5px rgb(0 0 0 / 12%), 0 4.2px 8.4px rgb(0 0 0 / 14%), 0 10px 20px rgb(0 0 0 / 20%); margin: 20px 10px; padding: 10px; } .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-search{ height: 11%; } .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-table{ height: calc( 85% - 40px); overflow: auto; } .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-page{ display: flex; justify-content: center; align-items: center; margin-top: 10px; } .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-search input{ border: none; border-bottom: 1px solid #000000; padding: 0px 5px; line-height: 28px; font-size: 16px; width: -webkit-fill-available; margin: 5px 5px 0px 5px; } .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-search input:focus-visible{ outline: none; border-bottom: 1px solid #0009ff; } .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-link{ } .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-link a{ color: #ff4848; font-size: 14px; border: none; word-break: break-word; } .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-link a[isvisited=true]{ color: #8b8888; } .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-icon{ } .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-icon img{ width: 28px; height: 28px; font-size: 13px; border-radius: 10px; box-shadow: 0 0.3px 0.6px rgb(0 0 0 / 6%), 0 0.7px 1.3px rgb(0 0 0 / 8%), 0 1.3px 2.5px rgb(0 0 0 / 10%), 0 2.2px 4.5px rgb(0 0 0 / 12%), 0 4.2px 8.4px rgb(0 0 0 / 14%), 0 10px 20px rgb(0 0 0 / 20%); } .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-url{ color: #000; } .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-top-url{ color: #000; } .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-functions button.btn-delete{ background: #263cf3; color: #fff; } .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-functions button.btn-delete:active{ background: #6e7be8; } .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-link, .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-icon, .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-url, .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-top-url, .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-add-time, .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-update-time, .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-url-title, .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-functions{ display: flex; margin: 5px 0px; } .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-link p, .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-icon p, .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-url p, .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-top-url p, .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-add-time p, .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-update-time p, .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-url-title p, .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-functions p{ min-width: 80px; max-width: 80px; align-self: center; } `); }, /** * 获取显示出的每一项的html * @param {object} item * @param {number} index item的索引 * @returns */ getTableHTML(item) { let netDiskURL = NetDisk.handleLinkShow( item.netDiskName, item.netDiskIndex, item.shareCode, item.accessCode ); return ` <li> <div class="netdiskrecord-link"> <p>链接</p> <a href="javascript:;" isvisited="false" data-netdisk="${item.netDiskName}" data-netdisk-index="${item.netDiskIndex}" data-sharecode="${item.shareCode}" data-accesscode="${item.accessCode}" data-open-enable-key="${item.netDiskName}-open-enable" data-static-enable-key="${item.netDiskName}-static-enable" data-scheme-enable-key="${ item.netDiskName }-scheme-enable">${netDiskURL}</a> </div> <div class="netdiskrecord-icon"> <p>网盘</p> <img src="${NetDiskUI.src.icon[item.netDiskName]}"> </div> ${ item.url === item.topURL ? ` <div class="netdiskrecord-url"> <p>网址</p> <a href="${item.url}" target="_blank">${item.url}</a> </div> ` : ` <div class="netdiskrecord-url"> <p>网址</p> <a href="${item.url}" target="_blank">${item.url}</a> </div> <div class="netdiskrecord-top-url"> <p>TOP网址</p> <a href="${item.topURL}" target="_blank">${item.topURL}</a> </div> ` } <div class="netdiskrecord-url-title"> <p>网址标题</p> ${item.title} </div> <div class="netdiskrecord-add-time"> <p>记录时间</p> ${utils.formatTime(item.addTime)} </div> <div class="netdiskrecord-update-time"> <p>更新时间</p> ${utils.formatTime(item.updateTime)} </div> <div class="netdiskrecord-functions"> <p>功能</p> <button class="btn-delete" data-json='${JSON.stringify( item )}'>删除</button> </div> </li>`; }, /** * 设置只执行一次的事件 * @returns */ setEvent() { if (this.isSetSearchEvent) { return; } let that = this; this.isSetEvent = true; NetDiskUI.view.setNetDiskUrlClickEvent( ".whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-link a" ); /** * 设置删除按钮点击事件 */ let setdeleteBtnEvent = function () { DOMUtils.on( document, "click", ".whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-functions button.btn-delete", function (event) { /* 删除中的遮罩层 */ let deleteLoading = pops.loading({ parent: document.querySelector( ".whitesevPopNetDiskHistoryMatch .pops-confirm-content ul" ), content: { text: "删除中...", }, only: true, }); let clickNode = event.target; let dataJSON = clickNode.getAttribute("data-json"); clickNode.closest("li")?.remove(); that.deleteNetDiskHistoryMatchData(dataJSON); deleteLoading?.close(); let totalNumberText = DOMUtils.text( document.querySelector( ".whitesevPopNetDiskHistoryMatch .pops-confirm-btn-other" ) ); let totalNumber = totalNumberText.match(/[\d]+/gi); totalNumber = parseInt(totalNumber[totalNumber.length - 1]); totalNumber--; totalNumberText = totalNumberText.replace(/[\d]+/gi, totalNumber); DOMUtils.text( document.querySelector( ".whitesevPopNetDiskHistoryMatch .pops-confirm-btn-other" ), totalNumberText ); } ); }; setdeleteBtnEvent(); }, /** * 设置分页 * @param {Array} data */ setDataPaging(data) { let that = this; let dataPaging = new DataPaging({ data: data, pageCount: 10, pageStep: pops.isPhone() ? 2 : 4, currentPage: 1, pageChangeCallBack: function (page) { let startIndex = (page - 1) * 10; let dataHTML = ""; for (let index = 0; index < 10; index++) { if (data[startIndex]) { dataHTML += that.getTableHTML(data[startIndex]); } else { break; } startIndex++; } DOMUtils.remove( ".whitesevPopNetDiskHistoryMatch .netdiskrecord-table ul li" ); DOMUtils.append( document.querySelector( ".whitesevPopNetDiskHistoryMatch .netdiskrecord-table ul" ), dataHTML ); }, }); dataPaging.append( document.querySelector( ".whitesevPopNetDiskHistoryMatch .netdiskrecord-page" ) ); }, /** * 设置搜索框的回车事件 */ setSearchEvent() { let isSeaching = false; /* 当前搜索的状态 */ let searchLoading = null; /* 搜索中的遮罩层 */ let that = this; function searchEvent() { if (isSeaching) { return; } isSeaching = true; searchLoading = pops.loading({ parent: document.querySelector( ".whitesevPopNetDiskHistoryMatch .pops-confirm-content ul" ), content: { text: "搜索中...", }, only: true, }); let inputText = document .querySelector( ".whitesevPopNetDiskHistoryMatch .netdiskrecord-search input" ) .value.trim(); let data = that.getNetDiskHistoryMatchData(); data = that.orderNetDiskHistoryMatchData(data); if (inputText === "") { /* 输入空就关闭遮罩层且恢复style */ let historyDataHTML = ""; data.forEach((item, index) => { if (index > 9) { return; } historyDataHTML += that.getTableHTML(item); }); DOMUtils.remove( ".whitesevPopNetDiskHistoryMatch .netdiskrecord-table ul li" ); DOMUtils.append( document.querySelector( ".whitesevPopNetDiskHistoryMatch .netdiskrecord-table ul" ), historyDataHTML ); searchLoading?.close(); isSeaching = false; that.setDataPaging(data); return; } let isFind = false; /* 找到的状态 */ let isFindHTML = ""; /* 找到的链接文本 */ data.forEach((item) => { let netDiskURL = NetDisk.handleLinkShow( item.netDiskName, item.netDiskIndex, item.shareCode, item.accessCode ); if ( netDiskURL.match(new RegExp(inputText, "ig")) || item.url.match(new RegExp(inputText, "ig")) || item.topURL.match(new RegExp(inputText, "ig")) || item.title.match(new RegExp(inputText, "ig")) ) { /* 匹配到 */ isFind = true; isFindHTML += that.getTableHTML(item); } }); DOMUtils.remove( ".whitesevPopNetDiskHistoryMatch .netdiskrecord-table ul li" ); DOMUtils.append( ".whitesevPopNetDiskHistoryMatch .netdiskrecord-table ul", isFindHTML ); DOMUtils.remove( ".whitesevPopNetDiskHistoryMatch .netdiskrecord-page > *" ); searchLoading?.close(); searchLoading = null; isSeaching = false; } utils.listenKeyPress( document.querySelector( ".whitesevPopNetDiskHistoryMatch .netdiskrecord-search input" ), (keyName) => { if (keyName === "Enter") { searchEvent(); } } ); }, /** * 设置右击菜单事件 */ setContextMenuEvent() { DOMUtils.on( document.querySelector(".whitesevPopNetDiskHistoryMatch"), "contextmenu", ".netdiskrecord-link a", function (event) { NetDiskUI.view.showContextMenu(event, undefined, [ { text: "复制链接", callback: function () { let netDiskName = event.target.getAttribute("data-netdisk"); let netDiskIndex = event.target.getAttribute("data-netdisk-index"); let shareCode = event.target.getAttribute("data-sharecode"); let accessCode = event.target.getAttribute("data-accesscode"); NetDiskParse.copyText( netDiskName, netDiskIndex, shareCode, accessCode ); }, }, { text: "访问链接", callback: function () { let netDiskName = event.target.getAttribute("data-netdisk"); let netDiskIndex = event.target.getAttribute("data-netdisk-index"); let shareCode = event.target.getAttribute("data-sharecode"); let accessCode = event.target.getAttribute("data-accesscode"); let url = NetDiskParse.getBlankUrl( netDiskName, netDiskIndex, shareCode, accessCode ); NetDiskParse.blank(url, netDiskName, shareCode, accessCode); }, }, { text: "修改访问码", callback: function () { let netDiskName = event.target.getAttribute("data-netdisk"); let netDiskIndex = parseInt( event.target.getAttribute("data-netdisk-index") ); let shareCode = event.target.getAttribute("data-sharecode"); let accessCode = event.target.getAttribute("data-accesscode"); let currentTime = new Date().getTime(); NetDiskUI.newAccessCodeView( "修改访问码", netDiskName, netDiskIndex, shareCode, (userInputAccessCode) => { let data = GM_getValue( NetDiskUI.netDiskHistoryMatch.storageKey ); let editFlag = false; data.forEach((item) => { if ( item["netDiskName"] === netDiskName && item["netDiskIndex"] === netDiskIndex && item["shareCode"] === shareCode && item["accessCode"] === accessCode ) { item = utils.assign(item, { accessCode: userInputAccessCode, updateTime: currentTime, }); log.success(["成功找到项", item]); editFlag = true; return; } }); if (editFlag) { GM_setValue( NetDiskUI.netDiskHistoryMatch.storageKey, data ); event.target .closest("li") .querySelector( ".netdiskrecord-update-time" ).lastChild.textContent = utils.formatTime(currentTime); event.target.setAttribute( "data-accesscode", userInputAccessCode ); Qmsg.success( `修改 ${accessCode} => ${userInputAccessCode}` ); } else { Qmsg.error("修改失败"); } } ); }, }, ]); } ); }, /** * 排序数据 * @returns {Array} */ orderNetDiskHistoryMatchData(data) { let localOrder = GM_getValue( "netdisk-history-match-ordering-rule", "按 更新时间 - 降序" ); let isDesc = localOrder.indexOf("降序") !== -1 ? true : false; /* 降序 */ let orderField = localOrder.indexOf("记录时间") !== -1 ? "addTime" : "updateTime"; /* 排序字段 */ utils.sortListByProperty( data, (item) => { return item[orderField]; }, isDesc ); return data; }, /** * 存储匹配到的链接 * @param {string} netDiskName 网盘名称 * @param {number} netDiskIndex 网盘名称索引下标 * @param {string} shareCode * @param {string} accessCode * @returns */ setNetDiskHistoryMatchData( netDiskName, netDiskIndex, shareCode, accessCode ) { if (!GM_getValue("saveMatchNetDisk", false)) { return; } let data = this.getNetDiskHistoryMatchData(); for (let i = 0; i < data.length; i++) { let item = data[i]; if ( item.url === window.location.href && item.topURL === top.window.location.href && item.netDiskName === netDiskName && shareCode.startsWith(item.shareCode) && item.netDiskIndex === netDiskIndex ) { if (item.accessCode !== accessCode) { /* 修改accessCode */ log.success("匹配历史记录 -> 修改accessCode"); data[i].accessCode = accessCode; data[i].updateTime = new Date().getTime(); if (data[i].title) { data[i].title = document.title; } GM_setValue(this.storageKey, data); return; } else if (item.accessCode === accessCode) { /* 已存在一模一样的 */ return; } } } log.success("匹配历史记录 -> 增加新的"); let time = new Date().getTime(); data = [ ...data, { url: window.location.href, topURL: top.window.location.href, netDiskName: netDiskName, netDiskIndex: netDiskIndex, shareCode: shareCode, accessCode, addTime: time, updateTime: time, title: document.title || top.document.title, }, ]; GM_setValue(this.storageKey, data); }, /** * 获取历史匹配到的链接 * @returns {} */ getNetDiskHistoryMatchData() { let data = GM_getValue(this.storageKey); if (data == null) { data = []; GM_setValue(this.storageKey, data); } return data; }, /** * 删除存储的某个项 * @param {string} dataJSONText */ deleteNetDiskHistoryMatchData(dataJSONText) { let data = this.getNetDiskHistoryMatchData(); for (let index = 0; index < data.length; index++) { if (JSON.stringify(data[index]) === dataJSONText) { console.log("删除 ===> ", data[index]); data.splice(index, 1); break; } } GM_setValue(this.storageKey, data); }, /** * 清空所有配置 */ clearNetDiskHistoryMatchData() { GM_setValue(this.storageKey, []); }, }, /** * 监听页面元素变动 进行匹配网盘链接 */ monitorDOMInsert() { NetDiskWorker.initWorkerBlobLink(); NetDiskWorker.initWorker(); utils.mutationObserver(document.body, { callback: async (mutations) => { if (NetDiskUI.isHandling) { /* 当前正在处理文本正则匹配中 */ return; } NetDiskUI.isHandling = true; let clipboardText = ""; if (GM_getValue("readClipboard", false)) { clipboardText = await NetDisk.getClipboardText(); } NetDisk.matchPageLink(clipboardText); }, config: { /* 子节点的变动(新增、删除或者更改) */ childList: true, /* 节点内容或节点文本的变动 */ characterData: true, /* 是否将观察器应用于该节点的所有后代节点 */ subtree: true, }, }); NetDisk.matchPageLink(); /* 自执行一次,因为有的页面上没触发mutationObserver */ }, }; GM_Menu = new utils.GM_Menu( { showSetting: { text: "⚙ 打开设置界面", callback: () => { NetDiskUI.suspension.initPop(); NetDiskUI.suspension.showSettingView(); }, }, showNetDiskHistoryMatch: { text: "⚙ 打开历史匹配记录", callback: () => { NetDiskUI.netDiskHistoryMatch.show(); }, }, repairHistoryMatchLocalData: { text: "🔧 修复版本<23.5.30.10.00历史匹配记录的数据", callback: () => { let localData = GM_getValue(NetDiskUI.netDiskHistoryMatch.storageKey); let repairCount = 0; if (!localData) { Qmsg.error("本地暂未存储历史匹配记录数据"); return; } localData.forEach((item) => { if (!("netDiskIndex" in item)) { repairCount++; item["netDiskIndex"] = 0; } }); if (repairCount) { GM_setValue(NetDiskUI.netDiskHistoryMatch.storageKey, localData); Qmsg.success(`成功修复 ${repairCount}条数据`); } else { Qmsg.success("不存在待修复的数据"); } }, }, }, false, GM_getValue, GM_setValue, GM_registerMenuCommand, GM_unregisterMenuCommand ); DOMUtils.ready(function () { NetDiskAutoFillAccessCode.default(); NetDiskAuthorization.default(); NetDiskUI.monitorDOMInsert(); }); })();