NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name 网盘链接识别 // @namespace https://greasyfork.org/zh-CN/scripts/445489 // @supportURL https://github.com/WhiteSevs/TamperMonkeyScript/issues // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAAAXNSR0IArs4c6QAACsJJREFUeF7tXW+IHdUVP2c2u8kHIQYL0TRIaK1SgrFFaZsvVkpAo6YR1LJpa9jUd++83SUpSrUNBFRCrVgxNOv+mTOvJBBNmtpamoQG9UNBKLHFDzEtFttKBdOYQENE/Lb75vZd2cVNum/uvXNnZt/MnoGQD+/c8+d3fu+c+2f2PgR+ljQCuKSj5+CBCbDEScAEYAIscQSWePhcAZgASxyBJR4+VwAmQHEIjIyM3DAzM/M1pdSXEfEWALgVANbkaPE0ABwhomdz1GmtSgixHxF3Wg8wC55HxPeVUu8DgP7/jRUrVvxpbGzsY/PQbBK5VwCd9Ha7vVkptRkA9L8yHiKisAxDczaklL8GgAfLsImIryql3gSAqBPnh3nazI0AjUZjbRAEjwLAI3k6aKtLKbUjjuODtvI+cs1m894kSY776Mg49hwAxHkSIRcCSCl10nXy12YMLI9hrxDR/XkoMukQQrQQ8WGTXIGfn0PEZ6IoGvO14U0AKeUJALjH15Ecxr9ARHn2464uCSEOI+K2HHz2VXGUiAZ9lHgRQEp5BgBu9nEgr7FBEGyZmprSZCz8EUIMIuKRwg3ZGfiAiK63E/1/qcwEkFJ+BAArsxrOedzLRPSdnHWmqgvD8EBntj5Ups0UWxeI6NosvmQigBDibUTckMVgAWNKXwHMxSClfBwAtgPA+gLiclX5GhHd6TrImQBhGO5RSu11MHQREY8nSXICEf/R399/bnx8/KLD+CUl2plf3BgEwa1JktyOiN8HgKscAHCuhE4EaDabQ0mSHLBxSCml5weHlFKHWq3WBZsxLHM5AlLKLwLAQwCwCwBWWeLzKBHts5S1fx9ASnkdALxluZPXIiJh6wTLpSMwPDx8U7vd/iEADFtgdTZJko2tVuushawTAZ4EgCdMSpVSW+M4PmaS48/dEZBSWuWgMznfR0R6X8b4WLUA228/Ig5GUXTUaJUFMiMghNiEiK+bFCxbtuxLExMT/zLJ2RLAhnmTRDRiMsif+yMQhuFupdTTaZoQcZfNTqEVAYQQf0TEO1IMXurr69s4OTn5rn94rMEGAYul+Ekiutuky0iAoaGhqwcGBi4ZFD1FRLpK8FMSAkKIHyHiz9PM2bQBIwGklPcBwO9SDH0CAF8hovdKip3NAECj0VgdBMHf05aHSqntcRwfSm0VJjSllD8DgJ90k1NKTcVxbLM8MZnizx0RkFL+BgC6noAi4nNRFD3mSwB96NH1xKnMc3hHfGovbnEoZdweNraAMAxPKaW+0Q1NRFwfRdE7tUe7BwOUUuqTWL3j2u0xHhIZCSCl1K8gdT1pIiKjjh7ErhYujY6OXjM9Pf3ftGBM+TEmT0qpfAzUAukeDsI3P0yAHk6ujWtMABuUaizDBKhxcm1CYwLYoFRjGSZAjZNrExoTwAalGsswAWqcXJvQmAA2KNVYhglQ4+TahMYEsEGpxjK1IYCU8vcAcJvlW8dVTqn+C9+3iGhrHkHUggCmIPIAqhd1mA5qbHw2YWeysehnAWVetGADaMkyzn/Jc6V/dSDAeQBYXTLwvWLOeF5vcrQOBEg9bjYBUPXPTSXaFB8TwIRQj3/OBDC8cNLj+fN2r+oEOE1EX/VBwVTCfHRXYWzBBDDmx7gKMNyF92PfO/pMBPAFKO9Zsyupio7PNz9GAuiAuyzVcrmZo2iA6k4A3/xYEUAb0Xfjtdvt+xBxlVLqeF538jEB8nmrOmt+rAngWvps5ZkA+RDAFu8r5XqBAP9J2f8/R0SfzxrcQuMWgXClxueKVS8QQB8CfbuL48fyOjSZ078IBCg1vsoRYHYSs+BuYN4rgDRbc8CVabMIW5UkwLyZ7O2zAbxR1MWPZVeAeZVH3y5eeHyVJYCr41nlF4sAWf0tetyizwGKDnCx9wHKjs/VHhPgCsR6oS+7JtFHngnABPDhT/XG8hzg8pxxBeAKUL1vsY/HXAG4AvCNJ/M4wC2AW4BPQa3eWG4B3AK4BXAL6F65eCOoelXdyWNuAdwCuAVwC+AWMIcALwN5GejUQisvzHMAngPwHIDnADwH4DlAFw7wPkDlu3x6ADwHyDgHCMPwLqXUJgCYDoLgpampqb9VkSt1JUDW/FgtA6WUvwSAH1yR8Bc7vxSmf9i4Uk8dCeCTHyMBDL8a9j0iOlwlBtSNAL75sSGA/v1Z/TPmCz3/JqIvMAEWDwEppVd+bAhQq3VzDSuAV36YABXfCvYlNBOACbC01s2+35jF6/YLW/aNhysAVwCuAPMRqNpWMFcAx5rsC5ijucLFfePhFsAtgFsAt4AUDviWmMJroKMBjsfxNJABc2RYyeK++VmKc4CevrfPlT9MAEfEZn+cqrR7CR3dcxZnAjhD9unl16XdS5jBPachTAAnuD4Tnr0Bvefu7XMNhwngiljN5JkANUuoazhMAFfEaia/6ATo7+//3Pj4+MWa4VqZcAwEOE9E16UFY7MPkLZu1ro3ENFfK4NYjRwVQtyIiO92CwkR34yiaKMvAY4BwJZuSpRSD8Rx/Nsa4VqZUMIw3KaUSnsr+1dEtM2LAEKIvYi4J4VlB6Mo2lEZ1GrkqBBiEhGbKSE9Q0S7vQggpfwuALyUouRikiTrW63WhRph2/OhSCn1q/qnAeCqlOp8dxzHJ70IMDIycsPMzMw/05QopR6L4/i5nketRg5KKZ8EgCfSQlq+fPnKsbGxj70IoAdLKf8AAJtTmHYmjuNbaoRvT4cyPDx8U7vdPgUAq1Ja86tRFN1lCsS4CtAKwjDcqZTab1DWIiJhMsif+yMgpZwAgGGDpqeISFeJ1MeKADZtQFtRSm2N41ivGvgpCAGb0t8p2ucA4DYi+tDkhhUBZtvA8wDwiFEh4mAURUdNcvy5OwJCiE2I+LrFSKtvv9ZjTYBGo7E2CALdd9ZaODDZ19f3i8nJya6bFBY6WGQeAmEY7lZKPW0BivW334kAs1VAVwBdCWyeSwCg5w2HOvcIvGczgGUuR6DRaKxGRH0Hw0OIuMEGH0TcFUXRmI2sMwFmSXACAO6xNQAAnyilXuysIv4cBMFfoih6x2HskhIdHR29Znp6eo1Saj0iPgAA30qb6S8AzlEiGnQBzboFzFcqpTwDADe7GCpIVm+EHCGiZwvSn6pWCLEfEXcuhu0FbH5ARNe7+pKJALOV4CMAWOlqsCB56sx4w4J0L6h29o2iB8u0mWLrAhFdm8WXzATQxoQQb9v2pizOuYxRSu2I4/igy5isss1m894kSY5nHZ/zuNeI6M6sOr0IoI2GYbhHKbU3qwM5jnulcyx9f476uqoSQrQQ8eEybBlsvOz7G8veBNAONpvNoSRJfgoAaxYRlBeIqJR+3DmHP9w5h089Zi0Yh7N6NUZE+3zt5EKA2TmBfvNE92G9HVw6EYIg2DI1NaVXKIU/QohBRDxSuKGFDexLkuT5VqulSeD95EaAOU+klJ8SQSn1TUS8w9tDOwXepdDOzGdSYRgeUEoNuY7LKH8SEU/29fWdnJiY0LeC5fbkToD5ng0NDV09MDCgSfB1AFiHiOuUUusAINOMtUvUpa8A5pH9cQDYDgDrc8sIgH6vQk+uzyRJcqa/v/9U3kmf72uhBMgRFFZVEAJMgIKArYpaJkBVMlWQn0yAgoCtilomQFUyVZCfTICCgK2KWiZAVTJVkJ9MgIKArYra/wGYigzMiqJYZwAAAABJRU5ErkJggg== // @version 2024.1.11 // @description 识别网页中显示的网盘链接,目前包括百度网盘、蓝奏云、天翼云、中国移动云盘(原:和彩云)、阿里云、文叔叔、奶牛快传、123盘、腾讯微云、迅雷网盘、115网盘、夸克网盘、城通网盘(部分)、坚果云、UC网盘、BT磁力,支持蓝奏云、天翼云(需登录)、123盘、奶牛、UC网盘(需登录)和坚果云(需登录)直链获取下载,页面动态监控加载的链接,可自定义规则来识别小众网盘/网赚网盘或其它自定义的链接。 // @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_registerMenuCommand // @grant GM_unregisterMenuCommand // @grant unsafeWindow // @connect * // @connect lanzoub.com // @connect lanzouc.com // @connect lanzoue.com // @connect lanzouf.com // @connect lanzoug.com // @connect lanzouh.com // @connect lanzoui.com // @connect lanzouj.com // @connect lanzouk.com // @connect lanzoul.com // @connect lanzoum.com // @connect lanzouo.com // @connect lanzoup.com // @connect lanzouq.com // @connect lanzous.com // @connect lanzout.com // @connect lanzouu.com // @connect lanzouv.com // @connect lanzouw.com // @connect lanzoux.com // @connect lanzouy.com // @connect lanosso.com // @connect lanzn.com // @connect 189.cn // @connect 123pan.com // @connect 123pan.cn // @connect wenshushu.cn // @connect jianguoyun.com // @connect cowtransfer.com // @connect cowcs.com // @exclude /^http(s|):\/\/s1\.hdslb\.com\/.*$/ // @exclude /^http(s|):\/\/www\.bilibili\.com\/video.*$/ // @exclude /^http(s|):\/\/message\.bilibili\.com\/.*$/ // @exclude /^http(s|):\/\/live\.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\/.*$/ // @exclude /^http(s|):\/\/cloudgame\.ds\.163\.com\/.*$/ // @exclude /^http(s|):\/\/cloudgame\.webapp\.163\.com\/.*$/ // @exclude /^http(s|):\/\/cg\.163\.com\/.*$/ // @require https://update.greasyfork.org/scripts/462234/1307862/Message.js // @require https://update.greasyfork.org/scripts/456470/1289386/%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 // @require https://update.greasyfork.org/scripts/465550/1270548/JS-%E5%88%86%E9%A1%B5%E6%8F%92%E4%BB%B6.js // @require https://update.greasyfork.org/scripts/456485/1311382/pops.js // @require https://update.greasyfork.org/scripts/455186/1309760/WhiteSevsUtils.js // @require https://update.greasyfork.org/scripts/465772/1310369/DOMUtils.js // ==/UserScript== (function () { /** * @type {import("../库/Qmsg")} */ const Qmsg = window.Qmsg; /** * @type {import("../库/pops")} */ const pops = window.pops; const AnyTouch = pops.config.Utils.AnyTouch(); /** * @type {import("../库/Utils")} */ const utils = window.Utils.noConflict(); /** * @type {import("../库/DOMUtils")} */ const DOMUtils = window.DOMUtils.noConflict(); const log = new utils.Log(GM_info); const httpx = new utils.Httpx(GM_xmlhttpRequest); let GM_Menu = new utils.GM_Menu({ autoReload: false, GM_getValue, GM_setValue, GM_registerMenuCommand, GM_unregisterMenuCommand, }); /** * 数据配置 */ const NetDiskData = { /** * 蓝奏云默认主机域名 */ lanzou_defaultHostName: "www.lanzout.com", /** * 是否点击网盘小图标寻找shareCode */ iconDefaultClickEventToFindShareCode: true, /** * 是否点击网盘小图标寻找shareCode且使用光标选中 */ iconDefaultClickEventToFindShareCodeWithSelect: true, /** * 是否点击网盘小图标(循环)寻找shareCode */ iconDefaultClickEventToFindShareCodeByLoop: true, }; const NetDisk = { /** * 是否初始化 * @type {boolean} */ isInit: false, /** * 链接字典 * @type {utils.Dictionary} */ linkDict: null, /** * 是否正在匹配链接中 */ isMatching: false, /** * 匹配到的链接 */ matchLink: null, /** * 是否成功匹配到链接 */ hasMatchLink: false, /** * 剪贴板内容 */ clipboardText: "", /** * 是否允许匹配window.location.href */ allowMatchLocationHref: false, /** * 当没有accessCode时,使用该正则去除不需要的字符串 */ noAccessCodeRegExp: /( |提取码:|{#accessCode#}|\?pwd=)/gi, 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,${parseInt( GM_getValue("accessCode_after_text_baidu", 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", 100) )}}(密码|访问码|提取码)[\\s\\S]{0,${parseInt( GM_getValue("accessCode_after_html_baidu", 15) )}}[0-9a-zA-Z]{4}|)`, /** * 链接参数 */ shareCode: /pan\.baidu\.com\/s\/([0-9a-zA-Z-_]+)/gi, /** * 需要替换空的字符串,比如pan.baidu.com/s/替换为空 */ shareCodeNeedRemoveStr: /pan\.baidu\.com\/s\//gi, /** * 用来判断是否存在密码 */ checkAccessCode: /(密码|访问码|提取码)[\s\S]+/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,${parseInt( GM_getValue("accessCode_after_text_lanzou", 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", 100) )}}(密码|访问码|提取码)[\\s\\S]{0,${parseInt( GM_getValue("accessCode_after_html_lanzou", 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, /** * shareCode参数中不可能存在的链接,如果shareCode存在这些,那就拒绝匹配 */ shareCodeNotMatch: /^(ajax|file|undefined|1125)/gi, shareCodeNeedRemoveStr: /lanzou[a-z]{0,1}.com\/(tp\/|u\/|)/gi, checkAccessCode: /(密码|访问码|提取码)[\s\S]+/g, accessCode: /([0-9a-zA-Z]{3,})/gi, uiLinkShow: `${GM_getValue( "lanzou-host-name", NetDiskData.lanzou_defaultHostName )}/{#shareCode#} 提取码: {#accessCode#}`, blank: `https://${GM_getValue( "lanzou-host-name", NetDiskData.lanzou_defaultHostName )}/{#shareCode#}`, copyUrl: `https://${GM_getValue( "lanzou-host-name", NetDiskData.lanzou_defaultHostName )}/{#shareCode#}\n密码:{#accessCode#}`, }, { link_innerText: `lanzn.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,${parseInt( GM_getValue("accessCode_after_text_lanzou", 10) )}}[a-zA-Z0-9]{3,6}|)`, link_innerHTML: `lanzn.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", 100) )}}(密码|访问码|提取码)[\\s\\S]{0,${parseInt( GM_getValue("accessCode_after_html_lanzou", 15) )}}[a-zA-Z0-9]{3,6}|)`, shareCode: /lanzn.com\/(tp\/|u\/|)([a-zA-Z0-9_\-]{5,22}|[%0-9a-zA-Z]{4,90}|[\u4e00-\u9fa5]{1,20})/gi, /** * shareCode参数中不可能存在的链接,如果shareCode存在这些,那就拒绝匹配 */ shareCodeNotMatch: /^(ajax|file|undefined|1125)/gi, shareCodeNeedRemoveStr: /lanzn.com\/(tp\/|u\/|)/gi, checkAccessCode: /(密码|访问码|提取码)[\s\S]+/g, accessCode: /([0-9a-zA-Z]{3,})/gi, uiLinkShow: `${GM_getValue( "lanzou-host-name", NetDiskData.lanzou_defaultHostName )}/{#shareCode#} 提取码: {#accessCode#}`, blank: `https://${GM_getValue( "lanzou-host-name", NetDiskData.lanzou_defaultHostName )}/{#shareCode#}`, copyUrl: `https://${GM_getValue( "lanzou-host-name", NetDiskData.lanzou_defaultHostName )}/{#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,${parseInt( GM_getValue("accessCode_after_text_tianyiyun", 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", 100) )}}(密码|访问码|提取码)[\\s\\S]{0,${parseInt( GM_getValue("accessCode_after_html_tianyiyun", 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: /(密码|访问码|提取码)[\s\S]+/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,${parseInt( GM_getValue("accessCode_after_text_hecaiyun", 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", 100) )}}(密码|访问码|提取码)[\\s\\S]{0,${parseInt( GM_getValue("accessCode_after_html_hecaiyun", 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: /(密码|访问码|提取码)[\s\S]+/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,${parseInt( GM_getValue("accessCode_after_text_aliyun", 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", 100) )}}(密码|访问码|提取码)[\\s\\S]{0,${parseInt( GM_getValue("accessCode_after_html_aliyun", 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: /(密码|访问码|提取码)[\s\S]+/g, accessCode: /([0-9a-zA-Z]{4})/gi, acceesCodeNotMatch: /^(font)/gi, uiLinkShow: "aliyundrive.com/s/{#shareCode#} 提取码: {#accessCode#}", blank: "https://www.aliyundrive.com/s/{#shareCode#}", copyUrl: "https://www.aliyundrive.com/s/{#shareCode#}\n密码:{#accessCode#}", }, { link_innerText: `alipan.com/s/([a-zA-Z0-9_-]{8,14})([\\s\\S]{0,${parseInt( GM_getValue("innerText_aliyun", 20) )}}(密码|访问码|提取码)[\\s\\S]{0,${parseInt( GM_getValue("accessCode_after_text_aliyun", 10) )}}[0-9a-zA-Z]{4}|)`, link_innerHTML: `alipan.com/s/([a-zA-Z0-9_-]{8,14})([\\s\\S]{0,${parseInt( GM_getValue("innerHTML_aliyun", 100) )}}(密码|访问码|提取码)[\\s\\S]{0,${parseInt( GM_getValue("accessCode_after_html_aliyun", 15) )}}[0-9a-zA-Z]{4}|)`, shareCode: /alipan\.com\/s\/([a-zA-Z0-9_\-]{8,14})/g, shareCodeNotMatch: /undefined/gi, shareCodeNeedRemoveStr: /alipan\.com\/s\//gi, checkAccessCode: /(密码|访问码|提取码)[\s\S]+/g, accessCode: /([0-9a-zA-Z]{4})/gi, acceesCodeNotMatch: /^(font)/gi, uiLinkShow: "alipan.com/s/{#shareCode#} 提取码: {#accessCode#}", blank: "https://www.alipan.com/s/{#shareCode#}", copyUrl: "https://www.alipan.com/s/{#shareCode#}\n密码:{#accessCode#}", }, ], wenshushu: [ { link_innerText: `(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,${parseInt( GM_getValue("accessCode_after_text_wenshushu", 10) )}}[0-9a-zA-Z]{4}|)`, link_innerHTML: `(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", 100) )}}(密码|访问码|提取码)[\\s\\S]{0,${parseInt( GM_getValue("accessCode_after_html_wenshushu", 15) )}}[0-9a-zA-Z]{4}|)`, shareCode: /wenshushu.cn\/f\/([a-zA-Z0-9_-]{8,14})|wenshushu.cn\/k\/([a-zA-Z0-9_-]{8,14})/gi, shareCodeNeedRemoveStr: /wenshushu.cn\/f\/|wenshushu.cn\/k\//gi, checkAccessCode: /(密码|访问码|提取码)[\s\S]+/g, accessCode: /[0-9a-zA-Z]{4}/gi, uiLinkShow: "www.wenshushu.cn/f/{#shareCode#} 提取码: {#accessCode#}", blank: "https://www.wenshushu.cn/f/{#shareCode#}", copyUrl: "https://www.wenshushu.cn/f/{#shareCode#}\n密码:{#accessCode#}", }, { 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})|ws59.cn/f/([a-zA-Z0-9_-]{8,14}))([\\s\\S]{0,${parseInt( GM_getValue("innerText_wenshushu", 20) )}}(密码|访问码|提取码)[\\s\\S]{0,${parseInt( GM_getValue("accessCode_after_text_wenshushu", 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})|ws59.cn/f/([a-zA-Z0-9_-]{8,14}))([\\s\\S]{0,${parseInt( GM_getValue("innerHTML_wenshushu", 100) )}}(密码|访问码|提取码)[\\s\\S]{0,${parseInt( GM_getValue("accessCode_after_html_wenshushu", 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})|ws59.cn\/f\/([a-zA-Z0-9_-]{8,14})/gi, shareCodeNeedRemoveStr: /wss.ink\/f\/|ws28.cn\/f\/|wss1.cn\/f\/|ws59.cn\/f\//gi, checkAccessCode: /(密码|访问码|提取码)[\s\S]+/g, accessCode: /[0-9a-zA-Z]{4}/gi, uiLinkShow: "www.wenshushu.cn/f/{#shareCode#} 提取码: {#accessCode#}", blank: "https://www.wenshushu.cn/f/{#shareCode#}", copyUrl: "https://www.wenshushu.cn/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,${parseInt( GM_getValue("accessCode_after_text_nainiu", 10) )}}[0-9a-zA-Z]{4,6}|)`, link_innerHTML: `cowtransfer.com/s/([a-zA-Z0-9_-]{8,14})([\\s\\S]{0,${parseInt( GM_getValue("innerHTML_nainiu", 100) )}}(密码|访问码|提取码)[\\s\\S]{0,${parseInt( GM_getValue("accessCode_after_html_nainiu", 15) )}}[0-9a-zA-Z]{4,6}|)`, shareCode: /cowtransfer.com\/s\/([a-zA-Z0-9_\-]{8,14})/gi, shareCodeNeedRemoveStr: /cowtransfer\.com\/s\//gi, checkAccessCode: /(密码|访问码|提取码)[\s\S]+/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,${parseInt( GM_getValue("accessCode_after_text__123pan", 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", 100) )}}(密码|访问码|提取码)[\\s\\S]{0,${parseInt( GM_getValue("accessCode_after_html__123pan", 15) )}}[0-9a-zA-Z]{4}|)`, shareCode: /123pan.com\/s\/([a-zA-Z0-9_\-]{8,14})/gi, shareCodeNeedRemoveStr: /123pan.com\/s\//gi, checkAccessCode: /(密码|访问码|提取码)[\s\S]+/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,${parseInt( GM_getValue("accessCode_after_text_weiyun", 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", 100) )}}(访问码|密码|提取码)[\\s\\S]{0,${parseInt( GM_getValue("accessCode_after_html_weiyun", 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: /(提取码|密码|访问码)[\s\S]+/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) )}}(\\?pwd=|访问码|提取码|密码|)[\\s\\S]{0,${parseInt( GM_getValue("accessCode_after_text_xunlei", 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", 100) )}}(\\?pwd=|访问码|提取码|密码|)[\\s\\S]{0,${parseInt( GM_getValue("accessCode_after_html_xunlei", 15) )}}[0-9a-zA-Z]{4}|)`, shareCode: /xunlei.com\/s\/([0-9a-zA-Z\-_]{8,30})/gi, shareCodeNeedRemoveStr: /xunlei.com\/s\//gi, checkAccessCode: /(\?pwd=|提取码|密码|访问码)[\s\S]+/g, accessCode: /([0-9a-zA-Z]{4})/gi, uiLinkShow: "pan.xunlei.com/s/{#shareCode#}?pwd={#accessCode#} 提取码: {#accessCode#}", blank: "https://pan.xunlei.com/s/{#shareCode#}?pwd={#accessCode#}", copyUrl: "https://pan.xunlei.com/s/{#shareCode#}?pwd={#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,${parseInt( GM_getValue("accessCode_after_text__115pan", 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", 100) )}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,${parseInt( GM_getValue("accessCode_after_html__115pan", 15) )}}[0-9a-zA-Z]{4}|)`, shareCode: /115.com\/s\/([0-9a-zA-Z\-_]{8,24})/gi, shareCodeNeedRemoveStr: /115.com\/s\//gi, checkAccessCode: /(提取码|密码|\?password=|访问码)[\s\S]+/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,${parseInt( GM_getValue("accessCode_after_text_chengtong", 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", 100 )}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,${parseInt( GM_getValue("accessCode_after_html_chengtong", 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: /(提取码|密码|访问码)[\s\S]+/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,${parseInt( GM_getValue("accessCode_after_text_chengtong", 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", 100 )}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,${parseInt( GM_getValue("accessCode_after_html_chengtong", 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: /(提取码|密码|访问码)[\s\S]+/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,${parseInt( GM_getValue("accessCode_after_text_chengtong", 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", 100 )}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,${parseInt( GM_getValue("accessCode_after_html_chengtong", 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: /(提取码|密码|访问码)[\s\S]+/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,${parseInt( GM_getValue("accessCode_after_text_chengtong", 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", 100) )}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,${parseInt( GM_getValue("accessCode_after_html_chengtong", 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: /(提取码|密码|访问码)[\s\S]+/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,${parseInt( GM_getValue("accessCode_after_text_chengtong", 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", 100 )}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,${parseInt( GM_getValue("accessCode_after_html_chengtong", 15) )}}[0-9a-zA-Z]{4,6}|)`, shareCode: /ctfile.com\/f\/([0-9a-zA-Z\-_]{8,26})/gi, shareCodeNeedRemoveStr: /ctfile.com\/f\//gi, checkAccessCode: /(提取码|密码|访问码)[\s\S]+/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,${parseInt( GM_getValue("accessCode_after_text_chengtong", 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", 100 )}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,${parseInt( GM_getValue("accessCode_after_html_chengtong", 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: /(提取码|密码|访问码)[\s\S]+/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,${parseInt( GM_getValue("accessCode_after_text_chengtong", 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", 100 )}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,${parseInt( GM_getValue("accessCode_after_html_chengtong", 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: /(提取码|密码|访问码)[\s\S]+/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,${parseInt( GM_getValue("accessCode_after_text_chengtong", 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", 100 )}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,${parseInt( GM_getValue("accessCode_after_html_chengtong", 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: /(提取码|密码|访问码)[\s\S]+/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,${parseInt( GM_getValue("accessCode_after_text_chengtong", 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", 100 )}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,${parseInt( GM_getValue("accessCode_after_html_chengtong", 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: /(提取码|密码|访问码)[\s\S]+/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,${parseInt( GM_getValue("accessCode_after_text_kuake", 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", 100) )}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,${parseInt( GM_getValue("accessCode_after_html_kuake", 15) )}}[0-9a-zA-Z]{4}|)`, shareCode: /quark.cn\/s\/([0-9a-zA-Z\-_]{8,24})/gi, shareCodeNeedRemoveStr: /quark.cn\/s\//gi, checkAccessCode: /(提取码|密码|访问码)[\s\S]+/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: /(提取码|密码|访问码)[\s\S]+/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,${parseInt( GM_getValue("accessCode_after_text_jianguoyun", 10) )}}[0-9a-zA-Z]+|)`, link_innerHTML: `jianguoyun.com/p/[0-9a-zA-Z-_]{16,24}([\\s\\S]{0,${parseInt( GM_getValue("innerHTML_jianguoyun", 100) )}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,${parseInt( GM_getValue("accessCode_after_html_jianguoyun", 15) )}}[0-9a-zA-Z]+|)`, shareCode: /jianguoyun.com\/p\/([0-9a-zA-Z\-_]{16,24})/gi, shareCodeNeedRemoveStr: /jianguoyun.com\/p\//gi, checkAccessCode: /(提取码|密码|访问码)[\s\S]+/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", 20) )}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,${parseInt( GM_getValue("accessCode_after_text_onedrive", 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", 100) )}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,${parseInt( GM_getValue("accessCode_after_html_onedrive", 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: /(提取码|密码|访问码)[\s\S]+/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", 20) )}}(访问码|密码|提取码|\\?password=|\\?e=)[\\s\\S]{0,${parseInt( GM_getValue("accessCode_after_text_onedrive", 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", 100) )}}(访问码|密码|提取码|\\?password=|\\?e=)[\\s\\S]{0,${parseInt( GM_getValue("accessCode_after_html_onedrive", 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=)[\s\S]+/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#}", }, ], uc: [ { link_innerText: `drive.uc.cn/s/[0-9a-zA-Z]{8,24}([\\s\\S]{0,${parseInt( GM_getValue("innerText_uc", 20) )}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,${parseInt( GM_getValue("accessCode_after_text_uc", 10) )}}[0-9a-zA-Z]+|)`, link_innerHTML: `drive.uc.cn/s/[0-9a-zA-Z]{8,24}([\\s\\S]{0,${parseInt( GM_getValue("innerHTML_uc", 100) )}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,${parseInt( GM_getValue("accessCode_after_html_uc", 15) )}}[0-9a-zA-Z]+|)`, shareCode: /drive.uc.cn\/s\/([0-9a-zA-Z]{8,24})/gi, shareCodeNeedRemoveStr: /drive.uc.cn\/s\//gi, checkAccessCode: /(提取码|密码|访问码)[\s\S]+/gi, accessCode: /([0-9a-zA-Z]+)/gi, uiLinkShow: "drive.uc.cn/s/{#shareCode#} 提取码: {#accessCode#}", blank: "https://drive.uc.cn/s/{#shareCode#}", copyUrl: "https://drive.uc.cn/s/{#shareCode#}\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" ) /* 历史存储记录弹窗 */, /* 自定义规则弹窗 */ document.querySelector( ".whitesevPopNetDiskAccessCodeRule .netdiskrecord-table" ), /* 添加/修改自定义规则弹窗 */ document.querySelector(".whitesevPopNetDiskAccessCodeRuleAddOrEdit"), ]; ignoreNodeList.forEach((ignoreElement) => { if (ignoreElement == null) { return; } let innerItemText = isHTML ? ignoreElement.innerHTML : ignoreElement.innerText; innerItemText = innerItemText == null ? "" : innerItemText; text = text.replaceAll(innerItemText, ""); }); return text; }, /** * 对页面进行match,处理匹配网盘链接 */ matchPageLink() { 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") { let pageText = this.ignoreStrRemove(document.documentElement.innerText); let pageHTML = this.ignoreStrRemove( document.documentElement.innerHTML, true ); Object.keys(this.regular).forEach((netDiskName) => { let item = this.regular[netDiskName]; item.forEach((netDiskListItem, index) => { NetDiskWorker.postMessage({ regexp: new RegExp(netDiskListItem["link_innerText"], "gi"), pageText: pageText, netDiskName: netDiskName, netDiskIndex: index, }); NetDiskWorker.postMessage({ regexp: new RegExp(netDiskListItem["link_innerHTML"], "gi"), pageText: pageHTML, netDiskName: netDiskName, netDiskIndex: index, }); if (NetDisk.clipboardText.trim() !== "") { NetDiskWorker.postMessage({ regexp: new RegExp(netDiskListItem["link_innerText"], "gi"), pageText: NetDisk.clipboardText, netDiskName: netDiskName, netDiskIndex: index, }); NetDiskWorker.postMessage({ regexp: new RegExp(netDiskListItem["link_innerHTML"], "gi"), pageText: NetDisk.clipboardText, netDiskName: netDiskName, netDiskIndex: index, }); } if (NetDisk.allowMatchLocationHref) { NetDiskWorker.postMessage({ regexp: new RegExp(netDiskListItem["link_innerText"], "gi"), pageText: window.location.href, netDiskName: netDiskName, netDiskIndex: index, }); NetDiskWorker.postMessage({ regexp: new RegExp(netDiskListItem["link_innerHTML"], "gi"), pageText: decodeURIComponent(window.location.href), netDiskName: netDiskName, netDiskIndex: index, }); } }); }); } else { let pageText = ""; if (matchTextRange.toLowerCase() === "innertext") { /* 对innerText进行match */ pageText = this.ignoreStrRemove(document.documentElement.innerText); } else { /* 对innerHTML进行match */ pageText = this.ignoreStrRemove( document.documentElement.innerHTML, true ); } Object.keys(this.regular).forEach((netDiskName) => { let item = this.regular[netDiskName]; item.forEach((netDiskListItem, index) => { NetDiskWorker.postMessage({ regexp: new RegExp( netDiskListItem[`link_${matchTextRange}`], "gi" ), pageText: pageText, netDiskName: netDiskName, netDiskIndex: index, }); if (NetDisk.clipboardText.trim() !== "") { NetDiskWorker.postMessage({ regexp: new RegExp( netDiskListItem[`link_${matchTextRange}`], "gi" ), pageText: NetDisk.clipboardText, netDiskName: netDiskName, netDiskIndex: index, }); } if (NetDisk.allowMatchLocationHref) { NetDiskWorker.postMessage({ regexp: new RegExp( netDiskListItem[`link_${matchTextRange}`], "gi" ), pageText: window.location.href, netDiskName: netDiskName, netDiskIndex: index, }); NetDiskWorker.postMessage({ regexp: new RegExp( netDiskListItem[`link_${matchTextRange}`], "gi" ), pageText: decodeURIComponent(window.location.href), 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); accessCode = this.handleAccessCodeByUserRule(netDiskName, accessCode); 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.isMatchedNetDiskIconMap.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]; if (netDiskMatchRegular.shareCodeNeedRemoveStr) { /* 删除ShareCode前面不需要的字符串 */ shareCode = shareCode.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 = ""; if (!netDiskMatchRegular.checkAccessCode) { /* 不存在匹配提取码的正则 */ return ""; } let accessCodeMatch = url.match(netDiskMatchRegular.checkAccessCode); if (accessCodeMatch) { accessCode = accessCodeMatch[accessCodeMatch.length - 1].match( netDiskMatchRegular.accessCode ); if (utils.isNull(accessCode)) { return ""; } /* 过滤掉match内的undefined或null的值 */ accessCode = accessCode.filter((item) => item != null); accessCode = accessCode[0]; if (accessCode.startsWith("http")) { /* 排除不可能的accessCode */ accessCode = ""; } } return accessCode; }, /** * 对accessCode二次处理,使用自定义的访问码规则 * @param {string} netDiskName 网盘名称 * @param {string} accessCode * @returns {string} */ handleAccessCodeByUserRule(netDiskName, accessCode) { let regularList = NetDiskUI.accessCodeRule.getValue(); let result = accessCode; let currentUrl = window.location.href; /* 先遍历本地的自定义的访问码规则 */ for ( let regularIndex = 0; regularIndex < regularList.length; regularIndex++ ) { let rule = regularList[regularIndex]; let urlRegexp = new RegExp(rule.urlRegexp, "i"); /* 如果网址匹配成功则进行下一步 */ if (!currentUrl.match(urlRegexp)) { continue; } /* 循环遍历自定义的访问码规则的网盘信息 */ for (let index = 0; index < rule.netdisk.length; index++) { let netDiskRegular = rule.netdisk[index]; /* 自定义规则的value(也就是网盘的字母名)和参数netDiskName相同,则直接返回设定的值 */ if (netDiskRegular.value === netDiskName) { log.success(`使用自定义规则中的提取码 ${netDiskName} ${result}`); return rule.accessCode; } } } /* 不存在 */ return result; }, /** * 获取在弹窗中显示出的链接 * @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(NetDisk.noAccessCodeRegExp, ""); } return uiLink; }, /** * 获取剪贴板文本 * @returns {Promise<string>} */ async getClipboardText() { return new Promise((resolve) => { function clipboardRead() { navigator.permissions .query({ name: "clipboard-read", }) .then((result) => { function getText() { let clipboard = navigator.clipboard.readText(); clipboard .then((clipText) => { resolve(clipText); }) .catch((error) => { log.error(["读取剪贴板内容失败", error]); resolve(""); }); } getText(); }) .catch((error) => { log.error(["读取剪贴板内容失败👉", error]); resolve(""); }); } if (document.hasFocus()) { clipboardRead(); } else { window.addEventListener( "focus", () => { clipboardRead(); }, { once: true } ); } }); }, }; /** * 网盘直链解析 */ const NetDiskParse = { netDisk: { /** * 百度网盘 * @constructor * @returns {object} */ baidu: function () { let that = this; /** * 所在规则的下标 */ this.netDiskIndex = 0; /** * 分享码 */ this.shareCode = ""; /** * 提取码 */ this.accessCode = ""; /** * 入口 * @param {number} netDiskIndex 网盘名称索引下标 * @param {string} shareCode * @param {string} accessCode * @returns */ this.default = function (netDiskIndex, shareCode, accessCode) { log.info([netDiskIndex, shareCode, accessCode]); that.netDiskIndex = netDiskIndex; that.shareCode = shareCode; that.accessCode = accessCode; let url = GM_getValue("baidu-baiduwp-php-url"); let postForm = GM_getValue("baidu-baiduwp-php-post-form"); let enableCopy = GM_getValue("baidu-baiduwp-php-copy-url"); if (!url) { Qmsg.error("请先在设置中配置百度网盘-网址"); return null; } if (!postForm) { Qmsg.error("请先在设置中配置百度网盘-表单参数"); return null; } postForm = postForm.replaceAll("{#shareCode#}", shareCode); postForm = postForm.replaceAll("{#accessCode#}", accessCode); let formElement = document.createElement("form"); /* POST的表单数据 */ let formData = {}; let urlParams = new URLSearchParams(postForm); /* 解析网址 */ formElement.action = url; formElement.method = "post"; formElement.style.display = "none"; formElement.target = "_blank"; for (let [key, value] of urlParams) { let textAreaElement = document.createElement("textarea"); textAreaElement.name = key; textAreaElement.value = value; formElement.appendChild(textAreaElement); formData[key] = value; } log.info(["表单数据", formData]); document.body.appendChild(formElement); log.info(["访问网址", url]); if (enableCopy) { NetDiskParse.copyText( "baidu", netDiskIndex, shareCode, accessCode, "1.5秒后跳转至解析站" ); setTimeout(() => { formElement.submit(); }, 1500); } else { formElement.submit(); } }; return this; }, /** * 蓝奏云 * 流程:判断是否是多文件 * 单文件 => 请求https://蓝奏云域名/{shareToken} 判断链接类型和是否能正常获取 * => 请求https://蓝奏云域名/ajaxm.php 获取下载参数,下载参数例如:https://蓝奏云文件域名/file/?xxxxxxxxx * 多文件 => 先请求https://蓝奏云域名/{shareToken} 获取文件sign => 请求https://蓝奏云域名/filemoreajax.php 获取json格式的文件参数, * 参数内容如{"info":"success","text":[{"duan":"xx","icon":"","id":"".....},{},{}]} * @constructor * @returns {object} */ lanzou: function () { let that = this; /** * 所在规则的下标 */ this.netDiskIndex = 0; /** * 分享码 */ this.shareCode = ""; /** * 提取码 */ this.accessCode = ""; /* 蓝奏云域名 */ let LanZouHostName = GM_getValue( "lanzou-host-name", NetDiskData.lanzou_defaultHostName ); this.handleUrl = { default(pathName = "") { if (pathName.startsWith("/")) { pathName = pathName.replace(/^\//, ""); } return `https://${LanZouHostName}/${pathName}`; }, tp(pathName = "") { if (pathName.startsWith("/")) { pathName = pathName.replace(/^\//, ""); } return `https://${LanZouHostName}/tp/${pathName}`; }, }; 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: /<span id=\"filemore\" onclick=\"more\(\);\">/g, }, /** * 蓝奏设置了密码的单文件请求需要的sign值 */ sign: { match: /var[\s]*(posign|postsign|vidksek|skdklds)[\s]*=[\s]*'(.+?)';/, }, /** * 蓝奏文件名 */ fileName: { match: /<title>(.*)<\/title>/, }, /** * 蓝奏文件大小 */ fileSize: { 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) { log.info([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(); }; /** * 获取文件链接 * @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.getRandomPCUA(), Referer: that.handleUrl.default(that.shareCode), }, onerror() {}, }); if (!getResp.status) { log.error(getResp); if (getResp.type === "ontimeout") { return; } if ( getResp.data.responseText.includes( "div>文件不存在,或者已被删除</div>" ) ) { Qmsg.error("文件不存在,或者已被删除"); } else { Qmsg.error("请求异常"); } return; } let respData = getResp.data; if (respData.readyState !== 4) { log.error(respData); Qmsg.error("请求失败,请重试"); return; } if (respData.responseText == null) { log.error(respData); Qmsg.error("获取网页内容为空"); return; } if (!that.checkPageCode(respData)) { return; } if (that.isMoreFile(respData)) { await that.getMoreFile(); } else { log.info(respData); let pageText = respData.responseText; if (getShareCodeByPageAgain) { let shareCodeNewMatch = pageText.match( /var[\s]*link[\s]*=[\s]*\'tp\/(.+?)\';/i ); that.shareCode = shareCodeNewMatch[shareCodeNewMatch.length - 1]; log.info(`新参数 => ${that.shareCode}`); } let pageDOM = DOMUtils.parseHTML(pageText, true, true); let pageIframeElement = pageDOM.querySelector('iframe[class^="ifr"]') || pageDOM.querySelector('iframe[class^="n_downlink"]'); if (pageIframeElement) { let iframeUrl = pageIframeElement.getAttribute("src"); log.error([ "该链接需要重新通过iframe地址访问获取信息", iframeUrl, ]); Qmsg.info("正在请求下载信息"); let fileName = pageDOM.querySelector("body div.d > div")?.innerText || pageDOM.querySelector("#filenajax")?.innerText || pageDOM .querySelector("title") ?.textContent?.replace(/ - 蓝奏云$/i, ""); let fileSize = pageText.match(/文件大小:<\/span>(.+?)<br>/i) || pageDOM.querySelector(".n_filesize")?.innerText; let fileUploadTime = pageText.match(/上传时间:<\/span>(.+?)<br>/i) || pageDOM.querySelector("span.n_file_infos")?.innerText; if (fileSize) { if (Array.isArray(fileSize)) { fileSize = fileSize[fileSize.length - 1]; } } else { log.error("解析文件大小信息失败"); } if (fileUploadTime) { if (Array.isArray(fileUploadTime)) { fileUploadTime = fileUploadTime[fileUploadTime.length - 1]; } } else { log.error("解析文件上传时间信息失败"); } let downloadUrl = await that.getLinkByIframe(iframeUrl, { fileName, fileSize, fileUploadTime, }); if (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 { await that.getLink(respData); } } }; /** * 页面检查,看看是否存在文件失效情况 * @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; } }; /** * 获取链接 * @param {object} response */ 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 fileName = pageText.match(that.regexp.fileName.match); let fileSize = pageText.match(that.regexp.fileSize.match) || pageText.match(/<div class="n_filesize">大小:(.+?)<\/div>/i); let fileUploadTime = pageText.match(that.regexp.uploadTime.match) || pageText.match(/<span class="n_file_infos">(.+?)<\/span>/i); if (fileName) { fileName = fileName[fileName.length - 1].trim(); } else { fileName = ""; } if (fileSize) { fileSize = fileSize[fileSize.length - 1].trim(); } else { fileSize = ""; } if (fileUploadTime) { fileUploadTime = fileUploadTime[fileUploadTime.length - 1].trim(); } else { fileUploadTime; } if (sign) { postData_sign = sign[sign.length - 1]; log.info(`获取Sign: ${postData_sign}`); if (utils.isNotNull(that.accessCode)) { log.info("传入参数=>有密码"); postData_p = that.accessCode; } else { log.info("传入参数=>无密码"); } let postResp = await httpx.post({ url: that.handleUrl.default("ajaxm.php"), responseType: "json", headers: { "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", "User-Agent": utils.getRandomAndroidUA(), Referer: that.handleUrl.default(that.shareCode), }, 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"]}`; if ( typeof json_data["url"] === "string" && (json_data["url"].startsWith("http") || json_data["url"].startsWith(json_data["dom"])) ) { /* 有些情况下比如苹果的ipa文件的请求,json_data["url"]就是一个完整的链接 */ downloadUrl = json_data["url"]; } /* json_data["zt"]表示状态,一般为1 */ let zt = json_data["zt"]; /* json_data["inf"]一般是文件名,也可以看作是请求信息提示 */ 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, }); } }; /** * 通过iframe的链接来获取单文件直链 * @param {string} urlPathName url路径 * @param {{ * fileName:string, * fileSize:string, * fileUploadTime:string * }} fileInfo 文件信息 */ this.getLinkByIframe = async function (urlPathName, fileInfo) { log.info([urlPathName, fileInfo]); let iFrameUrl = that.handleUrl.default(urlPathName); let getResp = await httpx.get({ url: iFrameUrl, headers: { Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "User-Agent": utils.getRandomPCUA(), Referer: that.handleUrl.default(that.shareCode), }, }); if (!getResp.status) { return; } let respData = getResp.data; log.info(respData); let pageText = respData.responseText; let aihidcms = pageText.match(/var[\s]*aihidcms[\s]*=[\s]*'(.*)';/i); let ciucjdsdc = pageText.match( /var[\s]*ciucjdsdc[\s]*=[\s]*'(.*)';/i ); let ajaxdata = pageText.match(/var[\s]*ajaxdata[\s]*=[\s]*'(.+)';/i); let sign = pageText.match(/'sign':[\s]*'(.+)',/i); if (!aihidcms) { Qmsg.error("ajaxm.php请求参数 websignkey 获取失败"); return; } else { aihidcms = aihidcms[aihidcms.length - 1]; } if (!ciucjdsdc) { Qmsg.error("ajaxm.php请求参数 websign 获取失败"); return; } else { ciucjdsdc = ciucjdsdc[ciucjdsdc.length - 1]; } if (!ajaxdata) { Qmsg.error("ajaxm.php请求参数 signs 获取失败"); return; } else { ajaxdata = ajaxdata[ajaxdata.length - 1]; } if (!sign) { Qmsg.error("ajaxm.php请求参数 sign 获取失败"); return; } else { sign = sign[sign.length - 1]; } let postData = `action=downprocess&signs=${ajaxdata}&sign=${sign}&websign=${ciucjdsdc}&ves=1&websignkey=${aihidcms}`; log.success("ajaxm.php的请求参数-> " + postData); let postResp = await httpx.post({ url: that.handleUrl.default("ajaxm.php"), headers: { Accept: "application/json, text/javascript, */*", "Content-Type": "application/x-www-form-urlencoded", Referer: that.handleUrl.default(that.shareCode), "User-Agent": utils.getRandomPCUA(), }, data: postData, }); if (!postResp.status) { return; } let postRespData = postResp.data; log.info(postRespData); let jsonData = utils.toJSON(postRespData.responseText); let downloadUrl = `${jsonData["dom"]}/file/${jsonData["url"]}`; let zt = jsonData["zt"]; log.success(["直链", downloadUrl]); if ("密码不正确".indexOf(jsonData["inf"]) != -1) { Qmsg.error("密码不正确!"); NetDiskUI.newAccessCodeView( undefined, "lanzou", that.netDiskIndex, that.shareCode, (userInputAccessCode) => { that.default( that.netDiskIndex, that.shareCode, userInputAccessCode ); } ); } else { fileInfo.fileName = utils.isNotNull(jsonData["inf"]) ? jsonData["inf"] : fileInfo.fileName; downloadUrl = await NetDiskParse.getRedirectFinalUrl( downloadUrl, utils.getRandomAndroidUA() ); log.info(downloadUrl); return downloadUrl; } }; /** * 多文件获取 */ this.getMoreFile = async function () { let getResp = await httpx.get({ url: that.handleUrl.default(that.shareCode), headers: { Accept: "*/*", "User-Agent": utils.getRandomAndroidUA(), Referer: that.handleUrl.default(that.shareCode), }, }); 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: that.handleUrl.default("filemoreajax.php"), responseType: "json", headers: { "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", "User-Agent": utils.getRandomAndroidUA(), Referer: that.handleUrl.default(that.shareCode), }, 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) { let QmsgLoading = Qmsg.loading("获取文件夹成功,解析文件直链中..."); /* 获取多文件的数组信息 */ let folder = json_data["text"]; /** * 弹出内容 * @type {PopsFolderDataConfig[]} */ let folderList = []; log.info(`本链接一共${folder.length}个文件`); for (let index = 0; index < folder.length; index++) { let folderInfo = folder[index]; let fileShareCode = folderInfo["id"]; let fileName = folderInfo["name_all"]; let fileSize = folderInfo["size"]; let fileType = folderInfo["icon"]; let uploadTime = folderInfo["time"]; folderList.push({ fileName: fileName, fileSize: fileSize, fileType: fileType, createTime: uploadTime, latestTime: uploadTime, isFolder: false, index: 0, async clickEvent() { let folderDownloadInfo = await that.parseMoreFile( fileShareCode, fileName, fileSize, uploadTime ); /* 成功获取下载信息 */ if (folderDownloadInfo.success) { return { autoDownload: true, mode: "aBlank", url: folderDownloadInfo.downloadUrl, }; } else { log.error(["获取下载信息失败:", folderDownloadInfo]); Qmsg.error(folderDownloadInfo.msg); } }, }); } QmsgLoading.close(); 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-vip * @param {string} paramShareCode 解析多文件获取的shareCode * @param {string} fileName 文件名 * @param {string} fileSize 文件大小 * @param {string} fileUploadTime 文件上传时间 * @returns {Promise<{ * success :boolean, * fileName: string, * fileSize: string, * fileUploadTime: string, * downloadUrl: ?string, * msg: string, * }>} */ this.parseMoreFile = async function ( paramShareCode, fileName, fileSize, fileUploadTime ) { /* 根据获取到的json中多文件链接来获取单文件直链 */ let getResp = await httpx.get({ url: that.handleUrl.default(paramShareCode), headers: { Accept: "*/*", "User-Agent": utils.getRandomPCUA(), Referer: that.handleUrl.default(that.shareCode), }, }); log.info(getResp); if (!getResp.status) { return { success: false, fileName: fileName, fileSize: fileSize, fileUploadTime: fileUploadTime, msg: `解析失败,${getResp.msg}`, downloadUrl: null, }; } let respData = getResp.data; let pageText = respData.responseText; let pageDOM = DOMUtils.parseHTML(pageText, true, true); let pageIframeElement = pageDOM.querySelector('iframe[class^="ifr"]') || pageDOM.querySelector('iframe[class^="n_downlink"]'); if (!pageIframeElement) { return { success: false, fileName: fileName, fileSize: fileSize, fileUploadTime: fileUploadTime, msg: `解析iframe链接失败`, downloadUrl: null, }; } let iframeUrl = pageIframeElement.getAttribute("src"); log.error(["该链接需要重新通过iframe地址访问获取信息", iframeUrl]); Qmsg.info("正在请求下载信息"); let downloadUrl = await that.getLinkByIframe(iframeUrl, { fileName, fileSize, fileUploadTime, }); if (downloadUrl) { downloadUrl = NetDiskFilterScheme.handleUrl( "lanzou-static-scheme-enable", "lanzou-static-scheme-forward", downloadUrl ); return { success: true, fileName: fileName, fileSize: fileSize, fileUploadTime: fileUploadTime, msg: "success", downloadUrl: downloadUrl, }; } else { return { success: false, fileName: fileName, fileSize: fileSize, fileUploadTime: fileUploadTime, msg: `获取下载链接失败`, downloadUrl: null, }; } }; return this; }, /** * 天翼云 * @constructor * @returns {object} */ tianyiyun: function () { let that = this; /** * 所在规则的下标 */ this.netDiskIndex = 0; /** * 分享码 */ this.shareCode = ""; /** * 提取码 */ this.accessCode = ""; let shareId = null; /* 猜测1是有密码,2是无密码 */ let shareMode = 1; this.code = { ShareNotFound: "抱歉,您访问的页面地址有误,或者该页面不存在。", ShareAuditNotPass: "抱歉,该内容审核不通过", FileNotFound: "抱歉,文件不存在", ShareExpiredError: "抱歉,您访问的页面地址有误,或者该页面不存在", ShareAuditWaiting: "抱歉,该链接处于审核中", ShareInfoNotFound: "抱歉,您访问的页面地址有误,或者该页面不存在", FileTooLarge: "抱歉,文件太大,不支持下载", InvalidSessionKey: "天翼云PC端Cookie未生成,是否前去登录?<br /> (注意,需要当前浏览器的UA切换成PC且在登录后要等待进入个人云空间后生成Cookie,不是手机端浏览的个人云空间,那样生成的Cookie无法使用)", }; /** * * @param {number} netDiskIndex * @param {string} shareCode * @param {string} accessCode * @returns */ this.default = async function (netDiskIndex, shareCode, accessCode) { log.info([netDiskIndex, shareCode, accessCode]); that.netDiskIndex = netDiskIndex; that.shareCode = shareCode; that.accessCode = accessCode; let shareInfoData = await that.getShareInfoByCodeV2(shareCode); if (!shareInfoData) { return; } log.info(["解析的JSON信息", shareInfoData]); if ( shareInfoData["needAccessCode"] && utils.isNull(that.accessCode) ) { Qmsg.error("密码不正确!"); NetDiskUI.newAccessCodeView( undefined, "tianyiyun", that.netDiskIndex, that.shareCode, (userInputAccessCode) => { that.default( that.netDiskIndex, that.shareCode, userInputAccessCode ); } ); return; } if ("shareId" in shareInfoData) { shareId = shareInfoData["shareId"]; } else { shareId = await that.getShareId(shareCode, accessCode); } if ("shareMode" in shareInfoData) { shareMode = shareInfoData["shareMode"]; } if (shareId == null) { return; } if (shareInfoData.isFolder) { /* 多文件 */ Qmsg.info("正在递归文件"); let QmsgLoading = Qmsg.loading(`正在解析多文件中,请稍后...`); let fileId = shareInfoData["fileId"]; let folderInfo = await that.listShareDir( shareCode, accessCode, undefined, undefined, fileId, fileId, undefined, shareId, undefined, undefined, undefined, undefined ); if (!folderInfo) { QmsgLoading.close(); return; } let folderInfoList = that.getFolderInfo( shareCode, accessCode, folderInfo, 0 ); QmsgLoading.close(); log.info("递归完毕"); NetDiskUI.staticView.moreFile("天翼云多文件直链", folderInfoList); return; } else { /* 单文件 */ let downloadUrl = await that.getDownloadUrl( that.shareCode, that.accessCode, shareInfoData.fileId, shareId ); if (downloadUrl) { downloadUrl = NetDiskFilterScheme.handleUrl( "tianyiyun-scheme-enable", "tianyiyun-scheme-forward", downloadUrl ); NetDiskUI.staticView.oneFile({ title: "天翼云单文件直链", fileName: shareInfoData.fileName, fileSize: utils.formatByteToSize(shareInfoData.fileSize), downloadUrl: downloadUrl, fileUploadTime: shareInfoData.fileCreateDate, fileLatestTime: shareInfoData.fileLastOpTime, }); } } }; /** * 获取当前登录用户的信息 * @returns {Promise<?{ * encryptAccount: string, * icon: string, * nickname: string, * res_code: string, * res_message: string, * sessionKey: string, * userAccount: string * }>} */ this.getUserBriefInfo = async function (shareCode) { let getResp = await httpx.get( "https://cloud.189.cn/api/portal/v2/getUserBriefInfo.action", { headers: { Accept: "application/json;charset=UTF-8", Referer: "https://cloud.189.cn/web/share?code=" + shareCode, "User-Agent": utils.getRandomPCUA(), }, onerror() {}, } ); log.info(getResp); if (!getResp.status) { let errorResultJSON = utils.toJSON(getResp.data.responseText); if (errorResultJSON["res_code"] in that.code) { Qmsg.error(that.code[errorResultJSON["res_code"]]); } else { Qmsg.error("请求异常"); } return; } let data = utils.toJSON(getResp.data.responseText); if (data["res_code"] === 0) { return data; } }; /** * 获取分享信息 * @param {string} shareCode * @returns */ this.getShareInfoByCodeV2 = async function (shareCode) { let postResp = await httpx.post({ url: "https://cloud.189.cn/api/open/share/getShareInfoByCodeV2.action", data: `shareCode=${shareCode}`, headers: { Accept: "application/json;charset=UTF-8", "Content-Type": "application/x-www-form-urlencoded", "User-Agent": utils.getRandomPCUA(), "Sign-Type": 1, Referer: "https://cloud.189.cn/web/share?code=" + shareCode, Origin: "https://cloud.189.cn", }, onerror() {}, }); if (!postResp.status) { let errorData = utils.toJSON(postResp.data.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 data = utils.toJSON(postData.responseText); if (data["res_code"] == 0) { return data; } else { if (that.code.hasOwnProperty(data["res_code"])) { Qmsg.error(that.code[data["res_code"]]); } else { Qmsg.error("获取FileId失败"); } } }; /** * 获取shareId * @returns {Promise<number|undefined>} */ this.getShareId = async function (shareCode, accessCode) { let getResp = await httpx.get({ url: `https://cloud.189.cn/api/open/share/checkAccessCode.action?shareCode=${shareCode}&accessCode=${accessCode}`, headers: { Accept: "application/json;charset=UTF-8", "Cache-Control": "no-cache", "User-Agent": utils.getRandomPCUA(), "Sign-Type": 1, Referer: `https://cloud.189.cn/web/share?code=${shareCode}`, }, responseType: "json", }); if (!getResp.status) { return; } let respData = getResp.data; log.info(respData); let data = utils.toJSON(respData.responseText); if (data["res_code"] === 0 && "shareId" in data) { return data["shareId"]; } else { Qmsg.error("获取shareId失败"); log.info(data); } }; /** * 获取随机noCache * @returns {string} */ this.getNoCacheValue = function () { let result = ""; for (let index = 0; index < 17; index++) { result += utils.getRandomValue(1, 9); } return "0." + result; }; /** * 获取下载链接 * @param {string} shareCode * @param {string} accessCode * @param {number} fileId * @param {number} shareId * @returns {Promise} */ this.getDownloadUrl = async function ( shareCode, accessCode, fileId, shareId ) { let getResp = await httpx.get({ url: `https://cloud.189.cn/api/open/file/getFileDownloadUrl.action?fileId=${fileId}&dt=1&shareId=${shareId}`, headers: { Accept: "application/json;charset=UTF-8", "Cache-Control": "no-cache", "User-Agent": utils.getRandomPCUA(), Referer: `https://cloud.189.cn/web/share?code=${shareCode}`, "Sign-Type": 1, }, responseType: "json", onerror() {}, }); log.info(getResp); if (!getResp.status) { let errorResultJSON = utils.toJSON(getResp.data.responseText); if (errorResultJSON["errorCode"] === "InvalidSessionKey") { that.gotoLogin(that.code["InvalidSessionKey"]); } else if (errorResultJSON["res_code"] in that.code) { Qmsg.error(that.code[errorResultJSON["res_code"]]); } else { Qmsg.error("请求异常"); } return; } let respData = getResp.data; let data = utils.toJSON(respData.responseText); log.info(data); if (data["res_code"] === 0) { return data["fileDownloadUrl"]; } else if ( "InvalidSessionKey" === data["res_code"] || "InvalidSessionKey" === data["errorCode"] ) { that.gotoLogin(that.code["InvalidSessionKey"]); } else if (that.code.hasOwnProperty(data["res_code"])) { Qmsg.error(that.code[data["res_code"]]); } else { Qmsg.error("请求失败"); log.error(respData); } }; /** * 天翼云登录弹窗 * @param {string} text 弹窗的显示的内容 */ this.gotoLogin = function (text = "") { NetDiskPops.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" ); }, }, }, }, NetDiskUI.popsStyle.tianYiYunLoginTip ); }; /** * 解析文件夹信息 */ this.listShareDir = async function ( shareCode, accessCode, pageNum = 1, pageSize = 60, fileId, shareDirFileId, isFolder = true, shareId, iconOption = 5, orderBy = "lastOpTime", descending = true ) { /* Sessionkey: Sessionkey */ let getResp = await httpx.get( `https://cloud.189.cn/api/open/share/listShareDir.action?pageNum=${pageNum}&pageSize=${pageSize}&fileId=${fileId}&shareDirFileId=${shareDirFileId}&isFolder=${isFolder}&shareId=${shareId}&shareMode=${shareMode}&iconOption=${iconOption}&orderBy=${orderBy}&descending=${descending}&accessCode=${accessCode}`, { headers: { Accept: "application/json;charset=UTF-8", Referer: `https://cloud.189.cn/web/share?code=${shareCode}`, "Sign-Type": 1, "User-Agent": utils.getRandomPCUA(), }, responseType: "json", onerror() {}, } ); if (!getResp.status) { let errorData = utils.toJSON(getResp.data.responseText); log.error(["解析文件夹信息失败", errorData]); if (errorData["res_code"] in that.code) { Qmsg.error(that.code[errorData["res_code"]]); } else if ("res_message" in errorData) { Qmsg.error(errorData["res_message"]); } else { Qmsg.error("解析文件夹信息失败"); } return; } let getData = getResp.data; log.info(getData); let data = utils.toJSON(getData.responseText); if (data["res_code"] == 0) { return data["fileListAO"]; } else { if (that.code.hasOwnProperty(data["res_code"])) { Qmsg.error(that.code[data["res_code"]]); } else { Qmsg.error("获取FileId失败"); } } }; /** * 获取直链弹窗的文件夹信息 */ this.getFolderInfo = function ( shareCode, accessCode, dirInfo, index = 0 ) { /** * @type {PopsFolderDataConfig[]} */ let folderInfoList = []; let tempFolderInfoList = []; let tempFolderFileInfoList = []; /* 文件夹 */ dirInfo["folderList"].forEach((folderInfo) => { folderInfoList.push({ fileName: folderInfo["name"], fileSize: 0, fileType: "", createTime: utils.formatToTimeStamp(folderInfo["createDate"]), latestTime: utils.formatToTimeStamp(folderInfo["lastOpTime"]), isFolder: true, index: index, async clickEvent() { let _folderInfo_ = await that.listShareDir( shareCode, accessCode, 1, 100, folderInfo["id"], folderInfo["id"], undefined, shareId, undefined, undefined, undefined, undefined ); if (!_folderInfo_) { return []; } return that.getFolderInfo( shareCode, accessCode, _folderInfo_, index + 1 ); }, }); }); /* 文件 */ dirInfo["fileList"].forEach((fileInfo) => { folderInfoList.push({ fileName: fileInfo["name"], fileSize: fileInfo["size"], fileType: "", createTime: utils.formatToTimeStamp(fileInfo["createDate"]), latestTime: utils.formatToTimeStamp(fileInfo["lastOpTime"]), isFolder: false, index: index, async clickEvent() { let downloadUrl = await that.getDownloadUrl( shareCode, accessCode, fileInfo["id"], shareId ); if (downloadUrl) { downloadUrl = NetDiskFilterScheme.handleUrl( "tianyiyun-scheme-enable", "tianyiyun-scheme-forward", downloadUrl ); return { autoDownload: true, mode: "aBlank", url: downloadUrl, }; } }, }); }); tempFolderInfoList.sort((a, b) => a["fileName"].localeCompare(b["fileName"]) ); tempFolderFileInfoList.sort((a, b) => a["fileName"].localeCompare(b["fileName"]) ); folderInfoList = folderInfoList.concat(tempFolderInfoList); folderInfoList = folderInfoList.concat(tempFolderFileInfoList); log.info(["getFolderInfo", folderInfoList]); return folderInfoList; }; return this; }, /** * 文叔叔 * @constructor * @returns {object} */ wenshushu: function () { let that = this; /** * 所在规则的下标 */ this.netDiskIndex = 0; /** * 分享码 */ this.shareCode = ""; /** * 提取码 */ this.accessCode = ""; /** * 用于header头x-token * @type {string} */ let token = null; this.code = { 1004: "no token", 1008: "您没有权限访问", 1013: "糟糕,此任务已过期销毁,下次要记得续期", 1066: "对方设置的下载 / 预览次数已用完", 1088: "糟糕,您访问的页面不存在", }; this.default = async function (netDiskIndex, shareCode, accessCode) { log.info([netDiskIndex, shareCode, accessCode]); that.netDiskIndex = netDiskIndex; that.shareCode = shareCode; that.accessCode = accessCode; Qmsg.info("正在请求直链中..."); let token = await this.getWssToken(); if (!token) { return; } let pidInfo = await this.getPid(); if (!pidInfo) { return; } await this.getFileNList(pidInfo.bid, pidInfo.pid); }; /** * 获取token * wss:xxxxxx * @returns {Promise<string>} */ this.getWssToken = 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: "https://www.wenshushu.cn/f/" + that.shareCode, }, }); log.success(postResp); if (!postResp.status) { return; } let data = utils.toJSON(postResp.data.responseText); if (data["code"] === 0) { token = data["data"]["token"]; return data["data"]["token"]; } else if (data["code"] in that.code) { Qmsg.error(that.code[data["code"]]); } else { Qmsg.error("获取wss失败"); } }; /** * 获取pid * @returns {Promise<{bid:string,pid:string}> } */ 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: "https://www.wenshushu.cn/f/" + that.shareCode, "x-token": token, }, }); log.success(postResp); if (!postResp.status) { return; } let respData = postResp.data; let data = utils.toJSON(respData.responseText); if (data["code"] === 0) { return { bid: data["data"]["boxid"], pid: data["data"]["ufileid"], }; } else if (data["code"] in that.code) { Qmsg.error(that.code[data["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": utils.getRandomAndroidUA(), Referer: "https://www.wenshushu.cn/f/" + that.shareCode, "x-token": 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: "https://www.wenshushu.cn/f/" + that.shareCode, "x-token": 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.netDiskIndex = 0; /** * 分享码 */ this.shareCode = ""; /** * 提取码 */ this.accessCode = ""; 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("正在递归文件"); let QmsgLoading = Qmsg.loading(`正在解析多文件中,请稍后...`); let folderInfoList = that.getFolderInfo(infoLists, 0); QmsgLoading.close(); log.info("递归完毕"); NetDiskUI.staticView.moreFile("123盘多文件直链", folderInfoList); } }; /** * 校验链接有效性 * @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<?{ * Category: number, * ContentType: string, * CreateAt: number, * DownloadUrl: string, * Etag: string, * FileId: number, * FileName: string, * ParentFileId: number, * PunishFlag: number, * S3KeyFlag: number, * Size: number, * Status: number, * StorageNode: string, * Type: 0|1, * UpdateAt: string, * }[]>} */ 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 {Promise<?{ * Category: number, * ContentType: string, * CreateAt: number, * DownloadUrl: string, * Etag: string, * FileId: number, * FileName: string, * ParentFileId: number, * PunishFlag: number, * S3KeyFlag: number, * Size: number, * Status: number, * StorageNode: string, * Type: 0|1, * UpdateAt: string, * }[]>} */ 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 {{ * Category: number, * ContentType: string, * CreateAt: number, * DownloadUrl: string, * Etag: string, * FileId: number, * FileName: string, * ParentFileId: number, * PunishFlag: number, * S3KeyFlag: number, * Size: number, * Status: number, * StorageNode: string, * Type: 0|1, * UpdateAt: string, * }[]} infoList * @returns {Promise<{ * fileName: string, * fileSize: string|number, * fileType: ?string, * createTime: ?string, * latestTime: ?string, * isFolder: boolean, * index: ?number, * clickCallBack: ?(event:Event,_config_: object)=>{} * }[]>} */ this.getFolderInfo = function (infoList, index) { let folderInfoList = []; let tempFolderInfoList = []; /** * @type {PopsFolderDataConfig[]} */ let tempFolderFileInfoList = []; infoList.forEach((item) => { if (item.Type) { /* 文件夹 */ tempFolderInfoList.push({ fileName: item.FileName, fileSize: 0, fileType: "", createTime: new Date(item.CreateAt).getTime(), latestTime: new Date(item.UpdateAt).getTime(), isFolder: true, index: index, async clickEvent() { let resultFileInfoList = await that.getFilesByRec( item["FileId"] ); if (resultFileInfoList) { return that.getFolderInfo(resultFileInfoList, index + 1); } else { return []; } }, }); } else { /* 文件 */ tempFolderFileInfoList.push({ fileName: item.FileName, fileSize: item.Size, fileType: "", createTime: new Date(item.CreateAt).getTime(), latestTime: new Date(item.UpdateAt).getTime(), isFolder: false, index: index, async clickEvent() { if (item.Status == 104) { Qmsg.error("文件已失效"); } else if (!Boolean(item.DownloadUrl)) { let downloadInfo = await that.getFileDownloadInfo( item["Etag"], item["FileId"], item["S3KeyFlag"], that.shareCode, item["Size"] ); if (downloadInfo && downloadInfo["code"] === 0) { return { url: downloadInfo["data"]["DownloadURL"], autoDownload: true, mode: "aBlank", }; } else if (downloadInfo && downloadInfo["code"] === 401) { Qmsg.error("请登录后下载"); } else { Qmsg.error("获取下载链接失败"); } } else { return { url: NetDiskFilterScheme.handleUrl( "_123pan-static-scheme-enable", "_123pan-static-scheme-forward", item.DownloadUrl ), autoDownload: true, mode: "aBlank", }; } }, }); } }); tempFolderInfoList.sort((a, b) => a["fileName"].localeCompare(b["fileName"]) ); tempFolderFileInfoList.sort((a, b) => a["fileName"].localeCompare(b["fileName"]) ); folderInfoList = folderInfoList.concat(tempFolderInfoList); folderInfoList = folderInfoList.concat(tempFolderFileInfoList); return folderInfoList; }; /** * 获取单文件下载链接 * 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", headers: { "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.status !== 210) { /* 很奇怪,123盘返回的状态码是210 */ return newDecodeUrl; } let respData = getResp.data; 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.netDiskIndex = 0; /** * 分享码 */ this.shareCode = ""; /** * 提取码 */ this.accessCode = ""; 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"]) { /* 是文件夹 */ let Qmsg_loading = Qmsg.loading("正在遍历多文件信息..."); let folderInfo = await that.getFolderInfo(downloadParams["hash"]); if (!folderInfo) { Qmsg_loading.close(); return; } let newFolderInfoList = that.parseMoreFile( folderInfo, downloadParams["hash"], downloadParams["name"] ); Qmsg_loading.close(); /* 坚果云盘没有上传时间信息(暂时是这样的) */ NetDiskUI.staticView.moreFile( "坚果云多文件直链", newFolderInfoList ); } 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 {{ * mtime: number, * relPath: string, * size: number, * tblUri: ?string, * type: "file"|string, * }[]} folderInfo * @param {string} hash 文件hash值 * @param {string} fileName 文件名 * @returns {{ * fileName: string, * fileSize: string|number, * fileType: ?string, * createTime: ?string, * latestTime: ?string, * isFolder: boolean, * index: ?number, * clickCallBack: ?(event:Event,_config_: object)=>{} * }[]} */ this.parseMoreFile = function (folderInfo, hash = "", fileName = "") { log.info(["解析多文件信息", folderInfo]); /** * @type {PopsFolderDataConfig[]} */ let folderInfoList = []; folderInfo.forEach((item) => { let fileName = item.relPath; if (fileName.startsWith("/")) { fileName = fileName.replace(/^\//, ""); } folderInfoList.push({ fileName: fileName, fileSize: item["size"], fileType: "", createTime: item.mtime, latestTime: item.mtime, isFolder: false, index: 0, async clickEvent() { Qmsg.info("正在获取下载链接..."); let downloadUrl = await that.getDirLink( hash, fileName, item["relPath"] ); if (!downloadUrl) { return; } Qmsg.success("获取成功!"); downloadUrl = NetDiskFilterScheme.handleUrl( "jianguoyun-static-scheme-enable", "jianguoyun-static-scheme-forward", downloadUrl ); log.info(downloadUrl); return { autoDownload: true, mode: "aBlank", url: downloadUrl, }; }, }); }); return folderInfoList; }; /** * 获取下载链接所需要的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?.responseText)) { let errorData = utils.toJSON(getResp.data.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?.responseText)) { let errorData = utils.toJSON(getResp.data.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 () { NetDiskPops.confirm( { 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" ); }, }, }, }, NetDiskUI.popsStyle.jianGuoYunLoginTip ); }; return this; }, /** * 奶牛快传 * 感谢:https://github.com/qaiu/netdisk-fast-download * @constructor * @returns {object} */ nainiu: function () { let that = this; /** * 所在规则的下标 */ this.netDiskIndex = 0; /** * 分享码 */ this.shareCode = ""; /** * 提取码 */ this.accessCode = ""; const OK_CODE = "0000"; 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( that.shareCode, that.accessCode ); if (!checkLinkValidityInfo) { return; } if (checkLinkValidityInfo.isFolder) { /* 多文件 */ Qmsg.info("正在递归文件"); let QmsgLoading = Qmsg.loading(`正在解析多文件中,请稍后...`); let firstFolderInfo = await that.getShareFolder( checkLinkValidityInfo["data"]["guid"] ); if (!firstFolderInfo) { QmsgLoading.close(); return; } let firstFileInfo = await that.getShareFiles( checkLinkValidityInfo["data"]["guid"] ); if (!firstFileInfo) { QmsgLoading.close(); return; } let folderInfoList = that.getFolderInfo( checkLinkValidityInfo["data"]["guid"], firstFolderInfo, firstFileInfo, 0 ); QmsgLoading.close(); log.info("递归完毕"); NetDiskUI.staticView.moreFile("奶牛快传多文件直链", folderInfoList); } else { /* 单文件 */ let downloadUrl = null; if (checkLinkValidityInfo["zipDownload"]) { downloadUrl = await that.getZipFileDownloadUrl( that.shareCode, checkLinkValidityInfo["guid"], checkLinkValidityInfo["fileName"] ); } else { downloadUrl = await that.getDownloadUrl( that.shareCode, 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_) => { that.downloadFile( checkLinkValidityInfo["fileName"], downloadUrl ); }, }); } }; /** * 校验链接有效性并解析获取信息 * @param {string} shareCode * @param {string} accessCode * @param {boolean|object} */ this.checkLinkValidity = async function (shareCode, accessCode) { let resultJSON = await that.getShareByUniqueUrl(shareCode); if (!resultJSON) { return false; } let code = resultJSON["code"]; let message = resultJSON["message"]; if (code !== OK_CODE) { Qmsg.error(message); return false; } else { let needPassword = resultJSON["data"]["needPassword"]; let zipDownload = resultJSON["data"]["zipDownload"]; if (needPassword && utils.isNull(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("该链接为zip单文件"); 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.success("该链接为文件夹类型"); return { isFolder: true, guid: resultJSON["data"]["guid"], firstFolder: resultJSON["data"]["firstFolder"], data: resultJSON["data"], }; } 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"] ), }; } }; /** * 获取直链弹窗的文件夹信息 * @returns */ this.getFolderInfo = function ( transferGuid, shareFolderInfoList, shareFileInfoList, index = 0 ) { let folderInfoList = []; let tempFolderInfoList = []; let tempFolderFileInfoList = []; /* 文件夹 */ shareFolderInfoList.forEach((folderInfo) => { folderInfoList.push({ fileName: folderInfo["title"], fileSize: 0, fileType: "", createTime: folderInfo["created_at"], latestTime: folderInfo["updated_at"], isFolder: true, index: index, async clickEvent() { if ( !folderInfo["child_folder_count"] && !folderInfo["content_count"] ) { /* 里面没有文件夹和文件 */ return []; } let childFolderInfo = await that.getShareFolder( transferGuid, folderInfo["id"] ); if (!childFolderInfo) { return []; } let childFileInfo = await that.getShareFiles( transferGuid, folderInfo["id"] ); if (!childFileInfo) { return []; } let folderInfoList = that.getFolderInfo( transferGuid, childFolderInfo, childFileInfo, index + 1 ); return folderInfoList; }, }); }); /* 文件 */ shareFileInfoList.forEach((fileInfo) => { let fileName = fileInfo["file_info"]["title"]; let fileType = fileInfo["file_info"]["format"] ?? ""; if (Boolean(fileType)) { fileName = fileName + "." + fileType; } folderInfoList.push({ fileName: fileName, fileSize: fileInfo["file_info"]["size"], fileType: fileType, createTime: fileInfo["created_at"], latestTime: fileInfo["updated_at"], isFolder: false, index: index, async clickEvent() { let downloadUrl = await that.getDownloadUrl( that.shareCode, transferGuid, fileInfo["id"] ); if (!downloadUrl) { return; } downloadUrl = NetDiskFilterScheme.handleUrl( "nainiu-static-scheme-enable", "nainiu-static-scheme-forward", downloadUrl ); that.downloadFile(fileName, downloadUrl); }, }); }); tempFolderInfoList.sort((a, b) => a["fileName"].localeCompare(b["fileName"]) ); tempFolderFileInfoList.sort((a, b) => a["fileName"].localeCompare(b["fileName"]) ); folderInfoList = folderInfoList.concat(tempFolderInfoList); folderInfoList = folderInfoList.concat(tempFolderFileInfoList); log.info(["getFolderInfo", folderInfoList]); return folderInfoList; }; /** * 多文件解析 * @param {string} shareCode * @param {string} accessCode */ this.parseMoreFile = async function (shareCode, accessCode) {}; /** * 获取文件夹信息 * @param {string} transferGuid * @param {number} folderId * @param {number} page * @param {number} size * @returns {Promise<object|undefined[]>} */ this.getShareFolder = async function ( transferGuid, folderId = "", page = 0, size = 100 ) { let getResp = await httpx.get( `https://cowtransfer.com/core/api/transfer/share/folders?transferGuid=${transferGuid}&folderId=${folderId}&page=${page}&size=${size}`, { headers: { Accept: "application/json", "User-Agent": utils.getRandomPCUA(), Referer: "https://cowtransfer.com/", }, } ); log.success(getResp); if (!getResp.status) { return; } let data = utils.toJSON(getResp.data.responseText); if (data.code !== OK_CODE) { Qmsg.error(data["message"]); return; } let folders = data["data"]["folders"]; if (!Array.isArray(folders)) { Qmsg.error("data.folders不是数组"); return; } return folders; }; /** * 获取文件信息 * @param {string} transferGuid * @param {number} folderId * @param {number} page * @param {number} size * @param {boolean} subContent * @returns {Promise<object|undefined[]>} */ this.getShareFiles = async function ( transferGuid, folderId = "", page = 0, size = 20, subContent = false ) { let getResp = await httpx.get( `https://cowtransfer.com/core/api/transfer/share/files?transferGuid=${transferGuid}&folderId=${folderId}&page=${page}&size=${size}&subContent=${subContent}`, { headers: { Accept: "application/json", "User-Agent": utils.getRandomPCUA(), Referer: "https://cowtransfer.com/", }, } ); log.success(getResp); if (!getResp.status) { return; } let data = utils.toJSON(getResp.data.responseText); if (data.code !== OK_CODE) { Qmsg.error(data["message"]); return; } let files = data["data"]["files"]; if (!Array.isArray(files)) { Qmsg.error("data.files不是数组"); return; } return files; }; /** * 获取分享信息 * @param {string} shareCode * @returns {undefined| { * code: string, * message: string, * data: {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.getShareByUniqueUrl = async function (shareCode) { let url = `https://cowtransfer.com/core/api/transfer/share?uniqueUrl=${shareCode}`; let getResp = await httpx.get({ url: url, headers: { "User-Agent": utils.getRandomPCUA(), Referer: "https://cowtransfer.com/s/" + shareCode, }, }); log.info(getResp); if (!getResp.status) { return; } let respData = getResp.data; let resultJSON = utils.toJSON(respData.responseText); log.info(["转换的JSON", resultJSON]); return resultJSON; }; /** * 获取下载链接 * @param {string} shareCode * @param {string} guid * @param {string} id * @returns {string|undefined} */ this.getDownloadUrl = async function (shareCode, 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/s/" + shareCode, }, }); log.info(getResp); if (!getResp.status) { return; } let respData = getResp.data; let resultJSON = utils.toJSON(respData.responseText); log.info(["转换的JSON", resultJSON]); if (resultJSON["code"] === OK_CODE) { return resultJSON["data"]["downloadUrl"]; } else { Qmsg.error(`奶牛快传-获取直链:${resultJSON["message"]}`); return; } }; /** * 获取zip文件的下载链接 * @param {string} shareCode * @param {string} guid * @param {string} title 标题 * @returns {string|undefined} */ this.getZipFileDownloadUrl = async function ( shareCode, 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/s/" + shareCode, }, }); log.info(getResp); if (!getResp.status) { return; } let respData = getResp.data; let resultJSON = utils.toJSON(respData.responseText); log.info(["转换的JSON", resultJSON]); if (resultJSON["code"] === OK_CODE) { return resultJSON["data"]["downloadUrl"]; } else { Qmsg.error(`奶牛快传-获取直链:${resultJSON["message"]}`); return; } }; /** * 下载文件 * @param {string} fileName 文件名 * @param {string} fileDownloadUrl 下载地址 */ this.downloadFile = async function (fileName, fileDownloadUrl) { log.info(["下载文件:", fileName, fileDownloadUrl]); Qmsg.info(`调用【GM_download】下载:${fileName}`); if (typeof GM_download === "undefined") { Qmsg.error("当前脚本环境缺失API 【GM_download】"); return; } let abortDownload = null; let downloadingQmsg = Qmsg.loading("下载中...", { showClose: true, onClose() { if (typeof abortDownload === "function") { abortDownload(); } }, }); let GM_download_Result = GM_download({ url: fileDownloadUrl, name: fileName, headers: { Referer: "https://cowtransfer.com/s/" + that.shareCode, }, onload() { downloadingQmsg.close(); Qmsg.success(`下载 ${fileName} 已完成`); }, onprogress(details) { if ( typeof details === "object" && "loaded" in details && "total" in details ) { let progressNum = details.loaded / details.total; let formatProgressNum = (progressNum * 100).toFixed(2); downloadingQmsg.setText(`下载中...${formatProgressNum}%`); } }, onerror(error) { downloadingQmsg.close(); log.error(["下载失败error👉", error]); if (typeof error === "object" && error["error"]) { Qmsg.error( `下载 ${fileName} 失败或已取消 原因:${error["error"]}`, { timeout: 6000, } ); } else { Qmsg.error(`下载 ${fileName} 失败或已取消`); } }, ontimeout() { downloadingQmsg.close(); Qmsg.error(`下载 ${fileName} 请求超时`); }, }); if ( typeof GM_download_Result === "object" && "abort" in GM_download_Result ) { abortDownload = GM_download_Result["abort"]; } }; return this; }, /** * UC网盘 * @constructor * @returns {object} */ uc: function () { let that = this; /** * 所在规则的下标 */ this.netDiskIndex = 0; /** * 分享码 */ this.shareCode = ""; /** * 提取码 */ this.accessCode = ""; /** * 入口 * @param {number} netDiskIndex 网盘名称索引下标 * @param {string} shareCode * @param {string} accessCode * @returns */ this.default = async function (netDiskIndex, shareCode, accessCode) { log.info([netDiskIndex, shareCode, accessCode]); that.netDiskIndex = netDiskIndex; that.shareCode = shareCode; that.accessCode = accessCode; Qmsg.info("检查是否已登录UC网盘"); let loginStatus = await that.isLogin(); if (!Boolean(loginStatus)) { that.gotoLogin( "检测到尚未登录UC网盘,是否前去登录?<br /> (注意,需要当前浏览器的UA切换成PC才有登录选项)" ); return; } let stoken = await that.getStoken(that.shareCode, that.accessCode); if (!stoken) { return; } let detail = await that.getDetail( that.shareCode, that.accessCode, stoken ); if (!detail) { Qmsg.error("UC网盘:获取detail失败"); return; } if ( detail.length === 1 && detail[0].dir == false && detail[0].file_type === 1 ) { let oneFileDetail = detail[0]; let oneFileDownloadDetail = await that.getDownload( that.shareCode, stoken, oneFileDetail.fid, oneFileDetail.share_fid_token ); if (!oneFileDownloadDetail) { return; } if (!oneFileDownloadDetail[0].download_url) { Qmsg.error("获取download_url失败"); return; } NetDiskUI.staticView.oneFile({ title: "UC网盘单文件直链", fileName: oneFileDownloadDetail[0].file_name, fileSize: utils.formatByteToSize(oneFileDownloadDetail[0].size), downloadUrl: oneFileDownloadDetail[0].download_url, fileUploadTime: utils.formatTime( oneFileDownloadDetail[0].created_at ), fileLatestTime: utils.formatTime( oneFileDownloadDetail[0].last_update_at ), clickCallBack() { that.downloadFile( oneFileDownloadDetail[0].file_name, oneFileDownloadDetail[0].download_url ); }, }); } else { Qmsg.info("正在递归文件"); let QmsgLoading = Qmsg.loading(`正在解析多文件中,请稍后...`); let folderInfoList = that.getFolderInfo(detail, stoken, 0); QmsgLoading.close(); log.info("递归完毕"); NetDiskUI.staticView.moreFile("UC网盘多文件直链", folderInfoList); return; } }; /** * 判断是否已登录UC网盘 * @returns {Promise<undefined|string|boolean>} */ this.isLogin = async function () { let getResp = await httpx.get("https://drive.uc.cn/", { headers: { "User-Agent": utils.getRandomPCUA(), }, }); log.success(["判断是否已登录UC网盘", getResp]); if (!getResp.status) { return; } if (getResp.data.finalUrl === "https://drive.uc.cn/list") { return "已登录"; } else { return false; } }; /** * 下载文件 * @param {string} fileName 文件名 * @param {string} downloadUrl 下载链接 * @return { { * abort: Function * } } */ this.downloadFile = function (fileName, downloadUrl) { log.info([`调用【GM_download】下载:`, arguments]); Qmsg.info(`调用【GM_download】下载:${fileName}`); if (typeof GM_download === "undefined") { Qmsg.error("当前脚本环境缺失API 【GM_download】"); return; } let downloadingQmsg = Qmsg.loading("下载中..."); return GM_download({ url: downloadUrl, name: fileName, headers: { Referer: "https://drive.uc.cn/", }, onload() { downloadingQmsg.close(); Qmsg.success(`下载 ${fileName} 已完成`); }, onprogress(details) { if ( typeof details === "object" && "loaded" in details && "total" in details ) { let progressNum = details.loaded / details.total; let formatProgressNum = (progressNum * 100).toFixed(2); downloadingQmsg.setText(`下载中...${formatProgressNum}%`); } }, onerror(error) { downloadingQmsg.close(); log.error(["下载失败error👉", error]); if (typeof error === "object" && error["error"]) { Qmsg.error( `下载 ${fileName} 失败或已取消 原因:${error["error"]}`, { timeout: 6000, } ); } else { Qmsg.error(`下载 ${fileName} 失败或已取消`); } }, ontimeout() { downloadingQmsg.close(); Qmsg.error(`下载 ${fileName} 请求超时`); }, }); }; /** * 前往登录 * @param {string} text 弹窗的显示的内容 */ this.gotoLogin = function (text = "") { NetDiskPops.confirm( { title: { position: "center", text: "UC网盘", }, content: { text: text, html: false, }, btn: { reverse: true, position: "end", ok: { text: "前往", enable: true, callback() { window.open("https://drive.uc.cn", "_blank"); }, }, }, }, NetDiskUI.popsStyle.tianYiYunLoginTip ); }; /** * 获取stoken * @param {string} pwd_id 分享码 * @param {string} passcode 访问码 * @returns {Promise<string|undefined>} */ this.getStoken = async function (pwd_id, passcode) { let postResp = await httpx.post( "https://pc-api.uc.cn/1/clouddrive/share/sharepage/token?entry=ft&fr=pc&pr=UCBrowser", { data: JSON.stringify({ share_for_transfer: true, passcode: passcode, pwd_id: pwd_id, }), headers: { Accept: "application/json, text/plain, */*", "Content-Type": "application/json;charset=UTF-8", "User-Agent": utils.getRandomPCUA(), Origin: "https://drive.uc.cn", Referer: "https://drive.uc.cn/", }, onerror() {}, } ); if (!postResp.status) { let errorData = utils.toJSON(postResp.data.responseText); log.error(["获取stoken失败JSON信息", errorData]); if ("message" in errorData) { Qmsg.error(errorData["message"]); } else { Qmsg.error("请求异常,获取stoken失败"); } return; } let data = utils.toJSON(postResp.data.responseText); log.info(["获取stoken:", data]); if (data["code"] !== 0) { log.error(["获取stoken失败", data]); Qmsg.error("获取stoken失败"); return; } return data["data"]["stoken"]; }; /** * 获取stoken * @param {string} pwd_id 分享码 * @param {string} passcode 访问码 * @param {string} stoken 获取的stoken * @param {string} [pdir_fid=0] 父fid,默认为0,如果为文件夹,那么它的fid就是这个值 * @param {number} [force=0] * @param {number} [_page=1] * @param {number} [_size=50] * @param {number} [_fetch_banner=0] * @param {number} [_fetch_share=0] * @param {number} [_fetch_total=1] * @returns {Promise<{ * backup_sign: number, * backup_source: boolean, * ban: boolean, * category: number, * created_at: number, * creator_ucid_or_default: string, * cur_version_or_default: number, * dir: boolean, * duration: number, * event_extra: { * recent_created_at: number * }, * extra: string, * fid: string, * file: boolean, * file_name: string, * file_name_hl_end: number, * file_name_hl_start: number, * file_source: string, * file_struct: { * fir_source: string, * platform_source: string, * sec_source: string, * thi_source: string, * upload_dm: string, * upload_mi: string, * }, * file_type: number, * format_type: string, * include_items: number, * l_created_at: number, * l_updated_at: number, * last_update_at: number, * like: number, * name_space: number, * offline_source: boolean, * operated_at: number, * owner_drive_type_or_default: number, * owner_ucid: string, * pdir_fid: string, * raw_name_space: number, * risk_type: number, * save_as_source: boolean, * share_fid_token: string, * size: number, * status: number, * tags: string, * updated_at: number, * _extra: {}, * }[]|undefined>} */ this.getDetail = async function ( pwd_id, passcode, stoken, pdir_fid = 0, force = 0, _page = 1, _size = 50, _fetch_banner = 0, _fetch_share = 0, _fetch_total = 1 ) { let getResp = await httpx.get( `https://pc-api.uc.cn/1/clouddrive/transfer_share/detail?pr=UCBrowser&fr=h5&pwd_id=${pwd_id}&__t=${new Date().getTime()}&passcode=${passcode}&stoken=${encodeURIComponent( stoken )}&pdir_fid=${pdir_fid}&force=${force}&_page=${_page}&_size=${_size}&_fetch_banner=${_fetch_banner}&_fetch_share=${_fetch_share}&_fetch_total=${_fetch_total}&_sort=${encodeURIComponent( "file_type:asc,file_name:asc" )}`, { headers: { Accept: "application/json, text/plain, */*", "User-Agent": utils.getRandomPCUA(), Origin: "https://drive.uc.cn", Referer: "https://drive.uc.cn/", }, } ); if (!getResp.status) { return; } let data = utils.toJSON(getResp.data.responseText); log.info(["获取detail:", data]); if (data["code"] !== 0) { log.error(["获取detail失败", data]); Qmsg.error("获取detail失败"); return; } return data["data"]["list"]; }; /** * 获取下载信息 * @param {string} pwd_id 分享码 * @param {string} stoken 获取的stoken * @param {string} fids 通过获取到的detail获取到的fid * @param {string} share_fid_token 通过获取到的detail获取到的share_fid_token * @returns {Promise< { * backup_sign: number, * backup_source: boolean, * ban: boolean, * big_thumbnail: string, * category: number, * created_at: number, * creator_ucid_or_default: string, * cur_version_or_default: number, * dir: boolean, * download_url: string, * duration: number, * event_extra: { * recent_created_at: number * }, * extra: string, * fid: string, * file: boolean, * file_name: string, * file_name_hl_end: number, * file_name_hl_start: number, * file_source: string, * file_type: number, * format_type: string, * l_created_at: number, * l_updated_at: number, * last_update_at: number, * like: number, * md5: string, * name_space: number, * obj_category: string, * offline_source: boolean, * operated_at: number, * owner_drive_type_or_default: number, * owner_ucid: string, * pdir_fid: string, * preview_url: string, * range_size: number, * raw_name_space: number, * risk_type: number, * save_as_source: boolean, * share_fid_token: string, * size: number, * status: number, * thumbnail: string, * updated_at: number, * video_height: number, * video_max_resolution: string, * video_width: number, * _extra: {}, * } []|undefined>} */ this.getDownload = async function ( pwd_id, stoken, fid, share_fid_token ) { let postResp = await httpx.post( "https://pc-api.uc.cn/1/clouddrive/file/download?entry=ft&fr=pc&pr=UCBrowser", { data: JSON.stringify({ fids: [fid], pwd_id: pwd_id, stoken: stoken, fids_token: [share_fid_token], }), headers: { Accept: "application/json, text/plain, */*", "Content-Type": "application/json;charset=UTF-8", "User-Agent": utils.getRandomPCUA(), Origin: "https://drive.uc.cn", Referer: "https://drive.uc.cn/", }, } ); if (!postResp.status) { return; } let data = utils.toJSON(postResp.data.responseText); log.info(["获取download:", data]); if (data["code"] !== 0) { log.error(["获取download失败", data]); Qmsg.error("获取download失败"); return; } if (data["data"].length === 0) { log.error(["获取download detail失败", data]); Qmsg.error("获取download detail失败失败"); return; } return data["data"]; }; /** * 获取文件夹信息 * @param {{ * backup_sign: number, * backup_source: boolean, * ban: boolean, * category: number, * created_at: number, * creator_ucid_or_default: string, * cur_version_or_default: number, * dir: boolean, * duration: number, * event_extra: { * recent_created_at: number * }, * extra: string, * fid: string, * file: boolean, * file_name: string, * file_name_hl_end: number, * file_name_hl_start: number, * file_source: string, * file_struct: { * fir_source: string, * platform_source: string, * sec_source: string, * thi_source: string, * upload_dm: string, * upload_mi: string, * }, * file_type: number, * format_type: string, * include_items: number, * l_created_at: number, * l_updated_at: number, * last_update_at: number, * like: number, * name_space: number, * offline_source: boolean, * operated_at: number, * owner_drive_type_or_default: number, * owner_ucid: string, * pdir_fid: string, * raw_name_space: number, * risk_type: number, * save_as_source: boolean, * share_fid_token: string, * size: number, * status: number, * tags: string, * updated_at: number, * _extra: {}, * }[]} infoList * @return {Promise<{ * fileName: string, * fileSize: string|number, * fileType: ?string, * createTime: ?string, * latestTime: ?string, * isFolder: boolean, * index: ?number, * clickCallBack: ?(event:Event,_config_: object)=>{} * }[]>} */ this.getFolderInfo = function (infoList, stoken, index = 0) { let folderInfoList = []; let tempFolderInfoList = []; /** * @type {PopsFolderDataConfig[]} */ let tempFolderFileInfoList = []; infoList.forEach((item) => { if (item.dir == false && item.file_type === 1) { /* 文件 */ tempFolderFileInfoList.push({ fileName: item.file_name, fileSize: item.size, fileType: "", createTime: item.created_at, latestTime: item.updated_at, isFolder: false, index: index, async clickEvent() { let fileDownloadUrl = await that.getDownload( that.shareCode, stoken, item.fid, item.share_fid_token ); if (fileDownloadUrl) { if (fileDownloadUrl.length) { fileDownloadUrl = fileDownloadUrl[0].download_url; } else { fileDownloadUrl = ""; } } else { fileDownloadUrl = ""; } if (item.ban) { Qmsg.error("文件已被禁止下载"); } else { let schemeDownloadUrl = NetDiskFilterScheme.handleUrl( "uc-static-scheme-enable", "uc-static-scheme-forward", fileDownloadUrl ); /* 如果已被scheme过滤,那么不进行GM_download下载 */ if (schemeDownloadUrl === fileDownloadUrl) { that.downloadFile(item.file_name, fileDownloadUrl); } else { return { autoDownload: true, mode: "aBlank", url: fileDownloadUrl, }; } } }, }); } else { /* 文件夹 */ tempFolderInfoList.push({ fileName: item.file_name, fileSize: item.size, fileType: "", createTime: item.created_at, latestTime: item.updated_at, isFolder: true, index: index, async clickEvent() { if (item.include_items === 0) { /* 里面没有文件 */ log.success("里面没有文件"); return []; } let newDetail = await that.getDetail( that.shareCode, that.accessCode, stoken, item.fid ); if (newDetail) { return that.getFolderInfo(newDetail, stoken, index + 1); } else { return []; } }, }); } }); tempFolderInfoList.sort((a, b) => a["fileName"].localeCompare(b["fileName"]) ); tempFolderFileInfoList.sort((a, b) => a["fileName"].localeCompare(b["fileName"]) ); folderInfoList = folderInfoList.concat(tempFolderInfoList); folderInfoList = folderInfoList.concat(tempFolderFileInfoList); log.info(["getFilesInfoByRec", folderInfoList]); return folderInfoList; }; 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]) { let 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); Qmsg.info("1.5秒后跳转该链接"); } log.success(["新标签页打开", [...arguments]]); /* 百度网盘会拒绝referrer不安全访问 */ document .querySelector("meta[name='referrer']") ?.setAttribute("content", "no-referrer"); /* 增加延迟跳转,因为要等待accessCode复制到剪贴板 */ setTimeout( () => { window.open(url, "_blank"); }, accessCode ? 1500 : 0 ); }, /** * 将链接转为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(NetDisk.noAccessCodeRegExp, ""); } 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#}", "") .replaceAll("{#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](); }); }, }; /** * 网盘直链进行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 currentScheme = GM_getValue(forward_key, this.defaultScheme); currentScheme = currentScheme.replace("{#intentData#}", url); return currentScheme; }, }; /** * 自动填入访问码 */ const NetDiskAutoFillAccessCode = { /** * 临时数据 * @type {{ * shareCode: string, * accessCode: string, * netDiskName: string, * }|undefined} */ tempData: GM_getValue("tempNetDiskInfo"), /** * @type {boolean} 自动输入访问码是否开启 */ enable: Boolean(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((element) => { if (!utils.isVisible(element)) { log.error("输入框不可见,不输入密码"); return; } Qmsg.success("自动填入访问码"); element.value = this.accessCode; utils.dispatchEvent(element, "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((element) => { if (!utils.isVisible(element)) { log.error("输入框不可见,不输入密码"); return; } Qmsg.success("自动填入访问码"); element.value = this.accessCode; utils.dispatchEvent(element, "input"); document .querySelector("#passwddiv > div > div.passwddiv-input > div") ?.click(); document.querySelector("#sub")?.click(); }); utils.waitNode("#f_pwd").then((element) => { utils.mutationObserver(element, { 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((codeTxtElement) => { setTimeout(() => { let visitBtn = document.querySelector(".btn.btn-primary.visit"); if (!utils.isVisible(codeTxtElement)) { log.error("输入框不可见,不输入密码"); return; } Qmsg.success("自动填入访问码"); codeTxtElement.value = this.accessCode; codeTxtElement._value = this.accessCode; utils.dispatchEvent(codeTxtElement, "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((accessInputElement) => { setTimeout(() => { if (!utils.isVisible(accessInputElement)) { log.error("输入框不可见,不输入密码"); return; } Qmsg.success("自动填入访问码"); accessInputElement.value = this.accessCode; accessInputElement._value = this.accessCode; utils.dispatchEvent(accessInputElement, "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((element) => { if (!utils.isVisible(element)) { log.error("输入框不可见,不输入密码"); return; } Qmsg.success("自动填入访问码"); element.value = this.accessCode; utils.dispatchEvent(element, "input"); document .querySelector("#homepage div.token div.token-form a") .click(); }); /* 移动端 */ utils .waitNode("#app div.token-form input[type=text]") .then((element) => { if (!utils.isVisible(element)) { log.error("输入框不可见,不输入密码"); return; } Qmsg.success("自动填入访问码"); element.value = this.accessCode; utils.dispatchEvent(element, "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((element) => { if (!utils.isVisible(element)) { log.error("输入框不可见,不输入密码"); return; } Qmsg.success("自动填入访问码"); element.value = this.accessCode; utils.getReactObj(element).reactFiber.memoizedProps.onChange({ currentTarget: element, target: element, }); document.querySelector('#root button[type="submit"]').click(); }); /* ------------------------------------ */ /* 移动端 */ utils.waitNode("#root input[name=pwd]").then((element) => { if (!utils.isVisible(element)) { log.error("输入框不可见,不输入密码"); return; } Qmsg.success("自动填入访问码"); element.value = this.accessCode; utils.getReactObj(element).reactFiber.memoizedProps.onChange({ currentTarget: element, target: element, }); 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((element) => { if (!utils.isVisible(element)) { log.error("输入框不可见,不输入密码"); return; } Qmsg.success("自动填入访问码"); utils.getReactObj(element).reactProps.onChange({ target: { value: this.accessCode, }, }); element.nextSibling.click(); }); /* ------------------------------------ */ /* 移动端 */ utils .waitNode("#app .appinput input.ant-input[type=text]") .then((element) => { if (!utils.isVisible(element)) { log.error("输入框不可见,不输入密码"); return; } Qmsg.success("自动填入访问码"); utils.getReactObj(element).reactProps.onChange({ target: { value: this.accessCode, }, }); element.nextSibling.click(); }); } }, /** * 腾讯微云 */ weiyun() { if (window.location.hostname === "share.weiyun.com") { /* 桌面端 */ log.success(["自动填写链接", this.tempData]); utils.waitNode("#app input.input-txt").then((element) => { if (!utils.isVisible(element)) { log.error("输入框不可见,不输入密码"); return; } Qmsg.success("自动填入访问码"); element.value = this.accessCode; utils.dispatchEvent(element, "input"); utils.dispatchEvent(element, "change"); setTimeout(() => { document.querySelector(".form-item button.btn-main").click(); }, 500); }); /* ------------------------------------ */ /* 移动端 */ utils.waitNode(".input-wrap input.pw-input").then((element) => { if (!utils.isVisible(element)) { log.error("输入框不可见,不输入密码"); return; } Qmsg.success("自动填入访问码"); element.value = this.accessCode; utils.dispatchEvent(element, "input"); utils.dispatchEvent(element, "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((element) => { if (!utils.isVisible(element)) { log.error("输入框不可见,不输入密码"); return; } log.error("输入框不可见,不输入密码"); element.value = this.accessCode; utils.dispatchEvent(element, "input"); utils.dispatchEvent(element, "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((element) => { if (!utils.isVisible(element)) { log.error("输入框不可见,不输入密码"); return; } log.error("输入框不可见,不输入密码"); element.value = this.accessCode; utils.dispatchEvent(element, "input"); utils.dispatchEvent(element, "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((element) => { if (!utils.isVisible(element)) { log.error("输入框不可见,不输入密码"); return; } Qmsg.success("自动填入访问码"); element.value = this.accessCode; utils.dispatchEvent(element, "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((element) => { if (!utils.isVisible(element)) { log.error("输入框不可见,不输入密码"); return; } Qmsg.success("自动填入访问码"); element.value = this.accessCode; utils.dispatchEvent(element, "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((element) => { if (!utils.isVisible(element)) { log.error("输入框不可见,不输入密码"); return; } Qmsg.success("自动填入访问码"); ( utils.getReactObj(element).reactProps || utils.getReactObj(element).reactEventHandlers ).onChange({ target: { value: this.accessCode, }, }); }); } }, /** * 坚果云 * 暂时没找到有密码的链接 */ jianguoyun() {}, /** * OneDrive * 暂时没找到有密码的链接 */ onedrive() {}, }; /** * Woker */ const NetDiskWorker = { blobUrl: "", /** * @type {Worker} */ 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 ); })(); `; let 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.isHandleMatch = 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) => { NetDisk.handleLink(netDiskName, netDiskIndex, item); }); if (NetDisk.hasMatchLink) { NetDiskUI.suspension.show(); } setTimeout(() => { NetDiskUI.isHandleMatch = false; }, parseFloat(GM_getValue("delaytime", 0.8)) * 1000); }, /** * Worker失败回调 * @param {object} error */ errorCallBack(error) { NetDiskUI.isHandleMatch = false; log.error(["Worker Error", error]); }, /** * 传递数据给worker内进行处理匹配 * @param {{ * regexp: RegExp, * pageText: string, * netDiskName: string, * netDiskIndex: number * }} message 数据 * @param { StructuredSerializeOptions | undefined } options 配置 */ postMessage(message, options) { this.GM_matchWorker.postMessage(message, options); }, }; /** * 网盘-自定义规则 */ const NetDiskCustomRules = { init() { Object.assign(NetDisk.regular, this.parseRule()); }, /** * 把用户自定义规则进行转换成脚本规则 * @returns {object} */ parseRule() { let regular = {}; this.getRule().forEach((item) => { let data = item.regexp; data.shareCode = new RegExp(data.shareCode, "ig"); data.shareCodeNeedRemoveStr = new RegExp( data.shareCodeNeedRemoveStr, "ig" ); if (data.checkAccessCode) { data.checkAccessCode = new RegExp(data.checkAccessCode, "ig"); } if (data.accessCode) { data.accessCode = new RegExp(data.accessCode, "ig"); } if (data.acceesCodeNotMatch) { data.acceesCodeNotMatch = new RegExp(data.acceesCodeNotMatch, "ig"); } if (regular[item.key]) { /* 已存在相同key规则,追加新的 */ regular[item.key].push(data); } else { regular[item.key] = [data]; } if (item.setting) { /* 进行了设置 */ if (item.setting.isBlank) { GM_setValue(item.key + "-open-enable", true); } else { GM_deleteValue(item.key + "-open-enable"); } } NetDiskUI.src.icon[item.key] = item.icon; }); return regular; }, /** * 设置规则到本地 * @param {object} userRule */ setRule(userRule) { GM_setValue("userRule", userRule); }, /** * 清空规则 */ clearRule() { GM_deleteValue("userRule"); }, /** * 获取规则 * @returns {{ * key: string, * icon: string, * regexp: { * link_innerText: string, * link_innerHTML: string, * shareCode: string, * shareCodeNeedRemoveStr: string, * accessCode: string|undefined, * checkAccessCode: string|undefined, * acceesCodeNotMatch: string|undefined, * uiLinkShow: string, * blank: string, * copyUrl: string, * }, * setting: { * name: string|undefined, * isBlank: boolean * }|undefined * }[]} */ getRule() { return GM_getValue("userRule", []); }, /** * 获取格式化后的规则 * @param {string|undefined} rule * @returns {string} */ getFormatRule(rule) { return JSON.stringify(rule || this.getRule(), null, 4); }, }; /** * 弹窗UI界面 */ const NetDiskUI = { /** * 已匹配到的网盘图标字典 */ isMatchedNetDiskIconMap: new Set(), /** * 高度和宽度大小 */ size: parseInt(GM_getValue("size", 50)), /** * 按钮透明度 */ opacity: parseFloat(GM_getValue("opacity", 1)), /** * 是否已创建设置界面 */ isCreatedUISetting: false, /** * 是否正在文本匹配中 */ isHandleMatch: false, /** * 是否正在循环切换按钮背景 */ isSwitchRandomBackground: false, /** * 链接弹窗的对象 */ uiLinkAlias: null, /** * 单文件直链弹窗的唯一标识 */ uiLinkParseAlias: "单文件直链层", /** * 多文件直链弹窗的唯一标识 */ uiLinkParseMoreAlias: "多文件直链层", /** * 重输密码弹窗的唯一标识 */ uiPasswordAlias: "重输密码层", /** * 是否默认弹窗可以拖拽 */ defaultPCDrag: false, /** * 是否默认弹窗拖拽距离 */ defaultPCDragLimit: true, /** * 点击弹窗遮罩层是否可以关闭弹窗 */ defaultClickMaskToCloseDialog: false, /** * 是否默认禁用弹窗弹出后背景可以滚动 */ defaultForbiddenScroll: false, /** * 默认弹窗动画 */ defaultAnimation: "pops-anim-fadein-zoom", /** * folder默认排序的属性名 */ defaultSortName: "fileName", /** * folder是否降序排序 */ defaultSortDesc: false, /** * 弹窗的配置 * 规定格式 * { * PC:{ * width: "", * height: "", * }, * Mobile: { * width: "", * height: "", * } * } */ popsStyle: { /** * 天翼云需要登录的提示 */ tianYiYunLoginTip: { PC: { width: "30vw", height: "280px", }, Mobile: { width: "80vw", height: "250px", }, }, /** * 坚果云需要登录的提示 */ jianGuoYunLoginTip: { PC: { width: "350px", height: "200px", }, Mobile: { width: "350px", height: "200px", }, }, /** * 设置界面 */ settingView: { PC: { width: "800px", height: "600px", }, Mobile: { width: "92vw", height: "80vh", }, }, /** * 设置默认值的界面 */ setDefaultValueView: { PC: { width: "350px", height: "200px", }, Mobile: { width: "350px", height: "200px", }, }, /** * (主)网盘链接界面 */ mainView: { PC: { width: "50vw", height: "65vh", }, Mobile: { width: "88vw", height: "50vh", }, }, /** * 单文件直链弹窗 */ oneFileStaticView: { PC: { width: "550px", height: "350px", }, Mobile: { width: "88vw", height: "300px", }, }, /** * 多文件直链弹窗 */ moreFileStaticView: { PC: { width: "700px", height: "600px", }, Mobile: { width: "88vw", height: "500px", }, }, /** * 新密码、错误密码输入弹窗 */ inputNewAccessCodeView: { PC: { width: "400px", height: "200px", }, Mobile: { width: "88vw", height: "160px", }, }, /** * 历史存储记录弹窗 */ historyMatchView: { PC: { width: "50vw", height: "65vh", }, Mobile: { width: "88vw", height: "60vh", }, }, /** * 自定义规则的弹窗 */ customRulesView: { PC: { width: "50vw", height: "65vh", }, Mobile: { width: "88vw", height: "60vh", }, }, /** * 主动识别的弹窗 */ matchPasteTextView: { PC: { width: "50vw", height: "65vh", }, Mobile: { width: "88vw", height: "60vh", }, }, /** * 访问码规则弹窗 */ accessCodeRuleView: { PC: { width: "50vw", height: "65vh", }, Mobile: { width: "88vw", height: "60vh", }, }, /** * 访问码规则添加/修改/删除 */ accessCodeRuleEditView: { PC: { width: "44vw", height: "50vh", }, Mobile: { width: "70vw", height: "45vh", }, }, }, src: { /** * 图标RESOURCE_ICON * 从图标库中引入并覆盖 */ icon: {}, }, /** * 悬浮按钮 双击打开主界面,长按打开设置(不能移动,移动就不打开,只是移动按钮 */ suspension: { /** * 是否已显示 */ isShow: false, /** * 显示悬浮按钮 */ show() { if (!this.isShow) { this.isShow = true; this.createUI(); this.initPop(); this.setSuspensionEvent(); this.setResizeEventListener(); this.setSuspensionPosition(); } this.backgroundSwitch(); }, /** * 判断当前是否是顶部窗口 * @returns {boolean} */ isTopWindow() { return self.window == top.window; }, /** * 创建UI界面 */ 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", { id: "whitesevSuspensionId", className: "whitesevSuspension", innerHTML: ` <div class="whitesevSuspensionMain"> <div class="whitesevSuspensionFloor"> <div class="netdisk"></div> </div> </div> `, }, { style: ` width: ${NetDiskUI.size}px; height: ${NetDiskUI.size}px; opacity: ${NetDiskUI.opacity} `, } ); 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), }); }, /** * 显示设置界面 */ showSettingView() { if (document.querySelector(".pops.whitesevPopSetting")) { log.error("设置界面已存在"); Qmsg.error("设置界面已存在"); return; } /** * * @param {string} text * @param {string} key * @param {boolean} defaultValue * @param {(event:Event,enable:boolean)=>void} callback * @param {string} description * @returns */ function getSwtichDetail( text, key, defaultValue, callback, description ) { defaultValue = Boolean(defaultValue); return { text: text, type: "switch", description: description, attributes: { "data-key": key, "data-default-value": defaultValue, }, getValue() { return Boolean(GM_getValue(key, defaultValue)); }, callback(event, value) { GM_setValue(key, Boolean(value)); if (typeof callback === "function") { callback(event, value); } }, }; } let contentDetails = [ { id: "netdisk-panel-config-all-setting", title: "总设置", isDefault: true, forms: [ { className: "netdisk-panel-forms-pops", text: "弹窗", type: "forms", forms: [ { text: "动画", type: "select", attributes: { "data-key": "popsAnimation", "data-default-value": NetDiskUI.defaultAnimation, }, getValue() { return GM_getValue( this.attributes["data-key"], this.attributes["data-default-value"] ); }, callback(event, isSelectedValue, isSelectedText) { GM_setValue(this.attributes["data-key"], isSelectedValue); }, data: [ { value: "", text: "无", }, { value: "pops-anim-spread", text: "spread", }, { value: "pops-anim-shake", text: "shake", }, { value: "pops-anim-rolling-left", text: "rolling-left", }, { value: "pops-anim-rolling-right", text: "rolling-right", }, { value: "pops-anim-slide-top", text: "slide-top", }, { value: "pops-anim-slide-bottom", text: "slide-bottom", }, { value: "pops-anim-slide-left", text: "slide-left", }, { value: "pops-anim-slide-right", text: "slide-right", }, { value: "pops-anim-fadein", text: "fadein", }, { value: "pops-anim-fadein-zoom", text: "fadein-zoom", }, { value: "pops-anim-fadein-alert", text: "fadein-alert", }, { value: "pops-anim-don", text: "don", }, { value: "pops-anim-roll", text: "roll", }, { value: "pops-anim-sandra", text: "sandra", }, { value: "pops-anim-gather", text: "gather", }, ], }, getSwtichDetail( "点击弹窗遮罩层关闭弹窗", "clickMaskToCloseDialog", NetDiskUI.defaultClickMaskToCloseDialog ), getSwtichDetail( "可拖拽窗口", "pcDrag", NetDiskUI.defaultPCDrag ), getSwtichDetail( "限制拖拽距离", "pcDragLimit", NetDiskUI.defaultPCDragLimit ), ], }, { className: "netdisk-panel-forms-pops-folder", text: "文件弹窗", type: "forms", forms: [ { text: "排序名", type: "select", description: "当前的规则", attributes: { "data-key": "pops-folder-sort-name", "data-default-value": NetDiskUI.defaultSortName, }, getValue() { return GM_getValue( this.attributes["data-key"], this.attributes["data-default-value"] ); }, callback(event, isSelectedValue, isSelectedText) { GM_setValue(this.attributes["data-key"], isSelectedValue); }, data: [ { value: "fileName", text: "文件名", }, { value: "latestTime", text: "修改时间", }, { value: "fileSize", text: "大小", }, ], }, { text: "排序规则", type: "select", description: "当前的规则", attributes: { "data-key": "pops-folder-sort-is-desc", "data-default-value": NetDiskUI.defaultSortDesc, }, getValue() { return GM_getValue( this.attributes["data-key"], this.attributes["data-default-value"] ); }, callback(event, isSelectedValue, isSelectedText) { GM_setValue(this.attributes["data-key"], isSelectedValue); }, data: [ { value: false, text: "升序", }, { value: true, text: "降序", }, ], }, ], }, { text: "小图标导航", type: "forms", forms: [ getSwtichDetail( "点击定位分享码", "pops-netdisk-icon-click-event-find-sharecode", true, NetDiskData.iconDefaultClickEventToFindShareCode, "自动滚动页面至包含分享码的元素" ), getSwtichDetail( "选中分享码", "pops-netdisk-icon-click-event-find-sharecode-with-select", true, NetDiskData.iconDefaultClickEventToFindShareCodeWithSelect, "使用光标选中分享码/元素" ), getSwtichDetail( "循环定位", "pops-netdisk-icon-click-event-loop-find-sharecode", true, NetDiskData.iconDefaultClickEventToFindShareCodeByLoop, "关闭则是每一个元素只定位一次" ), ], }, { text: "悬浮按钮", type: "forms", forms: [ { text: "大小", type: "slider", attributes: { "data-key": "size", "data-default-value": 50, }, getValue() { return GM_getValue( this.attributes["data-key"], this.attributes["data-default-value"] ); }, callback(event, value) { GM_setValue(this.attributes["data-key"], value); NetDiskUI.size = parseInt(value); if (NetDiskUI.suspension.isShow) { DOMUtils.css("#whitesevSuspensionId", { width: NetDiskUI.size, height: NetDiskUI.size, }); NetDiskUI.suspension.setSuspensionPosition(); } }, min: 15, max: 250, }, { text: "透明度", type: "slider", attributes: { "data-key": "opacity", "data-default-value": 1, }, getValue() { return GM_getValue( this.attributes["data-key"], this.attributes["data-default-value"] ); }, callback(event, value) { GM_setValue(this.attributes["data-key"], value); NetDiskUI.opacity = parseFloat(value); if (NetDiskUI.suspension.isShow) { DOMUtils.css("#whitesevSuspensionId", { opacity: NetDiskUI.opacity, }); } }, min: 0.1, max: 1, step: 0.1, }, { text: "背景轮播时间", type: "slider", attributes: { "data-key": "randbg-time", "data-default-value": 1500, }, getValue() { return GM_getValue( this.attributes["data-key"], this.attributes["data-default-value"] ); }, callback(event, value) { GM_setValue(this.attributes["data-key"], value); }, getToolTipContent(value) { return `${value}ms`; }, min: 0, max: 10000, step: 100, }, { text: "背景显示时间", type: "slider", attributes: { "data-key": "randbg-show-time", "data-default-value": 1200, }, getValue() { return GM_getValue( this.attributes["data-key"], this.attributes["data-default-value"] ); }, callback(event, value) { GM_setValue(this.attributes["data-key"], value); }, getToolTipContent(value) { return `${value}ms`; }, min: 0, max: 10000, step: 100, }, ], }, { className: "netdisk-panel-forms-toast", text: "Toast", type: "forms", forms: [ { text: "位置", type: "select", attributes: { "data-key": "qmsg-position", "data-default-value": "top", }, getValue() { return GM_getValue( this.attributes["data-key"], this.attributes["data-default-value"] ); }, callback(event, isSelectedValue, isSelectedText) { GM_setValue(this.attributes["data-key"], isSelectedValue); }, data: [ { value: "topleft", text: "左上角", }, { value: "top", text: "顶部", }, { value: "topright", text: "右上角", }, { value: "left", text: "左边", }, { value: "center", text: "中间", }, { value: "right", text: "右边", }, { value: "bottomleft", text: "左下角", }, { value: "bottom", text: "底部", }, { value: "bottomright", text: "右下角", }, ], }, { text: "同时最多显示的数量", type: "select", attributes: { "data-key": "qmsg-maxnums", "data-default-value": 3, }, getValue() { return GM_getValue( this.attributes["data-key"], this.attributes["data-default-value"] ); }, callback(event, isSelectedValue, isSelectedText) { GM_setValue( this.attributes["data-key"], parseInt(isSelectedValue) ); }, data: [ { value: 1, text: "1", }, { value: 2, text: "2", }, { value: 3, text: "3", }, { value: 4, text: "4", }, { value: 5, text: "5", }, ], }, getSwtichDetail("逆序弹出", "qmsg-showreverse", false), ], }, { className: "netdisk-panel-forms-function", text: "功能", type: "forms", forms: [ { text: "匹配间隔", type: "slider", attributes: { "data-key": "delaytime", "data-default-value": 0.8, }, getValue() { return GM_getValue( this.attributes["data-key"], this.attributes["data-default-value"] ); }, callback(event, value) { GM_setValue(this.attributes["data-key"], value); }, getToolTipContent(value) { return `${value}s`; }, min: 0.6, max: 5.0, step: 0.1, }, { text: "匹配类型", type: "select", attributes: { "data-key": "pageMatchRange", "data-default-value": "all", }, getValue() { return GM_getValue( this.attributes["data-key"], this.attributes["data-default-value"] ); }, callback(event, isSelectedValue, isSelectedText) { GM_setValue(this.attributes["data-key"], isSelectedValue); }, data: [ { value: "all", text: "全部", }, { value: "innerText", text: "普通文本", }, { value: "innerHTML", text: "超文本", }, ], }, { text: "历史记录排序规则", type: "select", attributes: { "data-key": "netdisk-history-match-ordering-rule", "data-default-value": "按 更新时间 - 降序", }, getValue() { return GM_getValue( this.attributes["data-key"], this.attributes["data-default-value"] ); }, callback(event, isSelectedValue, isSelectedText) { GM_setValue(this.attributes["data-key"], isSelectedValue); }, data: [ { value: "按 记录时间 - 升序", text: "按 记录时间 - 升序", }, { value: "按 记录时间 - 降序", text: "按 记录时间 - 降序", }, { value: "按 更新时间 - 升序", text: "按 更新时间 - 升序", }, { value: "按 更新时间 - 降序", text: "按 更新时间 - 降序", }, ], }, getSwtichDetail("读取剪贴板", "readClipboard", false), getSwtichDetail("存储匹配记录", "saveMatchNetDisk", false), getSwtichDetail( "自动输入访问码", "autoFillAccessCode", false ), getSwtichDetail( "获取重定向后的直链", "getTheDirectLinkAfterRedirection", false ), getSwtichDetail( "允许匹配当前URL", "allowMatchLocationHref", false ), ], }, ], }, ]; let shortcutDetails = { className: "netdisk-panel-forms-shortcut-keys", text: "快捷键", type: "forms", forms: [], }; let shortcurFormsDetailsList = [ { text: "打开设置界面", key: "netdisk-keyboard-open-setting", }, { text: "打开历史匹配记录", key: "netdisk-keyboard-open-history-matching-records", }, { text: "打开访问码规则", key: "netdisk-keyboard-open-accesscode-rule", }, { text: "打开用户自定义规则", key: "netdisk-keyboard-open-user-rule", }, { text: "打开主动识别文本", key: "netdisk-keyboard-open-proactively-recognize-text", }, ]; shortcurFormsDetailsList.forEach((item) => { shortcutDetails.forms.push({ text: item.text, type: "button", attributes: { "data-key": item.key, "data-default-value": "暂无快捷键", }, buttonIcon: "keyboard", buttonIconIsLoading: false, buttonType: "default", buttonText() { return NetDiskShortcut.getShowText( this.attributes["data-key"], this.attributes["data-default-value"] ); }, callback(event) { NetDiskShortcut.buttonClickCallBack( event, this.attributes["data-key"], this.attributes["data-default-value"] ); }, }); }); contentDetails[0].forms.push(shortcutDetails); /** * 追加网盘设置 */ function addNetDiskSetting() { let netDiskDetailsList = [ { type: "百度网盘", key: "baidu", checkbox_openBlank: true, range_innerText: true, range_innerText_default_value: 20, range_accessCode_after_text: true, range_accessCode_after_text_default_value: 10, range_innerHTML: true, range_innerHTML_default_value: 100, range_accessCode_after_html: true, range_accessCode_after_html_default_value: 15, ownFormList: [ { text: "第三方解析站", type: "forms", forms: [ { text: "启用解析站", type: "switch", attributes: { "data-key": "baidu-static-enable", "data-default-value": false, }, getValue() { return Boolean( GM_getValue( this.attributes["data-key"], this.attributes["data-default-value"] ) ); }, callback(event, value) { GM_setValue( this.attributes["data-key"], Boolean(value) ); }, }, { text: "跳转时复制链接", type: "switch", attributes: { "data-key": "baidu-baiduwp-php-copy-url", "data-default-value": false, }, getValue() { return Boolean( GM_getValue( this.attributes["data-key"], this.attributes["data-default-value"] ) ); }, callback(event, value) { GM_setValue( this.attributes["data-key"], Boolean(value) ); }, }, { text: "解析站网址", type: "input", attributes: { "data-key": "baidu-baiduwp-php-url", "data-default-value": "", }, getValue() { return GM_getValue( this.attributes["data-key"], this.attributes["data-default-value"] ); }, callback(event, value) { GM_setValue(this.attributes["data-key"], value); }, placeholder: "使用了baiduwp-php源码的网站,例如:https://www.example.com/", }, { text: "表单参数", type: "input", attributes: { "data-key": "baidu-baiduwp-php-post-form", "data-default-value": "", }, getValue() { return GM_getValue( this.attributes["data-key"], this.attributes["data-default-value"] ); }, callback(event, value) { GM_setValue(this.attributes["data-key"], value); }, placeholder: "POST表单,例如:surl={#shareCode#}&pwd={#accessCode#}&password=", }, ], }, ], }, { type: "蓝奏云", key: "lanzou", checkbox_oneOrMoreStatic: true, checkbox_openBlank: true, checkbox_static_scheme: true, text_static_scheme_forward: true, range_innerText: true, range_innerText_default_value: 20, range_accessCode_after_text: true, range_accessCode_after_text_default_value: 10, range_innerHTML: true, range_innerHTML_default_value: 100, range_accessCode_after_html: true, range_accessCode_after_html_default_value: 15, ownFormList: [ { text: "其它配置", type: "forms", forms: [ { text: "蓝奏云域名", type: "input", attributes: { "data-key": "lanzou-host-name", "data-default-value": NetDiskData.lanzou_defaultHostName, }, getValue() { return GM_getValue( this.attributes["data-key"], this.attributes["data-default-value"] ); }, callback(event, value) { GM_setValue(this.attributes["data-key"], value); }, placeholder: `例如:${NetDiskData.lanzou_defaultHostName}`, }, ], }, ], }, { type: "天翼云", key: "tianyiyun", checkbox_oneOrMoreStatic: true, checkbox_openBlank: true, checkbox_static_scheme: true, text_static_scheme_forward: true, range_innerText: true, range_innerText_default_value: 20, range_accessCode_after_text: true, range_accessCode_after_text_default_value: 10, range_innerHTML: true, range_innerHTML_default_value: 100, range_accessCode_after_html: true, range_accessCode_after_html_default_value: 15, }, { type: "中国移动云盘", key: "hecaiyun", checkbox_openBlank: true, range_innerText: true, range_innerText_default_value: 20, range_accessCode_after_text: true, range_accessCode_after_text_default_value: 10, range_innerHTML: true, range_innerHTML_default_value: 100, range_accessCode_after_html: true, range_accessCode_after_html_default_value: 15, }, { type: "阿里云", key: "aliyun", checkbox_openBlank: true, range_innerText: true, range_innerText_default_value: 20, range_accessCode_after_text: true, range_accessCode_after_text_default_value: 10, range_innerHTML: true, range_innerHTML_default_value: 100, range_accessCode_after_html: true, range_accessCode_after_html_default_value: 15, }, { type: "文叔叔", key: "wenshushu", checkbox_oneStatic: true, checkbox_openBlank: true, checkbox_static_scheme: true, text_static_scheme_forward: true, range_innerText: true, range_innerText_default_value: 20, range_accessCode_after_text: true, range_accessCode_after_text_default_value: 10, range_innerHTML: true, range_innerHTML_default_value: 100, range_accessCode_after_html: true, range_accessCode_after_html_default_value: 15, }, { type: "奶牛", key: "nainiu", checkbox_oneOrMoreStatic: true, checkbox_openBlank: true, checkbox_static_scheme: true, text_static_scheme_forward: true, range_innerText: true, range_innerText_default_value: 20, range_accessCode_after_text: true, range_accessCode_after_text_default_value: 10, range_innerHTML: true, range_innerHTML_default_value: 100, range_accessCode_after_html: true, range_accessCode_after_html_default_value: 15, }, { type: "123盘", key: "_123pan", checkbox_oneOrMoreStatic: true, checkbox_openBlank: true, checkbox_static_scheme: true, text_static_scheme_forward: true, range_innerText: true, range_innerText_default_value: 20, range_accessCode_after_text: true, range_accessCode_after_text_default_value: 10, range_innerHTML: true, range_innerHTML_default_value: 100, range_accessCode_after_html: true, range_accessCode_after_html_default_value: 15, }, { type: "微云", key: "weiyun", checkbox_openBlank: true, range_innerText: true, range_innerText_default_value: 20, range_accessCode_after_text: true, range_accessCode_after_text_default_value: 10, range_innerHTML: true, range_innerHTML_default_value: 100, range_accessCode_after_html: true, range_accessCode_after_html_default_value: 15, }, { type: "迅雷云盘", key: "xunlei", checkbox_openBlank: true, range_innerText: true, range_innerText_default_value: 20, range_accessCode_after_text: true, range_accessCode_after_text_default_value: 10, range_innerHTML: true, range_innerHTML_default_value: 100, range_accessCode_after_html: true, range_accessCode_after_html_default_value: 15, }, { type: "115网盘", key: "_115pan", checkbox_openBlank: true, range_innerText: true, range_innerText_default_value: 20, range_accessCode_after_text: true, range_accessCode_after_text_default_value: 10, range_innerHTML: true, range_innerHTML_default_value: 100, range_accessCode_after_html: true, range_accessCode_after_html_default_value: 15, }, { type: "城通网盘", key: "chengtong", checkbox_openBlank: true, range_innerText: true, range_innerText_default_value: 20, range_accessCode_after_text: true, range_accessCode_after_text_default_value: 10, range_innerHTML: true, range_innerHTML_default_value: 100, range_accessCode_after_html: true, range_accessCode_after_html_default_value: 15, }, { type: "夸克网盘", key: "kuake", checkbox_openBlank: true, range_innerText: true, range_innerText_default_value: 20, range_accessCode_after_text: true, range_accessCode_after_text_default_value: 10, range_innerHTML: true, range_innerHTML_default_value: 100, range_accessCode_after_html: true, range_accessCode_after_html_default_value: 15, }, { type: "BT磁力", key: "magnet", checkbox_openBlank: true, }, { type: "坚果云", key: "jianguoyun", checkbox_oneOrMoreStatic: true, checkbox_openBlank: true, checkbox_static_scheme: true, text_static_scheme_forward: true, range_innerText: true, range_innerText_default_value: 20, range_accessCode_after_text: true, range_accessCode_after_text_default_value: 10, range_innerHTML: true, range_innerHTML_default_value: 100, range_accessCode_after_html: true, range_accessCode_after_html_default_value: 15, }, { type: "OneDrive", key: "onedrive", checkbox_openBlank: true, range_innerText: true, range_innerText_default_value: 20, range_accessCode_after_text: true, range_accessCode_after_text_default_value: 10, range_innerHTML: true, range_innerHTML_default_value: 100, range_accessCode_after_html: true, range_accessCode_after_html_default_value: 15, }, { type: "UC网盘", key: "uc", checkbox_oneOrMoreStatic: true, checkbox_openBlank: true, checkbox_static_scheme: true, text_static_scheme_forward: true, range_innerText: true, range_innerText_default_value: 20, range_accessCode_after_text: true, range_accessCode_after_text_default_value: 10, range_innerHTML: true, range_innerHTML_default_value: 100, range_accessCode_after_html: true, range_accessCode_after_html_default_value: 15, }, ]; netDiskDetailsList.forEach((item) => { let formsList = []; if (item.range_innerText || item.range_accessCode_after_text) { let matchTextList = []; if (item.range_innerText) { matchTextList.push({ text: "提取码间隔前的字符长度", type: "slider", attributes: { "data-key": "innerText_" + item.key, "data-default-value": item.range_innerText_default_value, }, getValue() { return GM_getValue( this.attributes["data-key"], this.attributes["data-default-value"] ); }, callback(event, value) { GM_setValue(this.attributes["data-key"], value); }, min: 0, max: 100, }); } if (item.range_accessCode_after_text) { matchTextList.push({ text: "提取码间隔后的字符长度", type: "slider", attributes: { "data-key": "accessCode_after_text_" + item.key, "data-default-value": item.range_accessCode_after_text_default_value, }, getValue() { return GM_getValue( this.attributes["data-key"], this.attributes["data-default-value"] ); }, callback(event, value) { GM_setValue(this.attributes["data-key"], value); }, min: 0, max: 100, }); } if (matchTextList.length) { formsList.push({ text: "提取码文本匹配Text", type: "forms", forms: matchTextList, }); } } if (item.range_innerHTML || item.range_accessCode_after_html) { let matchTextList = []; if (item.range_innerHTML) { matchTextList.push({ text: "提取码间隔前的字符长度", type: "slider", attributes: { "data-key": "innerHTML_" + item.key, "data-default-value": item.range_innerHTML_default_value, }, getValue() { return GM_getValue( this.attributes["data-key"], this.attributes["data-default-value"] ); }, callback(event, value) { GM_setValue(this.attributes["data-key"], value); }, min: 0, max: 500, }); } if (item.range_accessCode_after_html) { matchTextList.push({ text: "提取码间隔后的字符长度", type: "slider", attributes: { "data-key": "accessCode_after_html_" + item.key, "data-default-value": item.range_accessCode_after_html_default_value, }, getValue() { return GM_getValue( this.attributes["data-key"], this.attributes["data-default-value"] ); }, callback(event, value) { GM_setValue(this.attributes["data-key"], value); }, min: 0, max: 200, }); } if (matchTextList.length) { formsList.push({ text: "提取码文本匹配HTML", type: "forms", forms: matchTextList, }); } } if ( item.checkbox_openBlank || item.checkbox_oneStatic || item.checkbox_oneOrMoreStatic ) { let functionFormsList = []; /* 新标签页打开 */ if (item.checkbox_openBlank) { functionFormsList.push({ text: "新标签页打开", type: "switch", attributes: { "data-key": `${item.key}-open-enable`, "data-default-value": false, }, getValue() { return Boolean( GM_getValue( this.attributes["data-key"], this.attributes["data-default-value"] ) ); }, callback(event, value) { GM_setValue(this.attributes["data-key"], Boolean(value)); if ( item.checkbox_oneStatic || item.checkbox_oneOrMoreStatic ) { /* 新标签页打开和单/多文件解析只能开启一个 */ /** * @type {HTMLInputElement} */ let checkboxElement = document.querySelector( `li[data-key="${item.key}-static-enable"] input[type=checkbox]` ); let checkboxCoreElement = document.querySelector( `li[data-key="${item.key}-static-enable"] span.pops-panel-switch__core` ); if (value == true && checkboxElement.checked == true) { checkboxCoreElement.click(); } } }, }); } /* 单文件解析|多文件解析 */ if (item.checkbox_oneStatic || item.checkbox_oneOrMoreStatic) { functionFormsList.push({ text: `${ item.checkbox_oneStatic ? "单文件解析" : "多文件解析" }`, type: "switch", attributes: { "data-key": `${item.key}-static-enable`, "data-default-value": false, }, getValue() { return Boolean( GM_getValue( this.attributes["data-key"], this.attributes["data-default-value"] ) ); }, callback(event, value) { GM_setValue(this.attributes["data-key"], Boolean(value)); if (item.checkbox_openBlank) { /* 新标签页打开和单/多文件解析只能开启一个 */ /** * @type {HTMLInputElement} */ let checkboxElement = document.querySelector( `li[data-key="${item.key}-open-enable"] input[type=checkbox]` ); let checkboxCoreElement = document.querySelector( `li[data-key="${item.key}-open-enable"] span.pops-panel-switch__core` ); if (value == true && checkboxElement.checked == true) { checkboxCoreElement.click(); } } }, }); /* Scheme转发直链 */ if (item.checkbox_static_scheme) { functionFormsList.push({ text: "Scheme转发直链", type: "switch", attributes: { "data-key": `${item.key}-static-scheme-enable`, "data-default-value": false, }, getValue() { return Boolean( GM_getValue( this.attributes["data-key"], this.attributes["data-default-value"] ) ); }, callback(event, value) { GM_setValue(this.attributes["data-key"], Boolean(value)); }, }); /* Scheme链接 */ if (item.text_static_scheme_forward) { functionFormsList.push({ text: "Scheme链接", type: "input", attributes: { "data-key": `${item.key}-static-scheme-forward`, "data-default-value": "", }, getValue() { return GM_getValue( this.attributes["data-key"], this.attributes["data-default-value"] ); }, callback(event, value) { GM_setValue(this.attributes["data-key"], value); }, placeholder: "如: jumpwsv://go?package=xx&activity=xx&intentAction=xx&intentData=xx&intentExtra=xx", }); } } } formsList.push({ text: "功能", type: "forms", forms: functionFormsList, }); } if (item.ownFormList) { formsList = formsList.concat(item.ownFormList); } let asideTitle = item.key; if (item.key in NetDiskUI.src.icon) { if (pops.isPhone()) { asideTitle = ` <div style=" width: 20px; height: 20px; background: url(${NetDiskUI.src.icon[item.key]}) no-repeat; background-size: 100% 100%; ">`; } else { asideTitle = ` <div style=" width: 20px; height: 20px; background: url(${NetDiskUI.src.icon[item.key]}) no-repeat; background-size: 100% 100%; "></div> <div style="margin-left: 4px;">${item.type}</div>`; } } contentDetails.push({ id: "netdisk-panel-config-" + item.key, title: asideTitle, headerTitle: item.type, attributes: { "data-key": item.key, }, forms: formsList, }); }); } addNetDiskSetting(); NetDiskPops.panel( { title: { text: `${GM_info?.script?.name || "网盘链接识别"}-设置`, position: "center", }, content: contentDetails, class: "whitesevPopSetting", }, NetDiskUI.popsStyle.settingView ); }, /** * 设置 悬浮按钮所有事件 */ setSuspensionEvent() { let needDragElement = document.querySelector("#whitesevSuspensionId"); let dragNode = new AnyTouch(needDragElement); /** * @type {number[]} */ let netDiskLinkViewTimer = null; let moveFlag = false; /* 是否是双击 */ let isDouble = false; /* 点击元素,left偏移 */ let clickElementLeftOffset = 0; /* 点击元素,top偏移 */ let clickElementTopOffset = 0; /** * 设置悬浮按钮 按下事件 */ dragNode.on("pan", function (event) { if (!moveFlag) { moveFlag = true; if (event.nativeEvent.offsetX) { clickElementLeftOffset = parseInt(event.nativeEvent.offsetX); } else { clickElementLeftOffset = parseInt(event.getOffset().x); } if (event.nativeEvent.offsetY) { clickElementTopOffset = parseInt(event.nativeEvent.offsetY); } else { clickElementTopOffset = parseInt(event.getOffset().y); } DOMUtils.css(needDragElement, { cursor: "move", transition: "none", }); } /** * 移动 */ if (event.phase === "move") { /* 悬浮按钮大小不能超过250px */ if (clickElementLeftOffset > 250 || clickElementTopOffset > 250) { return; } /* left偏移最大值 */ let maxLeftOffset = DOMUtils.width(globalThis) - NetDiskUI.size; /* top偏移的最大值 */ let maxTopOffset = DOMUtils.height(globalThis) - NetDiskUI.size; /* 当前移动的left偏移 */ let currentSuspensionLeftOffset = event.x - clickElementLeftOffset; /* 当前移动的top偏移 */ let currentSuspensionTopOffset = event.y - clickElementTopOffset; /* 不允许超过窗口最大宽度 */ currentSuspensionLeftOffset = currentSuspensionLeftOffset > maxLeftOffset ? maxLeftOffset : currentSuspensionLeftOffset; /* 不允许超过窗口最大高度 */ currentSuspensionTopOffset = currentSuspensionTopOffset > maxTopOffset ? maxTopOffset : currentSuspensionTopOffset; /* 不允许小于0 */ currentSuspensionLeftOffset = currentSuspensionLeftOffset < 0 ? 0 : currentSuspensionLeftOffset; /* 不允许小于0 */ currentSuspensionTopOffset = currentSuspensionTopOffset < 0 ? 0 : currentSuspensionTopOffset; if (NetDiskUI.suspension.isTopWindow()) { GM_setValue("suspensionX", currentSuspensionLeftOffset); GM_setValue("suspensionY", currentSuspensionTopOffset); } DOMUtils.css(needDragElement, { left: currentSuspensionLeftOffset + "px", top: currentSuspensionTopOffset + "px", }); } /** * 停止移动 */ if (event.phase === "end") { moveFlag = false; DOMUtils.css(needDragElement, { cursor: "auto", }); /* 获取当前悬浮按钮left偏移 */ let currentSuspensionLeftOffset = parseInt( DOMUtils.css(needDragElement, "left") ); let setCSSLeft = 0; /* 判断悬浮按钮是否在右边区域 */ if (currentSuspensionLeftOffset >= DOMUtils.width(globalThis) / 2) { /* 设置悬浮按钮的left偏移 */ setCSSLeft = DOMUtils.width(globalThis) - NetDiskUI.size; if (NetDiskUI.suspension.isTopWindow()) { GM_setValue("isRight", true); } } else { if (NetDiskUI.suspension.isTopWindow()) { GM_setValue("isRight", false); } } if (NetDiskUI.suspension.isTopWindow()) { GM_setValue("suspensionX", setCSSLeft); } DOMUtils.css(needDragElement, { left: setCSSLeft + "px", transition: "left 300ms ease 0s", }); } }); /** * 设置悬浮按钮 点击/按下事件 */ dragNode.on(["click", "tap"], function (event) { clearTimeout(netDiskLinkViewTimer); netDiskLinkViewTimer = null; if (isDouble) { isDouble = false; /* 判定为双击 */ NetDiskUI.suspension.showSettingView(); } else { netDiskLinkViewTimer = setTimeout(() => { isDouble = false; NetDiskUI.view.show(); }, 200); isDouble = true; } }); NetDiskUI.view.registerContextMenu(needDragElement, undefined, [ { text: "设置", callback() { log.info("打开-设置"); NetDiskUI.suspension.showSettingView(); }, }, { text: "历史匹配记录", callback() { log.info("打开-历史匹配记录"); NetDiskUI.netDiskHistoryMatch.show(); }, }, { text: "访问码规则", callback() { log.info("打开-访问码规则"); NetDiskUI.accessCodeRule.show(); }, }, { text: "自定义规则", callback() { log.info("打开-自定义规则"); NetDiskUI.customRules.show(); }, }, { text: "主动识别文本", callback() { log.info("打开-主动识别文本"); NetDiskUI.matchPasteText.show(); }, }, ]); }, /** * 设置window的resize事件监听,来重新设置悬浮按钮的位置 */ setResizeEventListener() { DOMUtils.on(globalThis, "resize", undefined, () => { let activeElement = document.activeElement; if (utils.isPhone()) { if (["input", "textarea"].includes(activeElement.localName)) { /* 可能是移动端的输入框弹出的键盘导致的resize */ return; } else if ( (activeElement.hasAttribute("contenteditable") && activeElement.getAttribute("contenteditable") === "true") || activeElement.closest("[contenteditable='true']") ) { /* 可能是移动端的输入框弹出的键盘导致的resize */ return; } else if (!document.hasFocus()) { /* 页面失焦 */ return; } } this.setSuspensionPosition(); }); }, /** * 设置悬浮按钮位置 */ setSuspensionPosition() { /* 最大的left偏移*/ let maxLeftOffset = DOMUtils.width(globalThis) - NetDiskUI.size; /* 最大的top偏移 */ let maxTopOffset = DOMUtils.height(globalThis) - NetDiskUI.size; /* 默认的left偏移(悬浮按钮在右边中间) */ let defaultLeftOffset = maxLeftOffset; /* 默认的top偏移(悬浮按钮在右边中间) */ let defaultTopOffset = maxTopOffset / 2; /* 用户自己拖动设置的悬浮按钮left偏移 */ let userSetLeftOffset = GM_getValue("suspensionX", defaultLeftOffset); /* 用户自己拖动设置的悬浮按钮top偏移 */ let userSetTopOffset = GM_getValue("suspensionY", defaultTopOffset); /* 如果存在isRight变量,悬浮按钮放到最右边,否则最左边 */ if (GM_getValue("isRight")) { userSetLeftOffset = maxLeftOffset; } else { userSetLeftOffset = 0; } /* 如果用户设置的top偏移超出最大的top偏移,那么设置用户的偏移为默认的最大top偏移 */ if (userSetTopOffset > maxTopOffset) { userSetTopOffset = maxTopOffset; } else if (userSetTopOffset < 0) { /* 如果用户设置的top偏移为负的,那么是超出边界,归位设置为0 */ userSetTopOffset = 0; } if (NetDiskUI.suspension.isTopWindow()) { /* 当前窗口是顶部窗口,才可以保存移动的值 */ GM_setValue("suspensionX", userSetLeftOffset); GM_setValue("suspensionY", userSetTopOffset); } DOMUtils.css("#whitesevSuspensionId", { left: userSetLeftOffset + "px", top: userSetTopOffset + "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%; } `); }, /** * 悬浮按钮背景轮播 效果为淡入淡出 */ backgroundSwitch() { if (this.isRandBg) { return; } /** * 获取随机背景的数组 * @returns {Array} */ function getRandBgList() { let resultList = []; NetDiskUI.isMatchedNetDiskIconMap.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: { isInitCSS: false, isRegisterEvent: false, show() { if (!this.isInitCSS) { this.isInitCSS = true; this.addCSS(); } if (!this.isRegisterEvent) { this.isRegisterEvent = true; this.registerIconGotoPagePosition(); this.registerNetDiskUrlContextMenu(); this.setNetDiskUrlClickEvent(".netdisk-url a"); } if (!NetDiskUI.uiLinkAlias) { this.createView(); } else { NetDiskUI.uiLinkAlias.show(); } }, addCSS() { GM_addStyle(` .netdisk-url-box:last-child{padding:0 0 10px 0} .netdisk-url-div{display:flex;align-items:center;width:100%;margin:10px 0} .netdisk-icon{margin:0 4px;display:contents} .netdisk-icon .netdisk-icon-img{ cursor: pointer; width:28px; height:28px; min-width:28px; min-height:28px; font-size:13px!important; margin-left: 10px; } .netdisk-icon .netdisk-icon-img, .netdisk-url a { border-radius: 10px; box-shadow: 0 .3px .6px rgb(0 0 0 / 6%),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 0;margin:0 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:0;outline:0} .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:0} .whitesevPop-content p[pop]{text-indent:0} .whitesevPop-button[type=primary]{border-color:#2d8cf0;background-color:#2d8cf0} `); }, /** * 创建视图 */ createView() { let viewAddHTML = ""; NetDiskUI.isMatchedNetDiskIconMap.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 = NetDiskPops.alert( { title: { text: "网盘", position: "center", }, content: { text: viewHTML, html: true, }, btn: { ok: { callback(event) { NetDiskUI.uiLinkAlias = null; event.close(); }, }, close: { callback(event) { NetDiskUI.uiLinkAlias = null; event.close(); }, }, }, mask: { enable: true, clickEvent: { toHide: false, toClose: true, }, clickCallBack() { NetDiskUI.uiLinkAlias.close(); NetDiskUI.uiLinkAlias = null; }, }, class: "whitesevPop", }, NetDiskUI.popsStyle.mainView ); }, /** * 获取视图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"> <div class="netdisk-icon-img" style="background: url(${netDiskImgSrc}) no-repeat;background-size: 100%;" data-netdisk="${netDiskName}" data-sharecode="${shareCode}" data-accesscode="${accessCode}"> </div> </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 {HTMLElement|Window} target * @param {?string} selector * @param {{text:string,callback:Function}[]} showTextList 右键菜单的内容 * @param {string} className className属性 */ registerContextMenu( target, selector, showTextList = [], className = "whitesevSuspensionContextMenu" ) { let data = []; showTextList.forEach((item) => { data.push({ icon: "", text: item.text, callback: item.callback, }); }); pops.rightClickMenu({ target: target, targetSelector: selector, data: data, isAnimation: true, className: className, }); }, /** * 添加新的链接 * @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() { /** * @type {?Generator<HTMLElement, void, any>} */ let findGenerator = null; /** * @type {?IteratorResult<HTMLElement, void>} */ let iterator = null; /** * 上一个的shareCode */ let prevSearchShareCode = null; DOMUtils.on( document, "click", ".whitesevPop .netdisk-icon .netdisk-icon-img", function (event) { let dataSharecode = event.target.getAttribute("data-sharecode"); if ( !GM_getValue( "pops-netdisk-icon-click-event-find-sharecode", NetDiskData.iconDefaultClickEventToFindShareCode ) ) { return; } if (typeof dataSharecode !== "string") { Qmsg.error("获取data-sharecode属性失败"); return; } if (prevSearchShareCode == null) { prevSearchShareCode = dataSharecode; } else if (prevSearchShareCode !== dataSharecode) { /* 切换到另一个shareCode搜索 */ log.info( `上一个搜索:${prevSearchShareCode},切换至:${dataSharecode}` ); findGenerator = null; iterator = null; prevSearchShareCode = dataSharecode; } if (findGenerator == null) { /* 未找到元素或者已迭代完毕 */ findGenerator = utils.findElementsWithText( document.documentElement, dataSharecode, (element) => Boolean(element.closest(".pops")) ); iterator = findGenerator.next(); } if (iterator.value) { log.success(["定位元素", iterator]); if ( iterator.value.nodeType === Node.ELEMENT_NODE && iterator.value.getClientRects().length ) { /* 可见 */ /* 滚动到该元素 */ iterator.value.scrollIntoView({ behavior: "smooth", block: "center", inline: "nearest", }); if ( GM_getValue( "pops-netdisk-icon-click-event-find-sharecode-with-select", NetDiskData.iconDefaultClickEventToFindShareCodeWithSelect ) ) { /* 开启功能 */ let elementText = iterator.value.innerText || iterator.value.textContent; let childTextNode = undefined; let startIndex = undefined; let endIndex = undefined; if (elementText.includes(dataSharecode)) { /* 文字包含shareCode */ let textNodeList = Array.from( iterator.value.childNodes ).filter((ele) => ele.nodeType === Node.TEXT_NODE); for (const textNode of textNodeList) { if (textNode.textContent.includes(dataSharecode)) { childTextNode = textNode; startIndex = textNode.textContent.indexOf(dataSharecode); endIndex = startIndex + dataSharecode.length; break; } } } try { utils.selectElementText( iterator.value, childTextNode, startIndex, endIndex ); } catch (error) { log.error(error); utils.selectElementText(iterator.value); } } } else if ( iterator.value.nodeType === Node.TEXT_NODE && iterator.value.parentElement.getClientRects().length ) { /* #text元素且可见 */ if ( GM_getValue( "pops-netdisk-icon-click-event-find-sharecode-with-select", NetDiskData.iconDefaultClickEventToFindShareCodeWithSelect ) ) { let elementText = iterator.value.textContent || iterator.value.nodeValue; let childTextNode = iterator.value; let startIndex = elementText.indexOf(dataSharecode); let endIndex = startIndex + dataSharecode.length; try { utils.selectElementText( iterator.value, childTextNode, startIndex, endIndex ); } catch (error) { log.error(error); utils.selectElementText(iterator.value.parentElement); } let selection = globalThis.getSelection(); if (selection.rangeCount > 0) { let range = selection.getRangeAt(0); let rect = range.getBoundingClientRect(); let scrollYOffset = globalThis.scrollY; /* 居中定位 */ let position = rect.top + scrollYOffset - globalThis.innerHeight / 2; globalThis.scrollTo({ behavior: "smooth", top: position, }); } else { iterator.value.parentElement.scrollIntoView({ behavior: "smooth", block: "center", inline: "nearest", }); } } else { try { let range = new Range(); range.selectNodeContents(iterator.value); let rect = range.getBoundingClientRect(); let scrollYOffset = globalThis.scrollY; /* 居中定位 */ let position = rect.top + scrollYOffset - globalThis.innerHeight / 2; globalThis.scrollTo({ behavior: "smooth", top: position, }); } catch (error) { log.error(error); iterator.value.parentElement.scrollIntoView({ behavior: "smooth", block: "center", inline: "nearest", }); } } } else { log.error(["无法定位该元素位置", iterator.value]); Qmsg.error( `无法定位该元素位置,类型:<${( iterator.value.nodeName || iterator.value.localName || iterator.value.tagName ).toLowerCase()}>`, { html: false, } ); } } iterator = findGenerator.next(); if (iterator.done) { /* 循环查找 */ if ( !GM_getValue( "pops-netdisk-icon-click-event-loop-find-sharecode", NetDiskData.iconDefaultClickEventToFindShareCodeByLoop ) ) { Qmsg.info("已经定位至最后一个元素了"); return; } findGenerator = null; iterator = null; } } ); }, /** * 设置全局监听url的右击菜单事件 */ registerNetDiskUrlContextMenu() { NetDiskUI.view.registerContextMenu( document, ".whitesevPop .netdisk-url a", [ { text: "复制链接", callback: function (event, contextMenuEvent) { let linkElement = contextMenuEvent.target; let netDiskName = linkElement.getAttribute("data-netdisk"); let netDiskIndex = linkElement.getAttribute("data-netdisk-index"); let shareCode = linkElement.getAttribute("data-sharecode"); let accessCode = linkElement.getAttribute("data-accesscode"); NetDiskParse.copyText( netDiskName, netDiskIndex, shareCode, accessCode ); }, }, { text: "访问链接", callback: function (event, contextMenuEvent) { let linkElement = contextMenuEvent.target; let netDiskName = linkElement.getAttribute("data-netdisk"); let netDiskIndex = linkElement.getAttribute("data-netdisk-index"); let shareCode = linkElement.getAttribute("data-sharecode"); let accessCode = linkElement.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 (event, contextMenuEvent) { let linkElement = contextMenuEvent.target; let netDiskName = linkElement.getAttribute("data-netdisk"); let netDiskIndex = linkElement.getAttribute("data-netdisk-index"); let shareCode = linkElement.getAttribute("data-sharecode"); let accessCode = linkElement.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(` .pops-folder-list .list-name-text{ max-width: 300px; } .netdisk-static-link-onefile .pops-folder-list .list-name-text{ max-width: 220px; } .netdisk-static-link-onefile .pops-mobile-folder-content .pops-folder-list .list-name-text{ max-width: unset; } `); } }, /** * 单文件直链弹窗 * @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("成功获取单文件直链"); NetDiskPops.folder( { title: { text: fileDetails.title, }, folder: [ { fileName: fileDetails.fileName, fileSize: fileDetails.fileSize, fileType: fileDetails.fileType ?? "", createTime: fileDetails.fileUploadTime || fileDetails.fileLatestTime, latestTime: fileDetails.fileLatestTime || fileDetails.fileUploadTime, isFolder: false, index: 0, async clickEvent() { if (typeof fileDetails.clickCallBack === "function") { fileDetails.clickCallBack(fileDetails); } else { return { autoDownload: true, mode: "aBlank", url: fileDetails.downloadUrl, }; } }, }, ], btn: { ok: { text: "下载", callback() { if (typeof fileDetails.clickCallBack === "function") { fileDetails.clickCallBack(fileDetails); } else { window.open(fileDetails.downloadUrl, "_blank"); } }, }, }, class: "netdisk-static-link-onefile", }, NetDiskUI.popsStyle.oneFileStaticView ); }, /** * 多文件直链弹窗 * @param {string} title 标题 * @param {?{ * fileName: string, * fileSize: string|number, * fileType: ?string, * createTime: ?string, * latestTime: ?string, * isFolder: boolean, * index: ?number, * clickCallBack: ?(event:Event,_config_: object)=>{} * }[]} [folderInfoList=[]] 文件夹信息 */ moreFile(title, folderInfoList = []) { this.addCSS(); Qmsg.success("成功获取多文件直链"); log.success(["多文件直链信息", folderInfoList]); NetDiskPops.folder( { title: { text: title, }, folder: folderInfoList, }, NetDiskUI.popsStyle.moreFileStaticView ); }, }, /** * 需要重新输入新密码的弹窗 * @param {string} [title="密码错误"] 标题 * @param {string} [netDiskName=""] 网盘名称 * @param {number} netDiskIndex 网盘名称索引下标 * @param {string} shareCode * @param {Function} [okCallBack=()=>{}] */ newAccessCodeView( title = "密码错误", netDiskName = "", netDiskIndex, shareCode, okCallBack = () => {} ) { NetDiskPops.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, }, }, NetDiskUI.popsStyle.inputNewAccessCodeView ); /** * 注册键盘回车事件 */ utils.listenKeyboard( document.querySelector(".pops-prompt-content input"), "keypress", (keyName) => { if (keyName === "Enter") { document.querySelector(".pops-prompt-btn-ok")?.click(); } } ); }, /** * 网盘历史匹配到的记录弹窗 */ netDiskHistoryMatch: { /** * 本地存储的keyName */ storageKey: "netDiskHistoryMatch", /** * 是否已添加CSS */ isAddCss: false, /** * 是否已设置DOM事件 */ isSetSearchEvent: false, /** * 是否已设置其它DOM事件 */ isSetOtherEvent: false, /** * 显示弹窗 */ 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>`; NetDiskPops.confirm( { title: { text: "历史匹配记录", position: "center", }, content: { text: dataHTML, html: true, }, btn: { reverse: true, position: "space-between", ok: { enable: true, callback(event) { event.close(); }, }, close: { callback(event) { event.close(); }, }, cancel: { enable: false, }, other: { enable: true, text: `清空所有(${data.length})`, type: "xiaomi-primary", callback: (event) => { NetDiskPops.confirm({ title: { text: "删除", position: "center", }, content: { text: "确定清空所有的记录?", html: false, }, btn: { ok: { enable: true, callback(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: { text: "取消", enable: true, }, }, }); }, }, }, class: "whitesevPopNetDiskHistoryMatch", }, NetDiskUI.popsStyle.historyMatchView ); this.setDataPaging(data); this.setEvent(); this.setSearchEvent(); this.setContextMenuEvent(); }, /** * 添加CSS */ 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 .netdisk-icon-img{ width: 28px; height: 28px; min-width: 28px; min-height: 28px; font-size: 13px!important; 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 {string} */ 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> <div class="netdisk-icon-img" style="background: url(${ NetDiskUI.src.icon[item.netDiskName] }) no-repeat;background-size:100%"></div> </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>`; }, /** * 设置只执行一次的事件 */ 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 = NetDiskPops.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 = NetDiskPops.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.listenKeyboard( document.querySelector( ".whitesevPopNetDiskHistoryMatch .netdiskrecord-search input" ), "keypress", (keyName) => { if (keyName === "Enter") { searchEvent(); } } ); }, /** * 设置右击菜单事件 */ setContextMenuEvent() { NetDiskUI.view.registerContextMenu( document.querySelector(".whitesevPopNetDiskHistoryMatch"), ".netdiskrecord-link a", [ { text: "复制链接", callback: function (event, contextMenuEvent) { let linkElement = contextMenuEvent.target; let netDiskName = linkElement.getAttribute("data-netdisk"); let netDiskIndex = linkElement.getAttribute("data-netdisk-index"); let shareCode = linkElement.getAttribute("data-sharecode"); let accessCode = linkElement.getAttribute("data-accesscode"); NetDiskParse.copyText( netDiskName, netDiskIndex, shareCode, accessCode ); }, }, { text: "访问链接", callback: function (event, contextMenuEvent) { let linkElement = contextMenuEvent.target; let netDiskName = linkElement.getAttribute("data-netdisk"); let netDiskIndex = linkElement.getAttribute("data-netdisk-index"); let shareCode = linkElement.getAttribute("data-sharecode"); let accessCode = linkElement.getAttribute("data-accesscode"); let url = NetDiskParse.getBlankUrl( netDiskName, netDiskIndex, shareCode, accessCode ); NetDiskParse.blank(url, netDiskName, shareCode, accessCode); }, }, { text: "修改访问码", callback: function (event, contextMenuEvent) { let linkElement = contextMenuEvent.target; let netDiskName = linkElement.getAttribute("data-netdisk"); let netDiskIndex = parseInt( linkElement.getAttribute("data-netdisk-index") ); let shareCode = linkElement.getAttribute("data-sharecode"); let accessCode = linkElement.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 ); linkElement .closest("li") .querySelector( ".netdiskrecord-update-time" ).lastChild.textContent = utils.formatTime(currentTime); linkElement.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) { log.success("删除 ===> ", data[index]); data.splice(index, 1); break; } } GM_setValue(this.storageKey, data); }, /** * 清空所有配置 */ clearNetDiskHistoryMatchData() { GM_setValue(this.storageKey, []); }, }, /** * 自定义访问码规则,用于设置某个网站下的某个网盘链接的固定访问码 */ accessCodeRule: { /** * 是否已初始化 */ isInit: false, /** * 弹窗的className */ accessCodeRuleDialogClassName: "whitesevPopNetDiskAccessCodeRule", /** * 显示弹窗 */ show() { let that = this; this.init(); let popsConfirm = NetDiskPops.confirm( { title: { text: "自定义访问码规则", position: "center", }, content: { text: ` <div class="netdisk-accesscode-rule-table"> <ul> ${that.getShowItemHTML()} </ul> </div> `, html: true, }, btn: { merge: true, reverse: false, position: "space-between", ok: { enable: true, text: "添加", callback(event) { that.showRule(event); }, }, close: { callback(event) { event.close(); }, }, cancel: { enable: true, }, other: { enable: true, type: "xiaomi-primary", text: `清空所有`, callback(event) { NetDiskPops.confirm({ title: { text: "删除", position: "center", }, content: { text: "确定清空所有的规则?", html: false, }, btn: { ok: { enable: true, callback: function (okEvent) { log.success("清空所有"); that.deleteAllValue(); if (that.getValue().length) { Qmsg.error("清空全部规则失败"); return; } else { Qmsg.success("已清空全部规则"); } that.setDeleteAllBtnText(event.animElement); event.animElement.querySelector( ".pops-confirm-content ul" ).innerHTML = ""; okEvent.close(); }, }, cancel: { text: "取消", enable: true, }, }, }); }, }, }, class: this.accessCodeRuleDialogClassName, }, NetDiskUI.popsStyle.accessCodeRuleView ); that.setDeleteAllBtnText(popsConfirm.animElement); this.setEvent(popsConfirm); }, getShowItemHTML() { let result = ""; this.getValue().forEach((item) => { let netdiskName = ""; item.netdisk.forEach((_netdisk_) => { netdiskName += _netdisk_.name; netdiskName += "、"; }); netdiskName = netdiskName.replace(/、$/g, ""); result += ` <li> <div class="accesscode-rule-url-regexp"> <p>匹配规则</p> ${item.urlRegexp} </div> <div class="accesscode-rule-netdisk-name"> <p>匹配网盘</p> ${netdiskName} </div> <div class="accesscode-rule-accesscode"> <p>固定值</p> ${item.accessCode} </div> <div class="accesscode-rule-functions" data-json='${JSON.stringify( item )}'> <p>功能</p> <button style="background: #46cb31;color: #fff;" data-edit>修改</button> <button style="background: #263cf3;color: #fff;" data-delete>删除</button> </div> </li> `; }); return result; }, init() { if (this.isInit) { return; } GM_addStyle(` .pops-confirm-content .whitesev-accesscode-rule{ display: flex; align-items: center; justify-content: space-between; margin: 15px 15px; } .pops-confirm-content div.netdisk-accesscode-rule-table{ /* height: calc( 85% - 40px); */ overflow: auto; } .pops-confirm-content .netdisk-accesscode-rule-table .accesscode-rule-url-regexp, .pops-confirm-content .netdisk-accesscode-rule-table .accesscode-rule-netdisk-name, .pops-confirm-content .netdisk-accesscode-rule-table .accesscode-rule-accesscode, .pops-confirm-content .netdisk-accesscode-rule-table .accesscode-rule-functions{ display: flex; margin: 5px 0px; } .pops-confirm-content .netdisk-accesscode-rule-table .accesscode-rule-url-regexp p, .pops-confirm-content .netdisk-accesscode-rule-table .accesscode-rule-netdisk-name p, .pops-confirm-content .netdisk-accesscode-rule-table .accesscode-rule-accesscode p, .pops-confirm-content .netdisk-accesscode-rule-table .accesscode-rule-functions p{ min-width: 80px; max-width: 80px; align-self: center; } .pops-confirm-content .netdisk-accesscode-rule-table 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; } `); }, /** * 显示规则弹窗进行添加/修改 * @param {object} mainEvent * @param {boolean} isEdit 是否是修改模式 * @param {{ * urlRegexp: string, * netdisk: { * name:string, * value:string, * }[], * accessCode: string, * }} oldValue 当isEdie为true时传入的值 */ showRule(mainEvent, isEdit = false, oldValue) { let that = this; let popsConfirm = NetDiskPops.confirm( { title: { text: isEdit ? "修改规则" : "添加规则", position: "center", }, content: { text: ` <div class="whitesev-accesscode-rule"> <div type-name>匹配网站</div> <input type="text" placeholder="请输入需要匹配的正则规则" val-key="access-rule-url" /> </div> <div class="whitesev-accesscode-rule"> <div>匹配网盘</div> <select val-key="access-rule-netdisk" multiple="true" style="height: auto;"> <option data-value="baidu">百度网盘</option> <option data-value="lanzou">蓝奏云</option> <option data-value="tianyiyun">天翼云</option> <option data-value="hecaiyun">中国移动云盘</option> <option data-value="aliyun">阿里云</option> <option data-value="wenshushu">文叔叔</option> <option data-value="nainiu">奶牛</option> <option data-value="_123pan">123盘</option> <option data-value="weiyun">微云</option> <option data-value="xunlei">迅雷云盘</option> <option data-value="_115pan">115网盘</option> <option data-value="chengtong">城通网盘</option> <option data-value="kuake">夸克网盘</option> <option data-value="jianguoyun">坚果云</option> <option data-value="onedrive">OneDrive</option> </select> </div> <div class="whitesev-accesscode-rule"> <div>固定值</div> <input type="text" placeholder="请输入固定的访问码" val-key="access-rule-accesscode" /> </div> `, html: true, }, btn: { ok: { enable: true, text: isEdit ? "修改" : "添加", callback(event) { let accessRuleUrl = event.popsElement.querySelector( 'input[val-key="access-rule-url"]' ).value; /** * @type {{name:string,value:string}[]} */ let accessRuleNetDisk = []; let accessRuleNetDiskElement = event.popsElement.querySelector( 'select[val-key="access-rule-netdisk"]' ); Array.from(accessRuleNetDiskElement.selectedOptions).forEach( (item) => { accessRuleNetDisk.push({ name: item.value, value: item.getAttribute("data-value"), }); } ); let accessRuleAccessCode = event.popsElement.querySelector( 'input[val-key="access-rule-accesscode"]' ).value; if (!that.checkRuleUrlValid(accessRuleUrl)) { log.error(["验证失败", accessRuleUrl]); return; } if (isEdit) { /* 编辑 */ if ( that.changeValue(oldValue, { urlRegexp: accessRuleUrl, netdisk: accessRuleNetDisk, accessCode: accessRuleAccessCode, }) ) { log.success([ "修改成功", { urlRegexp: accessRuleUrl, netdisk: accessRuleNetDisk, accessCode: accessRuleAccessCode, }, ]); Qmsg.success("修改成功"); mainEvent.animElement.querySelector( ".netdisk-accesscode-rule-table ul" ).innerHTML = that.getShowItemHTML(); popsConfirm.close(); } else { Qmsg.error("修改失败"); } } else { /* 添加 */ if ( that.addValue({ urlRegexp: accessRuleUrl, netdisk: accessRuleNetDisk, accessCode: accessRuleAccessCode, }) ) { Qmsg.success("添加成功"); mainEvent.animElement.querySelector( ".netdisk-accesscode-rule-table ul" ).innerHTML = that.getShowItemHTML(); that.setDeleteAllBtnText(mainEvent.animElement); popsConfirm.close(); } else { Qmsg.error("已存在重复的规则"); } } }, }, cancel: { text: "取消", enable: true, }, }, class: "whitesevPopNetDiskAccessCodeRuleAddOrEdit", }, NetDiskUI.popsStyle.accessCodeRuleEditView ); this.setRuleEvent(popsConfirm.element); if (isEdit) { popsConfirm.element.querySelector( '.whitesev-accesscode-rule input[val-key="access-rule-url"]' ).value = oldValue.urlRegexp; let optionElement = popsConfirm.element.querySelectorAll( '.whitesev-accesscode-rule select[val-key="access-rule-netdisk"] option' ); oldValue.netdisk.forEach((item) => { optionElement.forEach((element) => { if (element.getAttribute("data-value") === item.value) { element.selected = true; log.success(["选中", element]); return; } }); }); popsConfirm.element.querySelector( '.whitesev-accesscode-rule input[val-key="access-rule-accesscode"]' ).value = oldValue.accessCode; } }, /** * 修改 删除所有(xx)的文字 * @param {HTMLElement} element */ setDeleteAllBtnText(element) { ( element.querySelector( ".pops-confirm-btn button.pops-confirm-btn-other" ) || document.querySelector( ".whitesevPopNetDiskAccessCodeRule .pops-confirm-btn button.pops-confirm-btn-other" ) ).textContent = `清空所有(${this.getValue().length})`; }, /** * 校验填写的匹配网站正则规则是否正确 * @param {string} accessRuleUrl 填写的匹配网站正则规则 * @returns {boolean} */ checkRuleUrlValid(accessRuleUrl) { if (utils.isNull(accessRuleUrl)) { Qmsg.error("匹配网站的正则不能为空或纯空格"); return false; } try { new RegExp(accessRuleUrl); } catch (error) { log.error(error); Qmsg.error("匹配网站的正则错误</br>" + error.message, { html: true, timeout: 5000, }); return false; } return true; }, /** * 设置事件 * @param {object} event */ setEvent(event) { let that = this; DOMUtils.on( event.animElement, "click", ".netdisk-accesscode-rule-table div.accesscode-rule-functions button[data-delete]", function () { let dataJSON = this.closest( ".accesscode-rule-functions" ).getAttribute("data-json"); dataJSON = utils.toJSON(dataJSON); log.success(["删除👉", dataJSON]); if (that.deleteValue(dataJSON)) { this.closest("li").remove(); that.setDeleteAllBtnText(event.animElement); } else { Qmsg.error("删除失败"); } } ); DOMUtils.on( event.element, "click", ".netdisk-accesscode-rule-table div.accesscode-rule-functions button[data-edit]", function () { let dataJSON = this.closest( ".accesscode-rule-functions" ).getAttribute("data-json"); dataJSON = utils.toJSON(dataJSON); log.success(["修改👉", dataJSON]); let newEvent = Object.assign({}, event); newEvent.animElement = newEvent.element; that.showRule(newEvent, true, dataJSON); } ); }, /** * 设置事件 * @param {HTMLElement} element 弹窗元素 */ setRuleEvent(element) {}, /** * 获取值 * @returns {{ * urlRegexp: string, * netdisk: {name:string,value:string}[] * accessCode: string, * }[]} */ getValue() { return GM_getValue("accessCodeRule", []); }, /** * 设置值 * @param {{ * urlRegexp: string, * netdisk: {name:string,value:string}[] * accessCode: string, * }} value */ setValue(value) { let localData = this.getValue(); localData.push(value); GM_setValue("accessCodeRule", localData); }, /** * 修改值 * @param {{ * urlRegexp: string, * netdisk: {name:string,value:string}[] * accessCode: string, * }} oldValue * @param {{ * urlRegexp: string, * netdisk: {name:string,value:string}[] * accessCode: string, * }} newValue * @returns {boolean} 是否修改成功 */ changeValue(oldValue, newValue) { let result = false; let localData = this.getValue(); let oldValueStr = JSON.stringify(oldValue); for (let i = 0; i < localData.length; i++) { if (JSON.stringify(localData[i]) === oldValueStr) { localData[i] = newValue; result = true; break; } } GM_setValue("accessCodeRule", localData); return result; }, /** * 添加值 * @param {{ * urlRegexp: string, * netdisk: {name:string,value:string}[] * accessCode: string, * }} value */ addValue(value) { let result = true; let localData = this.getValue(); for (let i = 0; i < localData.length; i++) { if ( localData[i].urlRegexp === value.urlRegexp && localData[i].netdisk === value.netdisk ) { result = false; break; } } if (result) { localData.push(value); this.setValue(value); } return result; }, /** * 删除值 */ deleteValue(value) { let result = false; let localData = this.getValue(); let valueStr = JSON.stringify(value); for (let i = 0; i < localData.length; i++) { if (JSON.stringify(localData[i]) === valueStr) { localData.splice(i, 1); result = true; break; } } if (result) { GM_setValue("accessCodeRule", localData); } return result; }, /** * 清空所有规则 */ deleteAllValue() { GM_setValue("accessCodeRule", []); }, }, /** * 用户自定义规则 */ customRules: { isInitCSS: false, show() { let that = this; this.initCSS(); let popsConfirm = NetDiskPops.confirm( { title: { text: "自定义规则", position: "center", }, content: { text: ` <textarea class="netdisk-custom-rules" placeholder="请输入自定义规则"></textarea> `, html: true, }, btn: { merge: true, mergeReverse: false, reverse: false, position: "space-between", ok: { text: "保存", callback(event) { let textAreaElement = event.popsElement.querySelector( "textarea.netdisk-custom-rules" ); try { if (textAreaElement.value.trim() === "") { NetDiskCustomRules.clearRule(); event.close(); return; } let ruleJSON = JSON.parse(textAreaElement.value); if (!Array.isArray(ruleJSON)) { Qmsg.error("该规则不是一个数组"); return; } let mustProperty = ["key", "icon", "regexp"]; let regexpMustProperty = [ "link_innerText", "link_innerHTML", "shareCode", "shareCodeNeedRemoveStr", "uiLinkShow", "blank", "copyUrl", ]; for (let index = 0; index < ruleJSON.length; index++) { let item = ruleJSON[index]; if (typeof item !== "object") { Qmsg.error(`第${index + 1}条规则不是一个对象`); return; } for ( let index2 = 0; index2 < mustProperty.length; index2++ ) { let propertyName = mustProperty[index2]; if (!Object.hasOwnProperty.call(item, propertyName)) { Qmsg.error( `第${index + 1}条规则缺少属性 ${propertyName} ` ); return; } } if (typeof item["regexp"] !== "object") { Qmsg.error(`第${index + 1}条规则的regexp不是一个对象`); return; } for ( let index2 = 0; index2 < regexpMustProperty.length; index2++ ) { let propertyName = regexpMustProperty[index2]; if ( !Object.hasOwnProperty.call( item["regexp"], propertyName ) ) { Qmsg.error( `第${ index + 1 }条规则中的regexp内缺少属性 ${propertyName}` ); return; } } if ( item["regexp"]["accessCode"] && !item["regexp"]["checkAccessCode"] ) { Qmsg.error( `第${ index + 1 }条规则中的regexp内设置了accessCode但是没有设置checkAccessCode` ); return; } if ( item["regexp"]["checkAccessCode"] && !item["regexp"]["accessCode"] ) { Qmsg.error( `第${ index + 1 }条规则中的regexp内设置了checkAccessCode但是没有设置accessCode` ); return; } } NetDiskCustomRules.setRule(ruleJSON); Qmsg.success(`保存规则${ruleJSON.length}条`); event.close(); } catch (error) { log.error(error); Qmsg.error(error.message, { html: true, timeout: 3500, }); } }, }, other: { enable: true, text: "格式化", type: "xiaomi-primary", callback(event) { let textAreaElement = event.popsElement.querySelector( "textarea.netdisk-custom-rules" ); try { let ruleJSON = JSON.parse(textAreaElement.value); let ruleJSONString = NetDiskCustomRules.getFormatRule(ruleJSON); textAreaElement.value = ruleJSONString; Qmsg.success("格式化成功"); } catch (error) { log.error(error); Qmsg.error(error.message, { html: true, timeout: 3500, }); } }, }, }, class: "whitesevPopNetDiskCustomRules", }, NetDiskUI.popsStyle.customRulesView ); popsConfirm.popsElement.querySelector("textarea").value = NetDiskCustomRules.getFormatRule(); }, initCSS() { if (this.isInitCSS) { return; } this.isInitCSS = true; GM_addStyle(` .pops.whitesevPopNetDiskCustomRules[type-value="confirm"] .pops-confirm-content textarea{ width: 100%; height: 100%; font-size: 16px; } /* textarea美化 */ .pops.whitesevPopNetDiskCustomRules[type-value="confirm"] .pops-confirm-content textarea{ border: none; outline: none; padding: 0; margin: 0; -webkit-appearance: none; -moz-appearance: none; appearance: none; background-image: none; background-color: transparent; } .pops.whitesevPopNetDiskCustomRules[type-value="confirm"] .pops-confirm-content textarea:focus{ outline: none; } .pops.whitesevPopNetDiskCustomRules[type-value="confirm"] .pops-confirm-content textarea { display: inline-block; resize: vertical; padding: 5px 15px; line-height: 1.5; box-sizing: border-box; color: #606266; background-color: #fff; border: 1px solid #dcdfe6; border-radius: 4px; transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1); } /* 提示文字 */ .pops.whitesevPopNetDiskCustomRules[type-value="confirm"] .pops-confirm-content textarea::placeholder { color: #c0c4cc; } /* 鼠标hover */ .pops.whitesevPopNetDiskCustomRules[type-value="confirm"] .pops-confirm-content textarea:hover { border-color: #c0c4cc; } /* 获得焦点 */ .pops.whitesevPopNetDiskCustomRules[type-value="confirm"] .pops-confirm-content textarea:focus { border-color: #3677f0; } `); }, }, /** * 主动识别文本 */ matchPasteText: { isInitCSS: false, show() { this.initCSS(); let popsConfirm = NetDiskPops.confirm( { title: { text: "主动识别文本", position: "center", }, content: { text: ` <textarea class="netdisk-match-paste-text"></textarea> `, html: true, }, btn: { ok: { text: "识别", callback() { NetDisk.clipboardText = popsConfirm.popsElement?.querySelector( ".netdisk-match-paste-text" )?.value || ""; NetDisk.matchPageLink(); }, }, }, class: "whitesevPopNetDiskMatchPasteText", }, NetDiskUI.popsStyle.matchPasteTextView ); popsConfirm.popsElement.querySelector("textarea").focus(); }, initCSS() { if (this.isInitCSS) { return; } this.isInitCSS = true; GM_addStyle(` .netdisk-match-paste-text { display: inline-block; resize: vertical; padding: 5px 15px; line-height: 1.5; box-sizing: border-box; color: #606266; background-color: #fff; border: 1px solid #dcdfe6; border-radius: 4px; transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1); outline: none; margin: 0; -webkit-appearance: none; -moz-appearance: none; appearance: none; background-image: none; width: 100%; height: 100%; font-size: 16px; } .netdisk-match-paste-text:focus{ outline: none; border-color: #3677f0; } .netdisk-match-paste-text:hover{ border-color: #c0c4cc; } `); }, }, /** * 监听页面节点内容或节点文本的变动,从而进行匹配网盘链接 */ monitorDOMInsert() { NetDiskWorker.initWorkerBlobLink(); NetDiskWorker.initWorker(); utils.mutationObserver(document.body || document.documentElement, { callback: async (mutations) => { if (NetDiskUI.isHandleMatch) { /* 当前正在处理文本正则匹配中 */ return; } NetDiskUI.isHandleMatch = true; if (GM_getValue("readClipboard", false)) { NetDisk.clipboardText = await NetDisk.getClipboardText(); } if (typeof NetDisk.clipboardText !== "string") { NetDisk.clipboardText = ""; } NetDisk.matchPageLink(); }, config: { /* 子节点的变动(新增、删除或者更改) */ childList: true, /* 节点内容或节点文本的变动 */ characterData: true, /* 是否将观察器应用于该节点的所有后代节点 */ subtree: true, }, }); /* 主动触发一次,因为有的页面上没触发mutationObserver */ NetDisk.matchPageLink(); }, }; /** * 快捷键 */ const NetDiskShortcut = { /** * 是否正在等待用户按下键盘 */ isWaitUserPressKeyboard: false, /** * 获取本地存储的值 * @param {?string} key * @param {?string} defaultVal * @returns {{ * key: string, * value: { * keyName: string, * keyValue: number|string, * ohterCodeList: string[] * } * }|{ * keyName: string, * keyValue: number|string, * ohterCodeList: string[] * }[]} */ getValue(key, defaultVal) { let value = GM_getValue("GM_shortcut", []); if (key) { for (let index = 0; index < value.length; index++) { let item = value[index]; if (item["key"] === key) { return item["value"]; } } return defaultVal; } else { return value; } }, /** * 删除本地存储的快捷键值 * @param {string} key */ deleteValue(key) { let value = this.getValue(); let findValueIndex = value.findIndex((item) => item["key"] === key); if (findValueIndex !== -1) { value.splice(findValueIndex, 1); } GM_setValue("GM_shortcut", value); }, /** * 保存设置的快捷键到本地存储 * @param {string} key * @param {string} keyName * @param {string} keyValue * @param {string[]} ohterCodeList */ setValue(key, keyName, keyValue, ohterCodeList) { let value = this.getValue(); value.push({ key: key, value: { keyName: keyName, keyValue: keyValue, ohterCodeList: ohterCodeList, }, }); GM_setValue("GM_shortcut", value); }, /** * 获取快捷键显示的文字 * @param {string} key * @param {string} defaultValue */ getShowText(key, defaultValue) { let localValue = this.getValue(key); if (localValue) { /* 如果获取到,转需要显示的文字 */ let result = ""; localValue["ohterCodeList"].forEach((item) => { result += utils.stringTitleToUpperCase(item, true) + " + "; }); result += localValue["keyName"]; return result; } else { /* 未获取到,显示为默认的文字 */ return defaultValue; } }, /** * 快捷键按钮录入的点击事件 */ buttonClickCallBack(event, key, defaultValue) { let localValue = this.getValue(key, defaultValue); let spanElement = event.target .closest(".pops-panel-button") .querySelector("span"); if (localValue === defaultValue) { /* 设置快捷键 */ let loadingQmsg = Qmsg.loading("请按下快捷键...", { showClose: true, onClose() { keyboardListener.removeListen(); }, }); NetDiskShortcut.isWaitUserPressKeyboard = true; let keyboardListener = utils.listenKeyboard( window, "keyup", (keyName, keyValue, ohterCodeList) => { let shortcutJSONString = JSON.stringify({ keyName: keyName, keyValue: keyValue, ohterCodeList: ohterCodeList, }); let allDetails = this.getValue(); for (let index = 0; index < allDetails.length; index++) { if ( shortcutJSONString === JSON.stringify(allDetails[index]["value"]) ) { Qmsg.error( `快捷键 ${this.getShowText( allDetails[index]["key"] )} 已被占用` ); NetDiskShortcut.isWaitUserPressKeyboard = false; loadingQmsg.close(); return; } } this.setValue(key, keyName, keyValue, ohterCodeList); spanElement.innerHTML = this.getShowText(key, defaultValue); NetDiskShortcut.isWaitUserPressKeyboard = false; loadingQmsg.close(); } ); } else { /* 清空快捷键 */ this.deleteValue(key); } spanElement.innerHTML = this.getShowText(key, defaultValue); }, /** * 初始化全局键盘监听 */ initGlobalKeyboardListener() { let localValue = this.getValue(); if (!localValue.length) { /* 没有设置快捷键 */ return; } utils.listenKeyboard( window, "keydown", (keyName, keyValue, ohterCodeList) => { if (NetDiskShortcut.isWaitUserPressKeyboard) { return; } localValue = this.getValue(); let findShortcutIndex = localValue.findIndex((item) => { let itemValue = item["value"]; let tempValue = { keyName: keyName, keyValue: keyValue, ohterCodeList: ohterCodeList, }; if (JSON.stringify(itemValue) === JSON.stringify(tempValue)) { return item; } }); if (findShortcutIndex != -1) { let findShortcut = localValue[findShortcutIndex]; log.info(["调用快捷键", findShortcut]); if (findShortcut["key"] === "netdisk-keyboard-open-setting") { log.info("打开设置界面"); NetDiskUI.suspension.initPop(); NetDiskUI.suspension.showSettingView(); } else if ( findShortcut["key"] === "netdisk-keyboard-open-history-matching-records" ) { log.info("打开历史匹配记录"); NetDiskUI.netDiskHistoryMatch.show(); } else if ( findShortcut["key"] === "netdisk-keyboard-open-accesscode-rule" ) { log.info("打开访问码规则"); NetDiskUI.accessCodeRule.show(); } else if ( findShortcut["key"] === "netdisk-keyboard-open-user-rule" ) { log.info("打开用户自定义规则"); NetDiskUI.customRules.show(); } else if ( findShortcut["key"] === "netdisk-keyboard-open-proactively-recognize-text" ) { log.info("打开主动识别文本"); NetDiskUI.matchPasteText.show(); } else { log.error("还未配置调用函数"); } } } ); }, }; /** * 弹窗-统一管理 */ const NetDiskPops = { /** * 普通信息框 * @param {PopsAlertDetails} details 配置 * @param {{ * PC: { * width: string, * height: string, * }, * Mobile: { * width: string, * height: string * } * }} sizeConfig 大小配置 * @returns {{ * guid: string, * element: Element, * animElement: HTMLElement, * popsElement: Element, * maskElement: Element, * close: Function, * hide: Function, * show: Function, * }} */ alert(details, sizeConfig) { details = this.handleDetails(details, sizeConfig); return pops.alert(details); }, /** * 询问框 * @param {PopsConfirmDetails} details 配置 * @param {?{ * PC: { * width: string, * height: string, * }, * Mobile: { * width: string, * height: string * } * }} sizeConfig 大小配置 * @returns {{ * guid: string, * element: HTMLElement, * animElement: HTMLElement, * popsElement: HTMLElement, * maskElement: HTMLElement, * close: Function, * hide: Function, * show: Function, * }} */ confirm(details, sizeConfig) { details = this.handleDetails(details, sizeConfig); return pops.confirm(details); }, /** * 加载层 * @param {PopsLoadingDetails} details 配置 * @returns {{ * guid: string, * element: Element, * animElement: HTMLElement, * popsElement: Element, * maskElement: Element, * close: Function, * hide: Function, * show: Function, * }} */ loading(details) { if (typeof details["animation"] === "undefined") { details["animation"] = GM_getValue( "popsAnimation", NetDiskUI.defaultAnimation ); } if (typeof details["forbiddenScroll"] === "undefined") { details["forbiddenScroll"] = NetDiskUI.defaultForbiddenScroll; } return pops.loading(details); }, /** * 输入框 * @param {PopsPromptDetails} details 配置 * @param {?{ * PC: { * width: string, * height: string, * }, * Mobile: { * width: string, * height: string * } * }} sizeConfig 大小配置 * @returns {{ * guid: string, * element: Element, * animElement: HTMLElement, * popsElement: Element, * maskElement: Element, * close: Function, * hide: Function, * show: Function, * }} */ prompt(details, sizeConfig) { details = this.handleDetails(details, sizeConfig); return pops.prompt(details); }, /** * 文件夹 * @param {PopsFolderDetails} details 配置 * @returns {{ * guid: string, * element: Element, * animElement: HTMLElement, * popsElement: Element, * maskElement: Element, * close: Function, * hide: Function, * show: Function, * }} */ folder(details, sizeConfig) { details = this.handleDetails(details, sizeConfig); details["sort"] = { name: GM_getValue("pops-folder-sort-name", NetDiskUI.defaultSortName), isDesc: GM_getValue( "pops-folder-sort-is-desc", NetDiskUI.defaultSortDesc ), callback(target, event, sortName, sortDesc) { GM_setValue("pops-folder-sort-name", sortName); GM_setValue("pops-folder-sort-is-desc", sortDesc); }, }; return pops.folder(details); }, /** * 菜单面板 * @param {PopsPanelDetails} details 配置 * @returns {{ * guid: string, * element: Element, * animElement: HTMLElement, * popsElement: Element, * maskElement: Element, * close: Function, * hide: Function, * show: Function, * }} */ panel(details, sizeConfig) { details = this.handleDetails(details, sizeConfig); return pops.panel(details); }, /** * * @param {object} details * @param {?{ * PC: { * width: string, * height: string, * }, * Mobile: { * width: string, * height: string * } * }} sizeConfig 大小配置 * @returns {object} */ handleDetails(details, sizeConfig) { let defaultDetails = { mask: { enable: true, clickEvent: { toClose: GM_getValue( "clickMaskToCloseDialog", NetDiskUI.defaultClickMaskToCloseDialog ), }, }, animation: GM_getValue("popsAnimation", NetDiskUI.defaultAnimation), drag: GM_getValue("pcDrag", NetDiskUI.defaultPCDrag), dragLimit: GM_getValue("pcDragLimit", NetDiskUI.defaultPCDragLimit), forbiddenScroll: NetDiskUI.defaultForbiddenScroll, }; if (sizeConfig != null) { defaultDetails.width = pops.isPhone() ? sizeConfig.Mobile.width : sizeConfig.PC.width; defaultDetails.height = pops.isPhone() ? sizeConfig.Mobile.height : sizeConfig.PC.height; } Object.assign(defaultDetails, details); return defaultDetails; }, }; /** * 菜单 */ const NetDiskMenu = { /** * 初始化 */ init() { GM_Menu.add([ { key: "showSetting", text: "⚙ 打开设置界面", showText(text) { return text; }, callback() { NetDiskUI.suspension.initPop(); NetDiskUI.suspension.showSettingView(); }, }, { key: "showNetDiskHistoryMatch", text: "⚙ 打开历史匹配记录", showText(text) { return text; }, callback() { NetDiskUI.netDiskHistoryMatch.show(); }, }, { key: "showAccessCodeRule", text: "⚙ 打开访问码规则", showText(text) { return text; }, callback() { NetDiskUI.accessCodeRule.show(); }, }, { key: "showUserRule", text: "⚙ 打开用户自定义规则", showText(text) { return text; }, callback() { NetDiskUI.customRules.show(); }, }, { key: "showMatchPasteText", text: "⚙ 打开主动识别文本", showText(text) { return text; }, callback() { NetDiskUI.matchPasteText.show(); }, }, ]); }, /** * 初始化环境变量 */ initEnv() { if (GM_getValue("allowMatchLocationHref")) { NetDisk.allowMatchLocationHref = true; } }, }; Object.assign( NetDiskUI.src.icon, typeof RESOURCE_ICON === "undefined" ? {} : RESOURCE_ICON ); NetDiskMenu.init(); NetDiskMenu.initEnv(); NetDiskCustomRules.init(); DOMUtils.ready(function () { log.config({ logMaxCount: 200000, autoClearConsole: false, }); httpx.config({ onabort() { Qmsg.error("请求被取消"); }, ontimeout() { Qmsg.error("请求超时"); }, onerror(response) { Qmsg.error("请求异常"); log.error(["httpx-onerror", response]); }, }); NetDiskAutoFillAccessCode.default(); NetDiskAuthorization.default(); NetDiskUI.monitorDOMInsert(); NetDiskShortcut.initGlobalKeyboardListener(); }); })();