// ==UserScript==
// @name 网盘链接识别
// @namespace https://greasyfork.org/zh-CN/scripts/445489-网盘链接识别
// @supportURL https://greasyfork.org/zh-CN/scripts/445489-网盘链接识别/feedback
// @version 23.4.6.10.00
// @description 识别网页中显示的网盘链接,目前包括百度网盘、蓝奏云、天翼云、中国移动云盘(原:和彩云)、阿里云、文叔叔、奶牛快传、123盘、腾讯微云、迅雷网盘、115网盘、夸克网盘、城通网盘(部分)、坚果云、magnet格式,支持蓝奏云、天翼云(需登录)、123盘、奶牛和坚果云(需登录)直链获取下载,页面动态监控加载的链接
// @author WhiteSevs
// @match *://*/*
// @run-at document-body
// @license GPL-3.0-only
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_setClipboard
// @grant GM_xmlhttpRequest
// @grant GM_addStyle
// @grant GM_info
// @grant GM_openInTab
// @grant GM_registerMenuCommand
// @grant GM_unregisterMenuCommand
// @connect *
// @connect lanzoux.com
// @connect lanzoug.com
// @connect 189.cn
// @connect 123pan.com
// @connect wenshushu.cn
// @connect jianguoyun.com
// @exclude /^http(s|):\/\/s1\.hdslb\.com\/.*$/
// @exclude /^http(s|):\/\/(message|www)\.bilibili\.com\/.*$/
// @exclude /^http(s|):\/\/.*\.mail\.qq\.com\/.*$/
// @exclude /^http(s|):\/\/.*video\.qq\.com\/.*$/
// @exclude /^http(s|):\/\/.*\.vscode-cdn\.net\/.*$/
// @exclude /^http(s|):\/\/.*vscode\.dev\/.*$/
// @require https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/jquery/3.4.1/jquery.min.js
// @require https://unpkg.com/any-touch/dist/any-touch.umd.min.js
// @require https://greasyfork.org/scripts/462234-message/code/Message.js?version=1170653
// @require https://greasyfork.org/scripts/456470-%E7%BD%91%E7%9B%98%E9%93%BE%E6%8E%A5%E8%AF%86%E5%88%AB-%E5%9B%BE%E6%A0%87%E5%BA%93/code/%E7%BD%91%E7%9B%98%E9%93%BE%E6%8E%A5%E8%AF%86%E5%88%AB-%E5%9B%BE%E6%A0%87%E5%BA%93.js?version=1162631
// @require https://greasyfork.org/scripts/456485-pops/code/pops.js?version=1171602
// @require https://greasyfork.org/scripts/455186-whitesevsutils/code/WhiteSevsUtils.js?version=1169937
// ==/UserScript==
(function () {
let log = new Utils.Log(GM_info);
let httpx = new Utils.Httpx(GM_xmlhttpRequest);
httpx.config({
onabort: function () {
Qmsg.error("请求被取消");
},
ontimeout: function () {
Qmsg.error("请求超时");
},
onerror: function (response) {
Qmsg.error("请求异常");
log.error(["httpx-onerror", response]);
},
});
const NetDisk = {
isInit: false /* 是否初始化 */,
pageText: null /* 页面显示出的文字 */,
linkDict: null /* 链接字典 */,
isMatching: false /* 正在匹配链接中 */,
matchLink: null /* 匹配到的 */,
hasMatchLink: false /* 已存在匹配的链接 */,
regular: {
baidu: {
link_innerText: `pan.baidu.com/s/[0-9a-zA-Z-_]{8,24}([\\s\\S]{0,${parseInt(
GM_getValue("innerText_baidu", 20)
)}}(密码|访问码|提取码)[\\s\\S]{0,10}[0-9a-zA-Z]{4}|)` /* 百度网盘链接 */,
link_innerHTML: `pan.baidu.com/s/[0-9a-zA-Z-_]{8,24}([\\s\\S]{0,${parseInt(
GM_getValue("innerHTML_baidu", 300)
)}}(密码|访问码|提取码)[\\s\\S]{0,15}[0-9a-zA-Z]{4}|)` /* 百度网盘链接 */,
shareCode: /pan\.baidu\.com\/s\/([0-9a-zA-Z-_]+)/gi /* 链接参数 */,
shareCodeNeedRemoveStr:
/pan\.baidu\.com\/s\//gi /* 需要替换空的字符串,比如pan.baidu.com/s/替换为空 */,
checkAccessCode: /(密码|访问码|提取码).+/g /* 用来判断是否存在密码 */,
accessCode: /([0-9a-zA-Z]{4})/gi /* 提取码(如果存在的话) */,
uiLinkShow:
"pan.baidu.com/s/{#shareCode#}?pwd={#accessCode#} 提取码: {#accessCode#}" /* 用于显示的链接 */,
blank:
"https://pan.baidu.com/s/{#shareCode#}?pwd={#accessCode#}" /* 新标签页打开的链接 */,
},
lanzou: {
link_innerText: `lanzou[a-z]{0,1}.com/(tp/|u/|)([a-zA-Z0-9_-]{5,22}|[%0-9a-zA-Z]{4,90}|[\\u4e00-\\u9fa5]{1,20})([\\s\\S]{0,${parseInt(
GM_getValue("innerText_lanzou", 20)
)}}(密码|访问码|提取码)[\\s\\S]{0,10}[a-zA-Z0-9]{3,6}|)`,
link_innerHTML: `lanzou[a-z]{0,1}.com/(tp/|u/|)([a-zA-Z0-9_-]{5,22}|[%0-9a-zA-Z]{4,90}|[\\u4e00-\\u9fa5]{1,20})([\\s\\S]{0,${parseInt(
GM_getValue("innerHTML_lanzou", 300)
)}}(密码|访问码|提取码)[\\s\\S]{0,15}[a-zA-Z0-9]{3,6}|)`,
shareCode:
/lanzou[a-z]{0,1}.com\/(tp\/|u\/|)([a-zA-Z0-9_\-]{5,22}|[%0-9a-zA-Z]{4,90}|[\u4e00-\u9fa5]{1,20})/gi,
shareCodeNotMatch:
/^(ajax|file|undefined|1125)/gi /* shareCode参数中不可能存在的链接,如果shareCode存在这些,那就拒绝匹配 */,
shareCodeNeedRemoveStr: /lanzou[a-z]{0,1}.com\/(tp\/|u\/|)/gi,
checkAccessCode: /(密码|访问码|提取码).+/g,
accessCode: /([0-9a-zA-Z]{4})/gi,
uiLinkShow: "lanzoux.com/{#shareCode#} 提取码: {#accessCode#}",
blank: "https://www.lanzoux.com/{#shareCode#}",
},
tianyiyun: {
link_innerText: `(cloud.189.cn/web/share\\?code=([0-9a-zA-Z_-]){8,14}|cloud.189.cn/t/([a-zA-Z0-9_-]{8,14}))([\\s\\S]{0,${parseInt(
GM_getValue("innerText_tianyiyun", 20)
)}}(密码|访问码|提取码)[\\s\\S]{0,10}[0-9a-zA-Z]{4}|)`,
link_innerHTML: `(cloud.189.cn/web/share\\?code=([0-9a-zA-Z_\-]){8,14}|cloud.189.cn/t/([a-zA-Z0-9_-]{8,14}))([\\s\\S]{0,${parseInt(
GM_getValue("innerHTML_tianyiyun", 300)
)}}(密码|访问码|提取码)[\\s\\S]{0,15}[0-9a-zA-Z]{4}|)`,
shareCode:
/cloud.189.cn\/web\/share\?code=([0-9a-zA-Z_\-]){8,14}|cloud.189.cn\/t\/([a-zA-Z0-9_\-]{8,14})/gi,
shareCodeNeedRemoveStr:
/cloud\.189\.cn\/t\/|cloud.189.cn\/web\/share\?code=/gi,
checkAccessCode: /(密码|访问码|提取码).+/g,
accessCode: /([0-9a-zA-Z]{4})/gi,
uiLinkShow: "cloud.189.cn/t/{#shareCode#} 提取码: {#accessCode#}",
blank: "https://cloud.189.cn/t/{#shareCode#}",
},
hecaiyun: {
link_innerText: `caiyun.139.com/m/i\\?([a-zA-Z0-9_-]{8,14})([\\s\\S]{0,${parseInt(
GM_getValue("innerText_hecaiyun", 20)
)}}(密码|访问码|提取码)[\\s\\S]{0,10}[0-9a-zA-Z]{4}|)`,
link_innerHTML: `caiyun.139.com/m/i\\?([a-zA-Z0-9_-]{8,14})([\\s\\S]{0,${parseInt(
GM_getValue("innerHTML_hecaiyun", 300)
)}}(密码|访问码|提取码)[\\s\\S]{0,15}[0-9a-zA-Z]{4}|)`,
shareCode: /caiyun\.139\.com\/m\/i\?([a-zA-Z0-9_\-]{8,14})/gi,
shareCodeNeedRemoveStr: /caiyun\.139\.com\/m\/i\?/gi,
checkAccessCode: /(密码|访问码|提取码).+/g,
accessCode: /([0-9a-zA-Z]{4})/gi,
uiLinkShow: "caiyun.139.com/m/i?{#shareCode#} 提取码: {#accessCode#}",
blank: "https://caiyun.139.com/m/i?{#shareCode#}",
},
aliyun: {
link_innerText: `aliyundrive.com/s/([a-zA-Z0-9_-]{8,14})([\\s\\S]{0,${parseInt(
GM_getValue("innerText_aliyun", 20)
)}}(密码|访问码|提取码)[\\s\\S]{0,10}[0-9a-zA-Z]{4}|)`,
link_innerHTML: `aliyundrive.com/s/([a-zA-Z0-9_-]{8,14})([\\s\\S]{0,${parseInt(
GM_getValue("innerHTML_aliyun", 300)
)}}(密码|访问码|提取码)[\\s\\S]{0,15}[0-9a-zA-Z]{4}|)`,
shareCode: /aliyundrive\.com\/s\/([a-zA-Z0-9_\-]{8,14})/g,
shareCodeNotMatch: /undefined/gi,
shareCodeNeedRemoveStr: /aliyundrive\.com\/s\//gi,
checkAccessCode: /(密码|访问码|提取码).+/g,
accessCode: /([0-9a-zA-Z]{4})/gi,
acceesCodeNotMatch: /^(font)/gi,
uiLinkShow: "aliyundrive.com/s/{#shareCode#} 提取码: {#accessCode#}",
blank: "https://aliyundrive.com/s/{#shareCode#}",
},
wenshushu: {
link_innerText: `(wss.ink/f/([a-zA-Z0-9_-]{8,14})|ws28.cn/f/([a-zA-Z0-9_-]{8,14})|wss1.cn/f/([a-zA-Z0-9_-]{8,14}))([\\s\\S]{0,${parseInt(
GM_getValue("innerText_wenshushu", 20)
)}}(密码|访问码|提取码)[\\s\\S]{0,10}[0-9a-zA-Z]{4}|)`,
link_innerHTML: `(wss.ink/f/([a-zA-Z0-9_-]{8,14})|ws28.cn/f/([a-zA-Z0-9_-]{8,14})|wss1.cn/f/([a-zA-Z0-9_-]{8,14}))([\\s\\S]{0,${parseInt(
GM_getValue("innerHTML_wenshushu", 300)
)}}(密码|访问码|提取码)[\\s\\S]{0,15}[0-9a-zA-Z]{4}|)`,
shareCode:
/wss.ink\/f\/([a-zA-Z0-9_-]{8,14})|ws28.cn\/f\/([a-zA-Z0-9_-]{8,14})|wss1.cn\/f\/([a-zA-Z0-9_-]{8,14})/gi,
shareCodeNeedRemoveStr: /wss.ink\/f\/|ws28.cn\/f\/|wss1.cn\/f\//gi,
checkAccessCode: /(密码|访问码|提取码).+/g,
accessCode: /[0-9a-zA-Z]{4}/gi,
uiLinkShow: "wss.ink/f/{#shareCode#} 提取码: {#accessCode#}",
blank: "https://wss.ink/f/{#shareCode#}",
},
nainiu: {
link_innerText: `cowtransfer.com/s/([a-zA-Z0-9_-]{8,14})([\\s\\S]{0,${parseInt(
GM_getValue("innerText_nainiu", 20)
)}}(密码|访问码|提取码)[\\s\\S]{0,10}[0-9a-zA-Z]{4}|)`,
link_innerHTML: `cowtransfer.com/s/([a-zA-Z0-9_-]{8,14})([\\s\\S]{0,${parseInt(
GM_getValue("innerText_nainiu", 20)
)}}(密码|访问码|提取码)[\\s\\S]{0,15}[0-9a-zA-Z]{4}|)`,
shareCode: /cowtransfer.com\/s\/([a-zA-Z0-9_\-]{8,14})/gi,
shareCodeNeedRemoveStr: /cowtransfer\.com\/s\//gi,
checkAccessCode: /(密码|访问码|提取码).+/g,
accessCode: /([0-9a-zA-Z]{4})/gi,
uiLinkShow: "cowtransfer.com/s/{#shareCode#} 提取码: {#accessCode#}",
blank: "https://cowtransfer.com/s/{#shareCode#}",
},
_123pan: {
link_innerText: `123pan.com/s/([a-zA-Z0-9_-]{8,14})([\\s\\S]{0,${parseInt(
GM_getValue("innerText__123pan", 20)
)}}(密码|访问码|提取码)[\\s\\S]{0,10}[0-9a-zA-Z]{4}|)`,
link_innerHTML: `123pan.com/s/([a-zA-Z0-9_-]{8,14})([\\s\\S]{0,${parseInt(
GM_getValue("innerHTML__123pan", 300)
)}}(密码|访问码|提取码)[\\s\\S]{0,15}[0-9a-zA-Z]{4}|)`,
shareCode: /123pan.com\/s\/([a-zA-Z0-9_\-]{8,14})/gi,
shareCodeNeedRemoveStr: /123pan.com\/s\//gi,
checkAccessCode: /(密码|访问码|提取码).+/g,
accessCode: /([0-9a-zA-Z]{4})/gi,
uiLinkShow: "123pan.com/s/{#shareCode#} 提取码: {#accessCode#}",
blank: "https://123pan.com/s/{#shareCode#}",
},
weiyun: {
link_innerText: `weiyun.com/[0-9a-zA-Z-_]{7,24}([\\s\\S]{0,${parseInt(
GM_getValue("innerText_weiyun", 20)
)}}(访问码|密码|提取码)[\\s\\S]{0,10}[0-9a-zA-Z]{4}|)`,
link_innerHTML: `weiyun.com/[0-9a-zA-Z-_]{7,24}([\\s\\S]{0,${parseInt(
GM_getValue("innerHTML_weiyun", 300)
)}}(访问码|密码|提取码)[\\s\\S]{0,15}[0-9a-zA-Z]{4}|)`,
shareCode: /weiyun.com\/([0-9a-zA-Z\-_]{7,24})/gi,
shareCodeNotMatch:
/^(ajax|file|download|ptqrshow|xy-privacy|comp|web)/gi,
shareCodeNeedRemoveStr: /weiyun.com\//gi,
checkAccessCode: /(提取码|密码|访问码).+/g,
accessCode: /([0-9a-zA-Z]{4})/gi,
uiLinkShow: "share.weiyun.com/{#shareCode#} 提取码: {#accessCode#}",
blank: "https://share.weiyun.com/{#shareCode#}",
},
xunlei: {
link_innerText: `xunlei.com/s/[0-9a-zA-Z-_]{8,30}([\\s\\S]{0,${parseInt(
GM_getValue("innerText_xunlei", 20)
)}}(访问码|提取码|密码|)[\\s\\S]{0,10}[0-9a-zA-Z]{4}|)`,
link_innerHTML: `xunlei.com\/s\/[0-9a-zA-Z\-_]{8,30}([\\s\\S]{0,${parseInt(
GM_getValue("innerHTML_xunlei", 300)
)}}(访问码|提取码|密码|)[\\s\\S]{0,15}[0-9a-zA-Z]{4}|)`,
shareCode: /xunlei.com\/s\/([0-9a-zA-Z\-_]{8,30})/gi,
shareCodeNeedRemoveStr: /xunlei.com\/s\//gi,
checkAccessCode: /(提取码|密码|访问码).+/g,
accessCode: /([0-9a-zA-Z]{4})/gi,
uiLinkShow: "pan.xunlei.com/s/{#shareCode#} 提取码: {#accessCode#}",
blank: "https://pan.xunlei.com/s/{#shareCode#}",
},
_115pan: {
link_innerText: `115.com/s/[0-9a-zA-Z-_]{8,24}([\\s\\S]{0,${parseInt(
GM_getValue("innerText__115pan", 20)
)}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,10}[0-9a-zA-Z]{4}|)`,
link_innerHTML: `115.com\/s\/[0-9a-zA-Z-_]{8,24}([\\s\\S]{0,${parseInt(
GM_getValue("innerHTML__115pan", 300)
)}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,15}[0-9a-zA-Z]{4}|)`,
shareCode: /115.com\/s\/([0-9a-zA-Z\-_]{8,24})/gi,
shareCodeNeedRemoveStr: /115.com\/s\//gi,
checkAccessCode: /(提取码|密码|\?password=|访问码).+/gi,
accessCode: /(\?password=|)([0-9a-zA-Z]{4})/gi,
uiLinkShow: "115.com/s/{#shareCode#} 提取码: {#accessCode#}",
blank: "https://115.com/s/{#shareCode#}",
},
chengtong1: {
link_innerText: `(ctfile.com|ghpym.com)/d/[0-9a-zA-Z-_]{8,26}([\\s\\S]{0,${parseInt(
GM_getValue("innerText__chengtong1", 20)
)}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,10}[0-9a-zA-Z]{6}|)`,
link_innerHTML: `(ctfile.com|ghpym.com)/d/[0-9a-zA-Z-_]{8,26}([\\s\\S]{0,${GM_getValue(
"innerHTML__chengtong1",
300
)}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,15}[0-9a-zA-Z]{6}|)`,
shareCode: /(ctfile.com|ghpym.com)\/d\/([0-9a-zA-Z\-_]{8,26})/gi,
shareCodeNeedRemoveStr: /(ctfile.com|ghpym.com)\/d\//gi,
checkAccessCode: /(提取码|密码|访问码).+/gi,
accessCode: /([0-9a-zA-Z]{6})/gi,
uiLinkShow: "url95.ctfile.com/d/{#shareCode#} 提取码: {#accessCode#}",
blank: "https://url95.ctfile.com/d/{#shareCode#}",
},
chengtong2: {
link_innerText: `(2k.us/file/|u062.com/fil\/|545c.com/file/)[0-9a-zA-Z-_]{8,26}([\\s\\S]{0,${parseInt(
GM_getValue("innerText__chengtong2", 20)
)}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,10}[0-9a-zA-Z]{4}|)`,
link_innerHTML: `(2k.us/file/|u062.com/file/|545c.com/file/)[0-9a-zA-Z-_]{8,26}([\\s\\S]{0,${parseInt(
GM_getValue("innerHTML__chengtong2", 300)
)}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,15}[0-9a-zA-Z]{4}|)`,
shareCode:
/(2k.us\/file\/|u062.com\/file\/|545c.com\/file\/)([0-9a-zA-Z\-_]{8,26})/gi,
shareCodeNeedRemoveStr:
/2k.us\/file\/|u062.com\/file\/|545c.com\/file\//gi,
checkAccessCode: /(提取码|密码|访问码).+/gi,
accessCode: /([0-9a-zA-Z]{4})/gi,
uiLinkShow: "u062.com/file/{#shareCode#} 提取码: {#accessCode#}",
blank: "https://u062.com/file/{#shareCode#}",
},
chengtong3: {
link_innerText: `ctfile.com/f/[0-9a-zA-Z-_]{8,26}([\\s\\S]{0,${parseInt(
GM_getValue("innerText__chengtong1", 20)
)}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,10}[0-9a-zA-Z]{6}|)`,
link_innerHTML: `ctfile.com/f/[0-9a-zA-Z-_]{8,26}([\\s\\S]{0,${GM_getValue(
"innerHTML__chengtong1",
300
)}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,15}[0-9a-zA-Z]{6}|)`,
shareCode: /ctfile.com\/f\/([0-9a-zA-Z\-_]{8,26})/gi,
shareCodeNeedRemoveStr: /ctfile.com\/f\//gi,
checkAccessCode: /(提取码|密码|访问码).+/gi,
accessCode: /([0-9a-zA-Z]{6})/gi,
uiLinkShow: "url95.ctfile.com/f/{#shareCode#} 提取码: {#accessCode#}",
blank: "https://url95.ctfile.com/f/{#shareCode#}",
},
kuake: {
link_innerText: `quark.cn/s/[0-9a-zA-Z-_]{8,24}([\\s\\S]{0,${parseInt(
GM_getValue("innerText_kuake", 20)
)}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,10}[0-9a-zA-Z]{4}|)`,
link_innerHTML: `quark.cn/s/[0-9a-zA-Z-_]{8,24}([\\s\\S]{0,${parseInt(
GM_getValue("innerHTML_kuake", 300)
)}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,15}[0-9a-zA-Z]{4}|)`,
shareCode: /quark.cn\/s\/([0-9a-zA-Z\-_]{8,24})/gi,
shareCodeNeedRemoveStr: /quark.cn\/s\//gi,
checkAccessCode: /(提取码|密码|访问码).+/gi,
accessCode: /([0-9a-zA-Z]{4})/gi,
uiLinkShow: "quark.cn/s/{#shareCode#} 提取码: {#accessCode#}",
blank: "https://pan.quark.cn/s/{#shareCode#}",
},
magnet: {
link_innerText: `magnet:\\?xt=urn:btih:[0-9a-fA-F]{32,40}`,
link_innerHTML: `magnet:\\?xt=urn:btih:[0-9a-fA-F]{32,40}`,
shareCode: /magnet:\?xt=urn:btih:([0-9a-fA-F]{32,40})/gi,
shareCodeNeedRemoveStr: /magnet:\?xt=urn:btih:/gi,
checkAccessCode: /(提取码|密码|访问码).+/gi,
accessCode: /([0-9a-zA-Z]{4})/gi,
uiLinkShow: "magnet:?xt=urn:btih:{#shareCode#}",
blank: "magnet:?xt=urn:btih:{#shareCode#}",
},
jianguoyun: {
link_innerText: `jianguoyun.com/p/[0-9a-zA-Z-_]{16,24}([\\s\\S]{0,${parseInt(
GM_getValue("innerText_jianguoyun", 20)
)}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,10}[0-9a-zA-Z]+|)`,
link_innerHTML: `jianguoyun.com/p/[0-9a-zA-Z-_]{16,24}([\\s\\S]{0,${parseInt(
GM_getValue("innerHTML_jianguoyun", 300)
)}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,15}[0-9a-zA-Z]+|)`,
shareCode: /jianguoyun.com\/p\/([0-9a-zA-Z\-_]{16,24})/gi,
shareCodeNeedRemoveStr: /jianguoyun.com\/p\//gi,
checkAccessCode: /(提取码|密码|访问码).+/gi,
accessCode: /([0-9a-zA-Z]+)/gi,
uiLinkShow: "jianguoyun.com/p/{#shareCode#} 提取码: {#accessCode#}",
blank: "https://www.jianguoyun.com/p/{#shareCode#}",
},
},
/**
* 初始化字典
*/
initLinkDict() {
NetDisk.linkDict = new Utils.Dictionary();
Object.keys(NetDisk.regular).forEach((keys) => {
NetDisk.linkDict.set(keys, new Utils.Dictionary());
});
},
/**
* 检查页面是否存在链接
* @param {String} clipboardText 剪贴板文本
*/
matchPageLink(clipboardText = "") {
let matchTextRange = GM_getValue("pageMatchRange", "innerText");
let ignoreStr = [
$(".whitesevPopOneFile"),
$(".whitesevPopMoreFile"),
$(".whitesevPop-whitesevPopSetting"),
]; /* 忽略的文字,如:设置、直链弹窗 */
if (matchTextRange.toLowerCase() === "all") {
this.pageText = $("body").prop("innerText");
ignoreStr.forEach((item) => {
let _str_ = item.prop("innerText");
_str_ = _str_ == null ? "" : _str_;
this.pageText = this.pageText.replaceAll(_str_, "");
});
let pageHTML = $("body").prop("innerHTML");
ignoreStr.forEach((item) => {
let _str_ = item.prop("innerHTML");
_str_ = _str_ == null ? "" : _str_;
pageHTML = pageHTML.replaceAll(_str_, "");
});
this.pageText += pageHTML;
this.pageText += clipboardText;
} else {
this.pageText = $("body").prop(matchTextRange) + clipboardText;
if (matchTextRange.toLowerCase() === "innertext") {
ignoreStr.forEach((item) => {
let _str_ = item.prop("innerText");
_str_ = _str_ == null ? "" : _str_;
this.pageText = this.pageText.replaceAll(_str_, "");
});
} else {
ignoreStr.forEach((item) => {
let _str_ = item.prop("innerHTML");
_str_ = _str_ == null ? "" : _str_;
this.pageText = this.pageText.replaceAll(_str_, "");
this.pageText = this.pageText.replaceAll(_str_, "");
});
}
}
if (!this.isInit) {
this.matchLink = new Set();
this.initLinkDict();
this.isInit = true;
}
if (matchTextRange.toLowerCase() === "all") {
$.each(this.regular, (netdiskName, item) => {
WorkerHandle.GM_matchWorker.postMessage({
regexp: new RegExp(item["link_innerText"], "gi"),
pageText: this.pageText,
netdiskName: netdiskName,
});
WorkerHandle.GM_matchWorker.postMessage({
regexp: new RegExp(item["link_innerHTML"], "gi"),
pageText: this.pageText,
netdiskName: netdiskName,
});
});
} else {
$.each(this.regular, (netdiskName, item) => {
WorkerHandle.GM_matchWorker.postMessage({
regexp: new RegExp(item[`link_${matchTextRange}`], "gi"),
pageText: this.pageText,
netdiskName: netdiskName,
});
});
}
},
/**
* 处理链接,将匹配到的链接转为参数和密码存入字典中
* @param {String} netDiskName 网盘名称
* @param {String} url
*/
handleLink(netDiskName, url) {
let currentDict = this.linkDict.get(netDiskName);
let shareCode = this.handleShareCode(netDiskName, url);
if (shareCode == "" || shareCode == null) {
return null;
}
let accessCode = this.handleAccessCode(netDiskName, url);
if (currentDict.has(shareCode)) {
let dictAccessCode = this.linkDict.get(netDiskName).get(shareCode);
if (dictAccessCode == "" && accessCode != "" && accessCode != null) {
currentDict.set(shareCode, accessCode);
UI.view.changeLinkView(netDiskName, shareCode, accessCode);
log.info(
`已存在该链接,但无密码,设置密码 ${netDiskName}: ${shareCode} ===> ${accessCode}`
);
}
} else {
this.hasMatchLink = true;
currentDict.set(shareCode, accessCode);
UI.matchIcon.add(netDiskName);
UI.view.addLinkView(netDiskName, shareCode, accessCode);
log.success(
`添加链接 ${netDiskName}: ${shareCode} ===> ${accessCode}`
);
}
},
/**
* 对传入的url进行处理,返回shareCode
* @param {String} netDiskName 网盘名称
* @param {String} url
* @returns
*/
handleShareCode(netDiskName, url) {
let shareCodeMatch = url.match(this.regular[netDiskName].shareCode);
if (
shareCodeMatch == null ||
(shareCodeMatch != null && shareCodeMatch.length === 0)
) {
log.error(`根据链接获取shareCode失败`);
log.error([arguments, this.regular[netDiskName].shareCode]);
return "";
}
let shareCode = shareCodeMatch[0].replace(
this.regular[netDiskName].shareCodeNeedRemoveStr,
""
);
let shareCodeNotMatch = this.regular[netDiskName].shareCodeNotMatch;
if (shareCodeNotMatch != null && shareCode.match(shareCodeNotMatch)) {
log.error(`不可能的shareCode => ${shareCode}`);
return "";
}
shareCode =
decodeURIComponent(shareCode); /* %E7%BD%91%E7%9B%98 => 网盘 */
return shareCode;
},
/**
* 对传入的url进行处理,返回accessCode
* @param {String} netDiskName 网盘名称
* @param {String} url
* @returns "https://xxx" || ""
*/
handleAccessCode(netDiskName, url) {
let accessCode = "";
let accessCodeMatch = url.match(
this.regular[netDiskName].checkAccessCode
);
if (accessCodeMatch) {
accessCode = accessCodeMatch[accessCodeMatch.length - 1].match(
this.regular[netDiskName].accessCode
);
if (accessCode == null) {
return "";
}
$.each(accessCode, (index, item) => {
if (!item.match(this.regular[netDiskName]["accessCodeNotMatch"])) {
return accessCode[index];
}
});
accessCode = accessCode[accessCode.length - 1];
}
return accessCode;
},
/**
* 获取在弹窗中显示出的链接
* @param {String} netDiskName 网盘名称,指NetDisk.regular的内部键名
* @param {String} shareCode
* @param {String} accessCode
* @returns
*/
handleLinkShow(netDiskName, shareCode, accessCode) {
let netDiskRegular = NetDisk.regular[netDiskName];
if (netDiskRegular == null) {
Qmsg.error("BUG: 获取uiLink规则失败");
log.error(["BUG: 分析参数", netDiskName, shareCode, accessCode]);
throw "错误";
}
let uiLink = netDiskRegular["uiLinkShow"].replace(
/{#shareCode#}/gi,
shareCode
);
if (accessCode && accessCode != "") {
uiLink = uiLink.replace(/{#accessCode#}/g, accessCode);
} else {
uiLink = uiLink.replace(/( |提取码:|{#accessCode#}|\?pwd=)/g, "");
}
return uiLink;
},
/**
* 获取剪贴板文本
* @returns
*/
getClipboardText() {
return new Promise((res) => {
navigator.permissions
.query({
name: "clipboard-read",
})
.then((result) => {
const hasFocus =
document.hasFocus(); /* 这个是重点,可判断是否为当前dom页面 */
if (
hasFocus &&
(result.state === "granted" || result.state === "prompt")
) {
const clipboard = navigator.clipboard.readText();
clipboard.then((clipText) => {
res(clipText);
});
} else {
res("");
}
});
});
},
};
const NetDiskLinkParse = {
/* 网盘直链解析 */
netdisk: {
baidu: {
default(shareCode, accessCode) {
let bdurl = GM_getValue("bdurl");
let paramSurl = GM_getValue("paramSurl");
let paramPwd = GM_getValue("paramPwd");
let paramKey = GM_getValue("paramKey");
let paramWebSiteKey = GM_getValue("paramWebSiteKey");
let baidu_website_key_enable = GM_getValue(
"baidu-website-key-enable",
false
);
if (!bdurl) {
Qmsg.error("请完善配置 网址-Url");
return null;
}
if (!paramSurl) {
Qmsg.error("请完善配置 参数-Key");
return null;
}
if (!paramPwd) {
Qmsg.error("请完善配置 密码-Key");
return null;
}
if (!paramKey) {
Qmsg.error("请完善配置 密钥-Key");
return null;
}
if (baidu_website_key_enable && !paramWebSiteKey) {
Qmsg.error("请完善配置 密钥-Value");
return null;
}
var tempFormNode = document.createElement("form");
var list = {}; /* 表单数据 */
list[paramSurl] = shareCode;
list[paramPwd] = accessCode;
if (baidu_website_key_enable) {
list[paramKey] = paramWebSiteKey;
}
tempFormNode.action = bdurl; /* 解析网址 */
tempFormNode.method = "post";
tempFormNode.style.display = "none";
tempFormNode.target = "_blank";
for (var x in list) {
var opt = document.createElement("textarea");
opt.name = x;
opt.value = list[x]; /* alert(opt.name) */
tempFormNode.appendChild(opt);
}
document.body.appendChild(tempFormNode);
tempFormNode.submit();
},
},
lanzou: {
/* 流程:判断是否是多文件
单文件 => 请求https://www.lanzoux.com/{shareToken} 判断链接类型和是否能正常获取
=> 请求https://www.lanzoux.com/tp/{shareToken} 获取文件sign
=> 请求https://www.lanzoux.com/ajaxm.php 获取下载参数,下载参数例如:https://develope.lanzoug.com/file/?xxxxxxxxx
多文件 => 先请求https://www.lanzoux.com/{shareToken} 获取文件sign => 请求https://www.lanzoux.com/filemoreajax.php 获取json格式的文件参数,参数内容如{"info":"success","text":[{"duan":"xx","icon":"","id":"".....},{},{}]} */
handleUrl: {
default: (replaced, shareCode) => {
return NetDisk.regular.lanzou.blank
.replace("/s/", replaced)
.replace(/{#shareCode#}/g, shareCode);
},
tp: (shareCode) => {
return NetDisk.regular.lanzou.blank
.replace("/s/", "/tp/")
.replace(/{#shareCode#}/gi, shareCode);
},
},
regexp: {
unicode: {
match: /[%\u4e00-\u9fa5]+/g /* 判断该链接是否是中文 */,
tip: "中文链接",
isUnicode: false,
},
noFile: {
match: /div>来晚啦...文件取消分享了<\/div>/g /* 蓝奏文件取消分享 */,
tip: "来晚啦...文件取消分享了",
},
noExists: {
match: /div>文件不存在,或已删除<\/div>/g /* 蓝奏文件链接错误 */,
tip: "文件不存在,或已删除",
},
moreFile: {
match:
/<span id=\"filemore\" onclick=\"more\(\);\">/g /* 蓝奏多文件 */,
},
sign: {
match:
/var[\s]*(posign|postsign)[\s]*=[\s]*'(.+?)';/ /* 蓝奏设置了密码的单文件请求需要的sign值 */,
},
fileName: {
match: /<title>(.*)<\/title>/ /* 蓝奏文件名 */,
},
size: {
match: /<span class=\"mtt\">\((.*)\)<\/span>/ /* 蓝奏文件大小 */,
},
loadDown: {
match:
/var[\s]*(loaddown|oreferr|spototo|domianload)[\s]*=[\s]*'(.+?)';/i /* 蓝奏文件直链 */,
},
},
async default(shareCode, accessCode) {
this.regexp.unicode.isUnicode = shareCode.match(
this.regexp.unicode.match
)
? true
: false;
this.replaced = this.regexp.unicode.isUnicode ? "/u/" : "/";
await this.getFileLink(shareCode, accessCode);
},
async getFileLink(
shareCode,
accessCode,
getShareCodeByPageAgain = false
) {
/* 获取文件下载链接 */
let that = this;
let url = this.handleUrl.default(this.replaced, shareCode);
log.info("蓝奏云-获取文件下载链接" + url);
let getResp = await httpx.get({
url: url,
headers: {
Accept: "*/*",
"User-Agent": Utils.getRandomAndroidUA(),
referer: window.location.origin,
},
});
if (!getResp.status) {
return;
}
let respData = getResp.data;
if (respData.status !== 200 || respData.readyState !== 4) {
log.error(respData);
Qmsg.error("请求失败,请重试");
return;
}
if (!that.checkPageCode(respData)) {
return;
}
if (that.isMoreFile(respData)) {
log.info("该链接为多文件");
await that.getMoreFile(shareCode, accessCode);
} else {
log.info("该链接为单文件");
log.info(respData);
if (getShareCodeByPageAgain) {
let shareCodeNewMatch = respData.responseText.match(
/var[\s]*link[\s]*=[\s]*\'tp\/(.+?)\';/i
);
shareCode = shareCodeNewMatch[shareCodeNewMatch.length - 1];
log.info(`新参数 => ${shareCode}`);
}
await that.getLinkByTp(shareCode, accessCode);
}
},
checkPageCode(resp) {
/* 页面检查,看看是否存在文件失效情况 */
let pageText = resp.responseText;
if (pageText.match(this.regexp.noFile.match)) {
Qmsg.error(this.regexp.noFile.tip);
return false;
}
if (pageText.match(this.regexp.noExists.match)) {
Qmsg.error(this.regexp.noExists.tip);
return false;
}
return true;
},
isMoreFile(resp) {
/* 判断是否是多文件的链接 */
let pageText = resp.responseText;
if (pageText.match(this.regexp.moreFile.match)) {
log.info("该链接为多文件");
return true;
}
return false;
},
async getLinkByTp(shareCode, accessCode) {
/* 访问蓝奏tp获取sign */
let that = this;
let getResp = await httpx.get({
url: that.handleUrl.tp(shareCode),
headers: {
Accept: "*/*",
"User-Agent": Utils.getRandomAndroidUA(),
referer: window.location.origin,
},
});
if (!getResp.status) {
return;
}
let respData = getResp.data;
log.info("by_tp ↓");
log.info(respData);
if (respData.status == 200 && respData.readyState == 4) {
await that.getLink(respData, shareCode, accessCode);
} else {
Qmsg.error("请求失败,请重试");
}
},
async getLink(response, shareCode, accessCode) {
/* 获取链接 */
let that = this;
let pageText = response.responseText;
if (pageText == null) {
log.error("shareCode错误,重新从页面中获取");
await this.getFileLink(shareCode, accessCode, true);
return;
}
let sign = pageText.match(this.regexp.sign.match);
let postData_p = "";
let postData_sign = "";
let fileNameMatch = pageText.match(this.regexp.fileName.match);
let fileName = fileNameMatch ? fileNameMatch[1].trim() : "";
let fileSizeMatch = pageText.match(this.regexp.size.match);
let fileSize = fileSizeMatch ? fileSizeMatch[1].trim() : "";
if (sign) {
postData_sign = sign[sign.length - 1];
log.info(`获取Sign: ${postData_sign}`);
if (accessCode) {
log.info("传入参数=>有密码");
postData_p = accessCode;
} else {
log.info("传入参数=>无密码");
}
let postResp = await httpx.post({
url: "https://www.lanzoux.com/ajaxm.php",
responseType: "json",
headers: {
"content-type":
"application/x-www-form-urlencoded; charset=UTF-8",
"user-agent": Utils.getRandomAndroidUA(),
referer: window.location.origin,
},
data: `action=downprocess&sign=${postData_sign}&p=${postData_p}`,
});
if (!postResp.status) {
return;
}
let respData = postResp.data;
log.info(respData);
if (respData.status == 200 && respData.readyState == 4) {
let json_data = JSON.parse(respData.responseText);
let downloadUrl = `${json_data["dom"]}/file/${json_data["url"]}`;
let zt = json_data["zt"];
if ("密码不正确".indexOf(json_data["inf"]) != -1) {
Qmsg.error("密码不正确!");
UI.newAccessCodeView(
undefined,
"lanzou",
shareCode,
(userInputAccessCode) => {
that.default(shareCode, userInputAccessCode);
}
);
} else {
fileName = json_data["inf"] ? json_data["inf"] : fileName;
downloadUrl = await NetDiskLinkParse.getRedirectFinalUrl(
downloadUrl,
Utils.getRandomAndroidUA()
);
log.info(downloadUrl);
downloadUrl = filterScheme.handleUrl(
"lanzou-static-scheme-enable",
"lanzou-static-scheme-forward",
downloadUrl
);
UI.staticView.oneFile(
"蓝奏云单文件直链",
fileName,
fileSize,
downloadUrl
);
}
} else {
Qmsg.error("请求失败,请重试");
}
} else {
let loaddown = pageText.match(this.regexp.loadDown.match);
if (loaddown == null) {
loaddown = pageText.match(/cppat[\s]*\+[\s]*'(.+?)'/i);
}
if (loaddown != null) {
let downloadUrl = `https://develope.lanzoug.com/file/${
loaddown[loaddown.length - 1]
}`;
log.info([fileName, fileSize, downloadUrl]);
downloadUrl = await NetDiskLinkParse.getRedirectFinalUrl(
downloadUrl,
Utils.getRandomAndroidUA()
);
log.info(downloadUrl);
downloadUrl = filterScheme.handleUrl(
"lanzou-static-scheme-enable",
"lanzou-static-scheme-forward",
downloadUrl
);
UI.staticView.oneFile(
"蓝奏云单文件直链",
fileName,
fileSize,
downloadUrl
);
} else {
Qmsg.error("获取sign失败");
}
}
},
async getMoreFile(shareCode, accessCode) {
/* 多文件获取 */
let that = this;
let getResp = await httpx.get({
url: that.handleUrl.default(this.replaced, shareCode),
headers: {
Accept: "*/*",
"user-agent": Utils.getRandomAndroidUA(),
referer: window.location.origin,
},
});
if (!getResp.status) {
return;
}
let respData = getResp.data;
log.info(respData);
if (respData.status !== 200 || 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 = 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=${accessCode}`;
log.info(`多文件请求参数:${postData}`);
let postResp = await httpx.post({
url: "https://www.lanzoux.com/filemoreajax.php",
responseType: "json",
headers: {
"Content-Type":
"application/x-www-form-urlencoded; charset=UTF-8",
"user-agent": Utils.getRandomAndroidUA(),
referer: window.location.origin,
},
data: postData,
});
if (!postResp.status) {
return;
}
let postRespData = postResp.data;
log.info(postRespData);
let json_data = JSON.parse(postRespData.responseText);
let zt = json_data["zt"];
let info = json_data["info"];
if (zt === 4) {
Qmsg.error(info);
} else if (zt === 1) {
Qmsg.success("获取文件夹成功,解析文件直链中...");
var folder = json_data["text"]; /* 获取多文件的数组信息 */
var folderContent = ""; /* 弹出内容 */
log.info(`本链接一共${folder.length}个文件`);
for (let i = 0; i < folder.length; i++) {
let item = folder[i];
let _shareCode_ = item.id;
let fileName = item.name_all;
let fileSize = item.size;
let uploadTime = item.time;
log.info(`第${i + 1}个开始解析`);
let content = await that.parseMoreFile(
_shareCode_,
fileName,
fileSize
);
log.info(`第${i + 1}个解析完毕`);
folderContent += content;
}
UI.staticView.moreFile("蓝奏云多文件直链", folderContent);
} else if ("密码不正确".indexOf(info) !== -1) {
Qmsg.error("密码不正确!");
UI.newAccessCodeView(
undefined,
"lanzou",
shareCode,
(userInputAccessCode) => {
that.default(shareCode, userInputAccessCode);
}
);
} else if ("没有了".indexOf(info) !== -1) {
Qmsg.error("没有文件了");
} else {
Qmsg.error("未知错误");
}
},
async parseMoreFile(shareCode, fileName, fileSize) {
/* 根据获取到的json中多文件链接来获取单文件直链 */
let resultContent = "";
let that = this;
let getResp = await httpx.get({
url: that.handleUrl.tp(shareCode),
headers: {
Accept: "*/*",
"user-agent": Utils.getRandomAndroidUA(),
referer: window.location.origin,
},
});
let respData = getResp.data;
if (getResp.status) {
let pageText = respData.responseText;
let loaddown = pageText.match(
NetDiskLinkParse.netdisk.lanzou.regexp.loadDown.match
);
if (loaddown == null) {
loaddown = pageText.match(/cppat[\s]*\+[\s]*'(.+?)'/i);
}
let submit_url = "javascript:;";
let downloadUrl = "";
if (loaddown != null) {
let needRedirectDownloadUrl = `https://develope.lanzoug.com/file/${
loaddown[loaddown.length - 1]
}`;
downloadUrl = await NetDiskLinkParse.getRedirectFinalUrl(
needRedirectDownloadUrl,
Utils.getRandomAndroidUA()
);
submit_url = filterScheme.handleUrl(
"lanzou-static-scheme-enable",
"lanzou-static-scheme-forward",
downloadUrl
);
} else if (pageText.match("来晚啦...文件取消分享了</div>")) {
fileSize = "来晚啦...文件取消分享了";
} else {
fileSize = "解析直链失败";
}
resultContent = `
<div class="netdisk-static-body">
<div class="netdisk-static-filename">
<a target="${
submit_url === "javascript:;" ? "" : "_blank"
}" href="${submit_url}">${fileName}</a>
</div>
<div class="netdisk-static-filesize">${fileSize}</div>
</div>
`;
} else {
log.error(respData);
resultContent = `
<div class="netdisk-static-body">
<div class="netdisk-static-filename">
<a href="javascript:;">${fileName}</a>
</div>
<div class="netdisk-static-filesize">解析失败,${getResp.msg}</div>
</div>
`;
}
return resultContent;
},
},
tianyiyun: {
code: {
ShareAuditNotPass: "抱歉,该内容审核不通过",
FileNotFound: "抱歉,文件不存在",
ShareExpiredError: "抱歉,您访问的页面地址有误,或者该页面不存在",
ShareAuditWaiting: "抱歉,该链接处于审核中",
ShareInfoNotFound: "抱歉,您访问的页面地址有误,或者该页面不存在",
FileTooLarge: "抱歉,文件太大,不支持下载",
InvalidSessionKey:
"天翼云Session已失效,是否前去登录?<br /> (注意,需要当前浏览器的UA切换成PC才能进行登录)",
},
async default(shareCode, accessCode) {
log.info([shareCode, accessCode]);
this.shareCode = shareCode;
this.accessCode = accessCode;
await this.getDownloadParams();
},
async getDownloadParams() {
let that = this;
let postResp = await httpx.post({
url: "https://cloud.189.cn/api/open/share/getShareInfoByCodeV2.action",
data: `shareCode=${that.shareCode}`,
headers: {
accept: "application/json;charset=UTF-8",
"content-type": "application/x-www-form-urlencoded",
"user-agent":
"Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Mobile Safari/537.36 Edg/94.0.992.38",
referer: "https://h5.cloud.189.cn/",
origin: "https://h5.cloud.189.cn",
},
});
if (!postResp.status) {
return;
}
let postData = postResp.data;
log.info(postData);
let jsonData = JSON.parse(postData.responseText);
if (postData.status == 200 && jsonData.res_code == 0) {
log.info(jsonData);
this.isFolder = jsonData.isFolder;
if (jsonData["needAccessCode"] && !this.accessCode) {
Qmsg.error("密码不正确!");
UI.newAccessCodeView(
undefined,
"tianyiyun",
this.shareCode,
(userInputAccessCode) => {
that.default(that.shareCode, userInputAccessCode);
}
);
return;
}
if (this.isFolder) {
log.info("该链接是文件夹");
if (this.accessCode) {
GM_setClipboard(this.accessCode);
Qmsg.info("提取码已复制");
}
window.open(`https://cloud.189.cn/t/${this.shareCode}`, "_blank");
return;
}
this.fileId = jsonData.fileId;
this.fileName = jsonData.fileName;
this.fileSize = jsonData.fileSize;
this.fileType = jsonData.fileType;
this.shareId = jsonData.shareId;
if (!this.shareId) {
await this.getShareId();
} else {
await this.getDownloadUrl();
}
} else {
if (this.code.hasOwnProperty(jsonData["res_code"])) {
Qmsg.error(this.code[jsonData["res_code"]]);
} else {
Qmsg.error("获取FileId失败");
}
}
},
getCookie() {
/* 暂不需要获取cookie */
let cookie = "";
return cookie;
},
async getShareId() {
let that = this;
let getResp = await httpx.get({
url: `https://cloud.189.cn/api/open/share/checkAccessCode.action?noCache=0.44175365295952296&shareCode=${that.shareCode}&accessCode=${that.accessCode}`,
headers: {
accept: "application/json;charset=UTF-8",
"cache-control": "no-cache",
"user-agent": Utils.getRandomAndroidUA(),
referer: `https://cloud.189.cn/web/share?code=${that.shareCode}`,
},
responseType: "json",
});
if (!getResp.status) {
return;
}
let respData = getResp.data;
log.info(respData);
let jsonData = JSON.parse(respData.responseText);
if (respData.status === 200 && jsonData["res_message"] === "成功") {
this.shareId = jsonData["shareId"];
await this.getDownloadUrl();
} else {
Qmsg.error("获取shareId失败");
log.info(jsonData);
}
},
async getDownloadUrl() {
let that = this;
let getResp = await httpx.get({
url: `https://cloud.189.cn/api/open/file/getFileDownloadUrl.action?noCache=0.8242175875972797&fileId=${that.fileId}&dt=1&shareId=${that.shareId}`,
headers: {
accept: "application/json;charset=UTF-8",
"cache-control": "no-cache",
"user-agent": Utils.getRandomPCUA(),
referer: `https://cloud.189.cn/web/share?code=${that.shareCode}`,
},
cookie: that.getCookie(),
responseType: "json",
});
if (!getResp.status) {
return;
}
let respData = getResp.data;
let jsonData = JSON.parse(respData.responseText);
log.info(jsonData);
if (respData.status == 200 && jsonData.res_code == 0) {
let download_url = jsonData.fileDownloadUrl;
download_url = filterScheme.handleUrl(
"tianyiyun-scheme-enable",
"tianyiyun-scheme-forward",
download_url
);
UI.staticView.oneFile(
"天翼云单文件直链",
this.fileName,
Utils.formatByteToSize(this.fileSize),
download_url
);
} else if (
"InvalidSessionKey" === jsonData["res_code"] ||
"InvalidSessionKey" === jsonData["errorCode"]
) {
var loginPops = pops.confirm({
title: {
position: "center",
text: "天翼云",
},
content: {
text: that.code[jsonData.errorCode],
html: false,
},
btn: {
reverse: true,
position: "end",
ok: {
text: "前往",
enable: true,
callback: () => {
pops.iframe({
title: {
text: "天翼云登录",
},
loading: {
text: "加载中...",
},
btn: {
close: {
callback: () => {
loginPops?.close();
var waitRegister = pops.loading({
parent: document.body,
only: false,
content: {
text: "等待5s,登录的账号注册Cookies",
},
animation: GM_getValue(
"popsAnimation",
"pops-anim-fadein-zoom"
),
});
var registerTianYiYunCookies = GM_openInTab(
"https://cloud.189.cn/web/main/",
{ active: false, setParent: true }
);
setTimeout(() => {
registerTianYiYunCookies?.close();
waitRegister?.close();
that.getDownloadUrl();
}, 5000);
},
},
},
url: "https://cloud.189.cn/api/portal/loginUrl.action?redirectURL=https://cloud.189.cn/web/Fredirect.html",
height: pops.isPhone() ? "400px" : "400px",
width: pops.isPhone() ? "350px" : "350px",
drag: GM_getValue("pcDrag", false),
animation: GM_getValue(
"popsAnimation",
"pops-anim-fadein-zoom"
),
sandbox: true,
});
},
},
},
animation: GM_getValue("popsAnimation", "pops-anim-fadein-zoom"),
mask: true,
drag: GM_getValue("pcDrag", false),
height: "180px",
width: pops.isPhone() ? "350px" : "450px",
});
} else if (this.code.hasOwnProperty(jsonData["res_code"])) {
Qmsg.error(this.code[jsonData["res_code"]]);
} else {
Qmsg.error("请求失败");
log.error(respData);
}
},
},
hecaiyun: {
/* 不行 */
default(shareCode, accessCode) {
log.info([shareCode, accessCode]);
},
},
aliyun: {
/* 不行 */
default(shareCode, accessCode) {
log.info([shareCode, accessCode]);
},
},
wenshushu: {
code: {
1004: "no token",
1013: "糟糕,此任务已过期销毁,下次要记得续期",
1088: "糟糕,您访问的页面不存在",
},
async default(shareCode, accessCode) {
this.tid = shareCode;
Qmsg.info("正在请求直链中...");
await this.getWss();
},
async getWss() {
let postResp = await httpx.post({
url: "https://www.wenshushu.cn/ap/login/anonymous",
responseType: "json",
dataType: "json",
data: JSON.stringify({
dev_info: "{}",
}),
headers: {
accept: "application/json, text/plain, */*",
"user-agent": Utils.getRandomAndroidUA(),
referer: window.location.origin,
},
});
if (!postResp.status) {
return;
}
let respData = postResp.data;
let jsonData = JSON.parse(respData.responseText);
if (respData.status == 200 && jsonData["code"] == 0) {
this.token = jsonData["data"]["token"];
await this.getPid();
} else if (jsonData["code"] in this.code) {
Qmsg.error(this.code[jsonData["code"]]);
} else {
Qmsg.error("获取wss失败");
}
},
async getPid() {
let that = this;
let postResp = await httpx.post({
url: "https://www.wenshushu.cn/ap/task/mgrtask",
dataType: "json",
responseType: "json",
data: JSON.stringify({
tid: that.tid,
password: "",
ufileid: "",
}),
headers: {
accept: "application/json, text/plain, */*",
"user-agent": Utils.getRandomAndroidUA(),
referer: window.location.origin,
"x-token": that.token,
},
});
if (!postResp.status) {
return;
}
let respData = postResp.data;
let jsonData = JSON.parse(respData.responseText);
if (respData.status == 200 && jsonData["code"] == 0) {
let bid = jsonData["data"]["boxid"];
let pid = jsonData["data"]["ufileid"];
await this.getFileNList(bid, pid);
} else if (jsonData["code"] in this.code) {
Qmsg.error(this.code[jsonData["code"]]);
} else {
Qmsg.error("获取pid失败");
}
},
async getFileNList(bid, pid) {
let that = this;
let postResp = await httpx.post({
url: "https://www.wenshushu.cn/ap/ufile/nlist",
dataType: "json",
responseType: "json",
data: JSON.stringify({
start: 0,
sort: {
name: "asc",
},
bid: bid,
pid: pid,
options: {
uploader: "true",
},
size: 50,
}),
headers: {
accept: "application/json, text/plain, */*",
"user-agent":
"Mozilla/5.0 (Linux; Android 6.0.1; Moto G (4)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Mobile Safari/537.36 Edg/91.0.864.59",
referer: window.location.origin,
"x-token": that.token,
},
});
if (!postResp.status) {
return;
}
let respData = postResp.data;
let jsonData = JSON.parse(respData.responseText);
if (respData.status == 200 && jsonData["code"] == 0) {
await this.getDownloadUrl(jsonData["data"]["fileList"][0]);
} else if (jsonData["code"] in this.code) {
Qmsg.error(this.code[jsonData["code"]]);
} else {
Qmsg.error("获取文件信息失败");
}
},
async getDownloadUrl(data) {
let that = this;
let file_name = data.fname;
let file_size = Utils.formatByteToSize(data.size);
let postResp = await httpx.post({
url: "https://www.wenshushu.cn/ap/dl/sign",
dataType: "json",
responseType: "json",
data: JSON.stringify({
ufileid: data.fid,
consumeCode: 0,
}),
headers: {
accept: "application/json, text/plain, */*",
"user-agent": Utils.getRandomAndroidUA(),
referer: window.location.origin,
"x-token": that.token,
},
});
if (!postResp.status) {
return;
}
let respData = postResp.data;
let jsonData = JSON.parse(respData.responseText);
if (respData.status == 200 && jsonData["code"] == 0) {
let download_url = jsonData["data"]["url"];
if (download_url == "") {
Qmsg.error("对方的分享流量不足");
} else {
download_url = filterScheme.handleUrl(
"wenshushu-static-scheme-enable",
"wenshushu-static-scheme-forward",
download_url
);
UI.staticView.oneFile(
"文叔叔单文件直链",
file_name,
file_size,
download_url
);
}
} else if (jsonData["data"] in this.code) {
Qmsg.error(this.code[jsonData["data"]]);
} else {
Qmsg.error("获取下载链接失败");
}
},
},
nainiu: {
/* 不行 */
default(shareCode, accessCode) {
log.info([shareCode, accessCode]);
},
},
_123pan: {
code: {
5103: "分享码错误或者分享地址错误",
5104: "分享已过期",
"-1000": "获取出错",
"-2000": "请求异常",
"-3000": "请求意外中止",
"-4000": "请求超时",
104: "文件已失效",
},
async default(shareCode, accessCode) {
log.info([shareCode, accessCode]);
this.shareCode = shareCode;
this.accessCode = accessCode;
this.panelList = [];
this.panelContent = "";
let checkLinkValidityStatus = await this.checkLinkValidity(
shareCode,
accessCode
);
if (!checkLinkValidityStatus) {
return;
}
let infoLists = await this.getFiles(shareCode, accessCode);
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 this.getFileDownloadInfo(
fileInfo["Etag"],
fileInfo["FileId"],
fileInfo["S3KeyFlag"],
this.shareCode,
fileInfo["Size"]
);
if (downloadInfo && downloadInfo["code"] === 0) {
downloadUrl = filterScheme.handleUrl(
"_123pan-static-scheme-enable",
"_123pan-static-scheme-forward",
downloadInfo["data"]["DownloadURL"]
);
fileSize = Utils.formatByteToSize(fileInfo["Size"]);
} else {
downloadUrl = "javascript:;";
fileSize = "获取下载链接失败";
}
} else {
downloadUrl = filterScheme.handleUrl(
"_123pan-static-scheme-enable",
"_123pan-static-scheme-forward",
downloadUrl
);
fileSize = Utils.formatByteToSize(fileInfo["Size"]);
}
UI.staticView.oneFile(
"123盘单文件直链",
fileInfo["FileName"],
fileSize,
downloadUrl
);
} else {
Qmsg.info("正在递归文件");
this.folderNumber = 0;
await this.recursiveAlgorithm(infoLists);
Qmsg.info("正在排序中...");
this.panelList.sort(
Utils.sortListByProperty((item) => {
let timeStamp = new Date(item["updateTime"]).getTime();
return timeStamp;
})
);
log.info(this.panelList);
this.panelList.forEach((item) => {
if (
item["url"] === "获取下载链接失败" ||
item["fileSize"] === 0
) {
this.panelContent += `
<div class="netdisk-static-body">
<div class="netdisk-static-filename">
<a href="javascript:;">${item["fileName"]}</a>
</div>
<div class="netdisk-static-filesize">${item["fileSize"]}-获取下载链接失败</div>
</div>`;
} else {
this.panelContent += `
<div class="netdisk-static-body">
<div class="netdisk-static-filename">
<a target="_blank" href="${item["url"]}">${item["fileName"]}</a>
</div>
<div class="netdisk-static-filesize">${item["fileSize"]}</div>
</div>`;
}
});
UI.staticView.moreFile("123盘多文件直链", this.panelContent);
log.info("递归完毕");
}
},
async checkLinkValidity(shareCode, accessCode) {
/* 校验链接有效性 */
Qmsg.info("正在校验链接有效性");
let that = this;
let url = `https://www.123pan.com/s/${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;
}
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 = JSON.parse(
`{${g_initialPropsMatch[g_initialPropsMatch.length - 1]}}`
);
log.info(g_initialProps);
if (g_initialProps.res.code !== 0) {
Qmsg.error(g_initialProps.res.message);
return;
}
let HasPwd = g_initialProps.res.data.HasPwd;
if (HasPwd && (accessCode == null || accessCode == "")) {
/* 该链接需要密码但是没有获取到 */
Qmsg.error("密码缺失!");
UI.newAccessCodeView(
"密码缺失",
"_123pan",
shareCode,
(userInputAccessCode) => {
that.default(shareCode, userInputAccessCode);
}
);
} else {
/* 该链接不需要密码 || 该链接需要密码且已获取到 */
return true;
}
} else {
Qmsg.error("校验链接-获取初始化内容失败");
}
},
async getFiles(shareCode, accessCode, parentFileId = 0) {
/* 获取文件 */
let that = this;
let url = `https://www.123pan.com/b/api/share/get?limit=100&next=1&orderBy=share_id&orderDirection=desc&shareKey=${shareCode}&SharePwd=${accessCode}&ParentFileId=${parentFileId}&Page=1`;
let getResp = await httpx.get({
url: url,
headers: {
accept: "*/*",
"user-agent": Utils.getRandomPCUA(),
referer: `https://www.123pan.com/s/${shareCode}`,
},
});
log.info(getResp);
if (getResp.status) {
let respData = getResp.data;
let json_data = JSON.parse(respData.responseText);
if (respData.status == 200 && json_data["code"] == 0) {
let infoList = json_data["data"]["InfoList"];
return infoList;
} else if (json_data["code"] == 5103) {
UI.newAccessCodeView(
undefined,
"_123pan",
shareCode,
(userInputAccessCode) => {
that.default(shareCode, userInputAccessCode);
}
);
}
}
},
async getFilesByRec(shareCode, accessCode, 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=${shareCode}&SharePwd=${accessCode}&ParentFileId=${parentFileId}&Page=1`,
headers: {
accept: "*/*",
"user-agent": Utils.getRandomAndroidUA(),
referer: `https://www.123pan.com/s/${shareCode}`,
},
});
if (getResp.status) {
let respData = getResp.data;
log.info(respData);
let jsonData = JSON.parse(respData.responseText);
if (respData.status == 200 && jsonData["code"] == 0) {
return jsonData["data"]["InfoList"];
}
}
},
async recursiveAlgorithm(infoList) {
/* 异步递归算法 */
let that = this;
for (let i = 0; i < infoList.length; i++) {
let item = infoList[i];
let fileType = item["Type"];
log.info(fileType ? "文件夹" : "文件");
if (fileType) {
/* 是文件夹 */
let retList = await that.getFilesByRec(
that.shareCode,
that.accessCode,
item["FileId"]
);
retList && (await that.recursiveAlgorithm(retList));
} else {
/* 是文件 */
log.info(item);
let fileName = item["FileName"];
let fileSize = Utils.formatByteToSize(item["Size"]);
let fileDownloadUrl = item["DownloadUrl"];
let fileStatus = item["Status"]; /* 文件有效状态 */
if (fileStatus == 104) {
that.panelList = [
...that.panelList,
{
url: "文件已失效",
fileName: fileName,
fileSize: 0,
createTime: item["CreateAt"],
updateTime: item["UpdateAt"],
},
];
} else if (fileDownloadUrl == "") {
let downloadInfo = await that.getFileDownloadInfo(
item["Etag"],
item["FileId"],
item["S3KeyFlag"],
that.shareCode,
item["Size"]
);
if (downloadInfo && downloadInfo["code"] === 0) {
fileDownloadUrl = downloadInfo["data"]["DownloadURL"];
filterScheme.handleUrl(
"_123pan-static-scheme-enable",
"_123pan-static-scheme-forward",
fileDownloadUrl
);
that.panelList = [
...that.panelList,
{
url: fileDownloadUrl,
fileName: fileName,
fileSize: fileSize,
createTime: item["CreateAt"],
updateTime: item["UpdateAt"],
},
];
} else {
that.panelList = [
...that.panelList,
{
url: "获取下载链接失败",
fileName: fileName,
fileSize: 0,
createTime: item["CreateAt"],
updateTime: item["UpdateAt"],
},
];
}
} else {
fileDownloadUrl = filterScheme.handleUrl(
"_123pan-static-scheme-enable",
"_123pan-static-scheme-forward",
fileDownloadUrl
);
that.panelList = [
...that.panelList,
{
url: fileDownloadUrl,
fileName: fileName,
fileSize: fileSize,
createTime: item["CreateAt"],
updateTime: item["UpdateAt"],
},
];
}
}
}
},
async getFileDownloadInfo(Etag, FileID, S3keyFlag, ShareKey, Size) {
/* 获取单文件下载链接 */
let that = this;
let postResp = await httpx.post({
url: "http://www.123pan.com/a/api/share/download/info",
data: JSON.stringify({
Etag: Etag,
FileID: FileID,
S3keyFlag: S3keyFlag,
ShareKey: ShareKey,
Size: Size,
}),
headers: {
accept: "*/*",
"user-agent": Utils.getRandomPCUA(),
},
});
if (!postResp.status) {
return;
}
let postData = postResp.data;
let jsonData = JSON.parse(postData.responseText);
log.info(jsonData);
if (jsonData["code"] == 0) {
jsonData["data"]["DownloadURL"] = that.decodeDownloadUrl(
jsonData["data"]["DownloadURL"]
);
return jsonData;
} else {
return {
code: jsonData["code"],
};
}
},
decodeDownloadUrl(url) {
/* 将直链的param参数解析成真正的直链 */
if (url === "") {
return "";
}
const decodeURL = new URL(url);
const params = decodeURL.search.replace(/^\?params=/gi, "");
const atobURL = atob(params);
return decodeURI(atobURL);
},
},
weiyun: {
/* 不行 */
default(shareCode, accessCode) {
/* https://share.weiyun.com/webapp/json/weiyunQdiskClient/DiskUserInfoGet?refer=chrome_windows&g_tk=
不做解析 微云QQ或微信登录的有效期很短 */
log.info([shareCode, accessCode]);
},
},
xunlei: {
/* 不行 */
default(shareCode, accessCode) {
log.info([shareCode, accessCode]);
},
},
_115pan: {
/* 不行 */
default(shareCode, accessCode) {
log.info([shareCode, accessCode]);
},
},
chengtong1: {
/* 不行 */
default(shareCode, accessCode) {
log.info([shareCode, accessCode]);
},
},
chengtong2: {
/* 不行 */
default(shareCode, accessCode) {
log.info([shareCode, accessCode]);
},
},
chengtong3: {
/* 不行 */
default(shareCode, accessCode) {
log.info([shareCode, accessCode]);
},
},
kuake: {
/* 不行-需要转存到自己的网盘中fied才可以通过验证传递回下载地址,通过分享到是不会传回来的 */
code: {
14001: "非法token",
21001: "文件不存在",
15000: "inner error",
},
async default(shareCode, accessCode) {
log.info([shareCode, accessCode]);
Qmsg.error("抱歉,夸克不支持直链获取");
return;
this.shareCode = shareCode;
this.accessCode = accessCode;
this.url = NetDisk.regular.kuake.blank.replace(
/{#shareCode#}/g,
shareCode
);
this.shareStoken = await this.getShareStoken(); /* 分享的stoken */
log.info(`stoken: ${this.shareStoken}`);
if (this.shareStoken != "") {
let data_list = await this.getFolderInfo();
if (data_list.length == 0) {
Qmsg.error("获取失败");
} else if (data_list.length == 1 && data_list[0]["file"]) {
log.info("夸克单文件直链");
await this.parseFileLink(data_list[0]);
} else {
log.info("夸克多文件直链");
await this.parseMoreFileLink(data_list);
log.info("全部解析完毕");
}
}
},
async getShareStoken() {
/* 获取ShareStoken */
let that = this;
let postResp = await httpx.post({
url: "https://drive.quark.cn/1/clouddrive/share/sharepage/token?pr=ucpro&fr=h5",
data: JSON.stringify({
pwd_id: that.shareCode,
passcode: that.accessCode,
}),
headers: {
Accept: "application/json, text/plain, */*",
"user-agent": Utils.getRandomPCUA(),
referer: "https://pan.quark.cn/",
origin: "https://pan.quark.cn",
},
});
if (!postResp.status) {
return "";
}
let respData = postResp.data;
let jsonData = JSON.parse(respData.responseText);
if (jsonData["status"] == 200) {
return jsonData["data"]["stoken"];
} else {
log.info(jsonData);
Qmsg.error(jsonData["message"]);
return "";
}
},
async getFolderInfo(pdir_fid) {
/* 获取文件夹信息 */
let that = this;
pdir_fid = pdir_fid == null ? "" : pdir_fid;
let getResp = await httpx.get({
url: `https://drive.quark.cn/1/clouddrive/share/sharepage/detail?pr=ucpro&fr=pc&pwd_id=${that.shareCode}&stoken=${that.shareStoken}&pdir_fid=${pdir_fid}&force=0&_page=1&_size=50&_fetch_banner=0&_fetch_share=0&_fetch_total=1&_sort=file_type:asc,updated_at:desc`,
headers: {
Accept: "application/json, text/plain, */*",
"user-agent": Utils.getRandomPCUA(),
referer: "https://pan.quark.cn/",
origin: "https://pan.quark.cn",
},
});
if (!getResp.status) {
return [];
}
let respData = getResp.data;
let jsonData = JSON.parse(respData.responseText);
log.info(jsonData);
if (this.code[jsonData["code"]] != null) {
Qmsg.error(this.code[jsonData["code"]]);
res([]);
} else if (jsonData["status"] == 200) {
res(jsonData["data"]["list"]);
} else {
Qmsg.error(jsonData["message"]);
res([]);
}
},
async getLink(fids) {
/* 获取链接 */
let postResp = await httpx.post({
url: "https://drive.quark.cn/1/clouddrive/file/download?pr=ucpro&fr=pc&ve=2.1.5",
headers: {
"Content-Type": "application/json;charset=utf-8",
},
data: JSON.stringify({
fids: [fids],
}),
});
if (!postResp.status) {
return [];
}
let respData = postResp.data;
let jsonData = JSON.parse(respData.responseText);
log.info(jsonData);
if (this.code[jsonData["code"]] != null) {
Qmsg.error(this.code[jsonData["code"]]);
res([]);
} else {
res(jsonData);
}
},
async parseFileLink(_data_) {
/* 解析单文件链接 */
let downloadUrl = await this.getLink(_data_["fid"]);
return downloadUrl;
},
async parseMoreFileLink(_data_) {
/* 解析多文件链接 */
let that = this;
_data_ = Array.from(_data_);
for (let i = 0; i < _data_.length; i++) {
let item = _data_[i];
if (item["file"]) {
/* 是文件 */
log.info("是文件");
log.info(item);
let fileInfo = await that.getLink(item["fid"]);
log.info(fileInfo);
} else {
/* 是文件夹 */
let folderInfo = await that.getFolderInfo(item["fid"]);
if (folderInfo.length != 0) {
await that.parseMoreFileLink(folderInfo);
}
}
}
},
},
jianguoyun: {
errorCode: {
UnAuthorized: "请先登录坚果云账号",
},
async default(shareCode, accessCode) {
log.info([shareCode, accessCode]);
this.shareCode = shareCode;
this.accessCode = accessCode;
let downloadParams = await this.getRequestDownloadParams();
if (!downloadParams) {
return;
}
if (downloadParams["isdir"]) {
/* 是文件夹 */
this.parseMoreFile(downloadParams["hash"], downloadParams["name"]);
} else {
/* 是文件 */
let fileSize = Utils.formatByteToSize(downloadParams["size"]);
let downloadUrl = await this.getFileLink(
downloadParams.hash,
downloadParams.name
);
if (!downloadUrl) {
return;
}
downloadUrl = filterScheme.handleUrl(
"jianguoyun-static-scheme-enable",
"jianguoyun-static-scheme-forward",
downloadUrl
);
log.info(downloadUrl);
UI.staticView.oneFile(
"坚果云盘单文件直链",
downloadParams["name"],
fileSize,
downloadUrl
);
}
},
/**
* 解析多文件信息
* @param {String} hash 文件hash值
* @param {String} currentLocation 当前位置
* @returns
*/
async parseMoreFile(hash = "", currentLocation = "") {
let folderInfo = await this.getFolderInfo(hash);
if (!folderInfo) {
return;
}
let that = this;
let downloadList = [];
for (let i = 0; i < folderInfo.length; i++) {
let item = folderInfo[i];
let downloadUrl = await that.getDirLink(
hash,
currentLocation,
item["relPath"]
);
if (!downloadUrl) {
return;
}
downloadUrl = filterScheme.handleUrl(
"jianguoyun-static-scheme-enable",
"jianguoyun-static-scheme-forward",
downloadUrl
);
log.info(downloadUrl);
downloadList = [
...downloadList,
{
url: downloadUrl,
name: item["relPath"].replace(/^\//gi, ""),
size: Utils.formatByteToSize(item["size"]),
mtime: item["mtime"],
content: "",
},
];
await Utils.sleep(150);
}
if (downloadList.length == 0) {
return;
}
let folderContent = "";
downloadList.sort(
Utils.sortListByProperty((item) => {
return item["mtime"];
})
);
downloadList.forEach((item) => {
folderContent = `${folderContent}
<div class="netdisk-static-body">
<div class="netdisk-static-filename">
<a target="_blank" href="${item["url"]}">${item["name"]}</a>
</div>
<div class="netdisk-static-filesize">${item["size"]}</div>
</div>
`;
});
UI.staticView.moreFile("坚果云多文件直链", folderContent);
},
/**
* 获取下载链接所需要的hash值和name
*/
async getRequestDownloadParams() {
let that = this;
log.info("获取hash值");
Qmsg.info("正在获取请求信息");
let pageInfoRegexp = /var[\s]*PageInfo[\s]*=[\s]*{([\s\S]+)};/i;
let formData = new FormData();
formData.append("pd", this.accessCode);
let requestDetails = {
url: `https://www.jianguoyun.com/p/${this.shareCode}`,
data: this.accessCode == "" ? undefined : `pd=${this.accessCode}`,
responseType: "html",
headers: {
"content-type": "application/x-www-form-urlencoded",
"User-Agent": Utils.getRandomPCUA(),
referer: `https://www.jianguoyun.com/p/${this.shareCode}`,
},
};
let requestResp = null;
if (this.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 &&
(this.accessCode == null || this.accessCode == "")
) {
/* 需要密码但没密码 */
Qmsg.error("密码不正确!");
UI.newAccessCodeView(
"密码缺失",
"jianguoyun",
this.shareCode,
(userInputAccessCode) => {
that.default(that.shareCode, userInputAccessCode);
}
);
return;
}
if (fileErrorCode === "AuthenticationFailed") {
Qmsg.error("密码错误");
UI.newAccessCodeView(
undefined,
"jianguoyun",
this.shareCode,
(userInputAccessCode) => {
that.default(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 {
log.error("获取PageInfo失败");
Qmsg.error("坚果云: 获取PageInfo失败");
return;
}
},
/**
* 获取下载链接
* @param {String} fileHash 文件hash值
* @param {String} fileName 文件名
*/
async getFileLink(fileHash = "", fileName = "") {
fileName = encodeURIComponent(fileName);
let that = this;
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(),
},
});
if (!getResp.status) {
return;
}
let respData = getResp.data;
log.info("请求信息");
log.info(respData);
try {
let resultJSON = JSON.parse(respData.responseText);
log.info(resultJSON);
if (resultJSON.hasOwnProperty("errorCode")) {
Qmsg.error("坚果云: " + resultJSON["detailMsg"]);
return;
} else {
return resultJSON["url"];
}
} catch (error) {
log.error(error);
Qmsg.error("坚果云: 处理下载链接异常");
return;
}
},
/**
* 获取文件夹下的文件下载链接
* @param {String} fileHash
* @param {String} fileName
* @param {String} filePath
* @returns
*/
async getDirLink(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(),
},
});
if (!getResp.status) {
return;
}
let respData = getResp.data;
log.info("请求信息");
log.info(respData);
try {
let resultJSON = JSON.parse(respData.responseText);
log.info(resultJSON);
if (resultJSON.hasOwnProperty("errorCode")) {
Qmsg.error("坚果云: " + resultJSON["detailMsg"]);
return;
} else {
return resultJSON["url"];
}
} catch (error) {
log.error(error);
Qmsg.error("坚果云: 处理下载链接异常");
return;
}
},
async getFolderInfo(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("请求信息");
log.info(respData);
try {
let resultJSON = JSON.parse(respData.responseText);
log.info(resultJSON);
return resultJSON["objects"];
} catch (error) {
log.error(error);
Qmsg.error("坚果云: 处理多文件信息异常");
return;
}
},
},
},
async parse(netdiskName, shareCode, accessCode) {
Qmsg.info("正在获取直链");
await NetDiskLinkParse.netdisk[netdiskName].default(
shareCode,
accessCode
);
},
setClipboard(uiLink, tip) {
/* 复制到剪贴板 */
GM_setClipboard(uiLink);
tip = tip ? tip : "提取码已复制";
Qmsg.success(tip);
},
blank(url, accessCode) {
/* 新标签页打开 */
if (accessCode) {
this.setClipboard(accessCode);
}
document
.querySelector("meta[name='referrer']")
?.setAttribute(
"content",
"no-referrer"
); /* 百度网盘会拒绝referrer不安全访问 */
window.open(url);
},
scheme(netdiskName, shareCode, accessCode) {
let url = NetDisk.regular[netdiskName].blank.replace(
/{#shareCode#}/gi,
shareCode
);
url = filterScheme.handleUrl(
`${netdiskName}-scheme-enable`,
`${netdiskName}-scheme-forward`,
url
);
window.open(url);
},
/**
* 获取重定向后的直链
* @param {String} url
* @param {String} userAgent 用户代理字符串
* @returns
*/
async getRedirectFinalUrl(url, userAgent) {
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;
}
},
};
const filterScheme = {
/* android scheme调用 */
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: "",
handleUrl(enable_key, forward_key, url) {
/* 参数 是否启用的key和转发的scheme和需要转发的url */
if (!GM_getValue(enable_key, false)) {
return url;
}
url = url.replace(/&/g, "{-and-}");
url = url.replace(/#/g, "{-number-}");
let thisScheme = GM_getValue(forward_key, this.defaultScheme);
thisScheme = thisScheme.replace("{#intentData#}", url);
return thisScheme;
},
};
const WorkerHandle = {
blobUrl: "",
GM_matchWorker: null,
/**
* 初始化Worker的Blob链接
*/
initWorkerBlobLink: function () {
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 matchData = pageText.match(link_regexp);
matchData = matchData ? matchData : [];
this.postMessage({
msg: matchData.length
? "workercallback: success! " + matchData.length.toString()
: "workercallback: none",
netdiskName: netdiskName,
data: matchData,
});
},
false
);
})();
`;
var blob = new Blob([handleMatch]);
WorkerHandle.blobUrl = window.URL.createObjectURL(blob);
log.info(`Worker Blobk Link ===> ${WorkerHandle.blobUrl}`);
},
/**
* 初始化Worker对象
*/
initWorker: function () {
WorkerHandle.GM_matchWorker = new Worker(WorkerHandle.blobUrl);
WorkerHandle.GM_matchWorker.onmessage = function (event) {
WorkerHandle.successCallBack(
event.data["data"],
event.data["netdiskName"]
);
};
WorkerHandle.GM_matchWorker.onerror = function (error) {
WorkerHandle.errorCallBack(error);
};
},
/**
* Worker成功回调
* @param {String} matchLink
* @param {String} netdiskName
* @returns
*/
successCallBack: function (matchLink, netdiskName) {
/* worker处理文件匹配后的回调 */
if (matchLink.length === 0 && UI.isHandling) {
setTimeout(() => {
UI.isHandling = false;
/* 延迟赋值-防止页面子元素插入导致闪烁 */
}, parseFloat(GM_getValue("delaytime", 0.8)) * 1000);
return;
}
NetDisk.matchLink.add(netdiskName);
/* 匹配到的可能很多,使用集合去重 */
let matchLinkSet = new Set();
matchLink.forEach((item) => {
matchLinkSet.add(item);
});
Array.from(matchLinkSet).forEach((item) => {
NetDisk.handleLink(netdiskName, item);
});
if (NetDisk.hasMatchLink) {
UI.suspension.show();
}
setTimeout(() => {
UI.isHandling = false;
}, parseFloat(GM_getValue("delaytime", 0.8)) * 1000);
},
/**
* Worker失败回调
* @param {Object} error
*/
errorCallBack: function (error) {
log.error(["Worker Error", error]);
},
};
const UI = {
matchIcon: new Set(),
size: 50 /* 高度和宽度 */,
opacity: 1 /* 按钮透明度 */,
isCreatedUISetting: false /* 已创建设置界面 */,
isHandling: false /* 是否在处理页面链接中标识 */,
uiLinkAlias: null /* 链接层唯一标识 */,
uiSettingAlias: null /* 设置层唯一标识 */,
uiLinkParseAlias: "单文件直链层" /* 单文件直链层唯一标识 */,
uiLinkParseMoreAlias: "多文件直链层" /* 多文件直链层唯一标识 */,
uiPasswordAlias: "重输密码层" /* 重输密码层唯一标识 */,
isRandBg: false /* 是否正在循环切换按钮背景 */,
src: {
/* 图标 */
icon: {
baidu: RESOURCE_ICON.baidu,
lanzou: RESOURCE_ICON.lanzou,
tianyiyun: RESOURCE_ICON.tianyiyun,
hecaiyun: RESOURCE_ICON.hecaiyun,
aliyun: RESOURCE_ICON.aliyun,
wenshushu: RESOURCE_ICON.wenshushu,
nainiu: RESOURCE_ICON.nainiu,
_123pan: RESOURCE_ICON._123pan,
weiyun: RESOURCE_ICON.weiyun,
xunlei: RESOURCE_ICON.xunlei,
_115pan: RESOURCE_ICON._115pan,
chengtong1: RESOURCE_ICON.chengtong,
chengtong2: RESOURCE_ICON.chengtong,
chengtong3: RESOURCE_ICON.chengtong,
kuake: RESOURCE_ICON.kuake,
magnet: RESOURCE_ICON.magnet,
jianguoyun: RESOURCE_ICON.jianguoyun,
} /* icon结尾处 */,
},
suspension: {
/* 悬浮按钮 双击打开主界面,长按打开设置(不能移动,移动就不打开,只是移动按钮) */
isShow: false,
show() {
if (!UI.suspension.isShow) {
this.createUI();
this.initPop();
this.setSuspensionEvent();
this.setSuspensionDefaultPositionEvent();
this.resizeEvent();
UI.suspension.isShow = true;
}
this.randBg();
},
createUI() {
UI.size = GM_getValue("size") ? parseInt(GM_getValue("size")) : 50;
UI.opacity = GM_getValue("opacity")
? parseFloat(GM_getValue("opacity"))
: 1;
if (UI.size < 15) {
GM_setValue("size", 15);
UI.size = 15;
}
if (UI.size > 250) {
GM_setValue("size", 250);
UI.size = 250;
}
if (UI.opacity < 0.1) {
GM_setValue("opacity", 0.1);
UI.opacity = 0.1;
}
if (UI.opacity > 1.0) {
GM_setValue("opacity", 1);
UI.opacity = 1;
}
this.loadCSS();
let _html_ = `
<div class="whitesevSuspension" id="whitesevSuspensionId" style="width:${UI.size}px;height:${UI.size}px;opacity:${UI.opacity}">
<div class="whitesevSuspensionMain">
<div class="whitesevSuspensionFloor">
<div class="netdisk"></div>
</div>
</div>
</div>
`;
let _settingHtml_ = `
<div id="whitesevSuspensionContextMenu" class="whitesevSuspensionContextMenuHide">
<ul>
<li class="whitesevSuspensionSetting">
设置
</li>
</ul>
</div>
`;
$("body").append($(_html_)[0]);
$("body").append($(_settingHtml_)[0]);
},
initPop() {
/* 所有的弹窗初始化设置 */
Qmsg.config({
position: GM_getValue("qmsg-position", "top"),
html: true,
maxNums: parseInt(GM_getValue("qmsg-maxnums", 3)),
autoClose: true,
showClose: false,
showReverse: GM_getValue("qmsg-showreverse", false),
});
GM_addStyle(`
.whitesevPop{
user-select: unset;
}
.whitesevPop .pops-alert-content{
padding: 15px;
}
.whitesevPop-whitesevPopSetting .whitesevPop-buttonSpcl{
display: none;
}
.whitesevPop-whitesevPopSetting .whitesevPop-content{
overflow: auto;
}
.whitesevPopSetting .netdisk-setting-main{
padding: 6px 20px 6px 20px;
}
.whitesevPopSetting details.netdisk-setting-menu {
margin: 10px 0px;
}
.netdisk-setting-menu-item{
display:flex;
justify-content: space-between;
display: flex;
align-items: center;
}
.netdisk-setting-menu-item label{
width:150px;
padding-right: 15px;
}
.netdisk-setting-menu-item[type=checkbox]{
align-items: flex-start;
}
.netdisk-setting-menu-item[type=checkbox],
.netdisk-setting-menu-item[type="scheme"]{
display: flex;
height: 50px;
}
.netdisk-setting-menu-item[type=checkbox] p,
.netdisk-setting-menu-item[type="scheme"] p{
align-self: center;
width: 150px;
}
.netdisk-setting-menu-item input[type=text],
.netdisk-setting-menu-item input[type=number],
.netdisk-setting-menu-item input[type=range]{
border: none;
border-bottom: 1px solid #8f8e8e;
width: 60%;
padding: 0px 2px;
}
.netdisk-setting-menu-item input[type=text]:focus,
.netdisk-setting-menu-item input[type=number]:focus{
outline: none;
border-bottom: 1px solid #2196f3;
}
.netdisk-setting-menu[type='百度'] .netdisk-setting-menu-item,
.netdisk-setting-menu[type='总设置'] .netdisk-setting-menu-item{
margin: 12px 0px;
}
.netdisk-setting-menu[type='总设置'] .netdisk-setting-menu-item{
align-items: center;
display: flex;
justify-content: space-between;
}
.netdisk-setting-menu-item select{
background-color: #fff;
}
/*checkbox美化*/
/* CSS规则保持重复,以便您可以轻松获取每个按钮的CSS规则 :) */
.netdisk-checkbox .knobs,
.netdisk-checkbox .layer{
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
.netdisk-checkbox{
position: relative;
top: 50%;
width: 56px;
height: 28px;
margin: 0px auto 0 auto;
overflow: hidden;
transform: translateY(-50%);
}
.netdisk-checkbox input[type="checkbox"]{
position: relative;
width: 100%;
height: 100%;
padding: 0;
margin: 0;
opacity: 0;
cursor: pointer;
z-index: 3;
}
.netdisk-checkbox .knobs{
z-index: 2;
}
.netdisk-checkbox .layer{
width: 100%;
background-color: #fcebeb;
transition: 0.3s ease all;
z-index: 1;
}
/*
.netdisk-checkbox .knobs:before,
.netdisk-checkbox .knobs span{
position: absolute;
display: inline;
top: 5px;
left: 6px;
width: 20px;
height: 10px;
color: #fff;
font-size: 10px;
font-weight: bold;
text-align: center;
line-height: 1;
padding: 9px 4px;
}
另类写法居中
*/
.netdisk-checkbox .knobs:before,
.netdisk-checkbox .knobs span{
position: relative;
display: block;
top: 50%;
left: 30%;
width: 35%;
height: 65%;
color: #fff;
font-size: 10px;
font-weight: bold;
text-align: center;
line-height: 1;
padding: 9px 4px;
transform: translate(-50%,-50%);
}
.netdisk-checkbox .knobs span{
background-color: #F44336;
border-radius: 2px;
transition: 0.3s ease all, left 0.3s cubic-bezier(0.18, 0.89, 0.35, 1.15);
z-index: 1;
}
.netdisk-checkbox .knobs:before{
transition: 0.3s ease all, left 0.5s cubic-bezier(0.18, 0.89, 0.35, 1.15);
z-index: 2;
}
/*
.netdisk-checkbox .knobs:before{
content: 'N';
display: inline;
top: -2px;
left: -10px;
}
.netdisk-checkbox input[type="checkbox"]:checked + .knobs:before{
content: 'Y';
display: inline;
position: inherit;
top: -2px;
left: 20px;
}
.netdisk-checkbox input[type="checkbox"]:checked + .knobs span{
left: 30px;
background-color: #03A9F4;
}
另类写法居中 */
.netdisk-checkbox input[type="checkbox"]:checked + .knobs span{
left: 70%;
background-color: #03A9F4;
}
.netdisk-checkbox input[type="checkbox"]:checked ~ .layer{
background-color: #ebf7fc;
}
/*range美化*/
.netdisk-setting-menu-item input[type=range] {
background-size: 98% 3px;
background: linear-gradient(to right, #ccc 0%, #ccc 100%);
outline: none;
-webkit-appearance: none;
/*清除系统默认样式*/
height: 1px;
/*横条的高度*/
}
.netdisk-setting-menu-item input[type=range]::-webkit-slider-thumb {
width: 15px;
height: 15px;
border-radius: 50%;
background-color: #fff;
box-shadow: 0 0 2px rgba(0, 0, 0, 0.3), 0 3px 5px rgba(0, 0, 0, 0.2);
cursor: pointer;
-webkit-appearance: none;
border: 0;
}
/* select美化 无法美化option*/
.netdisk-setting-menu-item select{
height: 32px;
line-height: 32px;
font-size: 14px;
width: 200px;
border: 1px solid #5c5c5c;
border-radius: 5px;
text-align: center;
outline: 0;
}
.netdisk-setting-menu-item select:focus{
border: 1px solid #002bff;
}
/* select美化*/
`);
if (!pops.isPhone()) {
GM_addStyle(`
.whitesevPop ::-webkit-scrollbar
{
width: 11px;
height: 16px;
background-color: #ffffff;
}
/*定义滚动条轨道
内阴影+圆角*/
.whitesevPop ::-webkit-scrollbar-track
{
-webkit-box-shadow: inset 0 0 6px rgb(0 0 0 / 25%);
border-radius:10px;
background-color: #f2f2f2;
}
/*定义滑块
内阴影+圆角*/
.whitesevPop ::-webkit-scrollbar-thumb
{
border-radius: 16px;
-webkit-box-shadow:inset 0 0 6px rgba(0,0,0,.3);
background-color: #3597ff;
}
`);
}
},
showSettingView() {
/* 显示设置界面 */
let _settingHtml_ = `
<div class="netdisk-setting-body">
<div class="netdisk-setting">
<div class="netdisk-setting-main">
<details class="netdisk-setting-menu" type="总设置">
<summary>总设置</summary>
<div class="netdisk-setting-menu-item">
<label data-id="netdisk-size">大小 ${GM_getValue("size", 50)}</label>
<input type="range" data-key="size" data-content="大小 " min="15" max="250" data-default="50">
</div>
<div class="netdisk-setting-menu-item">
<label data-id="netdisk-opacity" content="透明度 ">透明度 ${GM_getValue(
"opacity",
1
)}</label>
<input type="range" data-key="opacity" data-content="透明度 " min="0.1" max="1" step="0.1" data-default="1">
</div>
<div class="netdisk-setting-menu-item">
<label data-id="netdisk-randbg-time" content="按钮背景切换时间(毫秒) ">按钮背景切换时间(毫秒) ${GM_getValue(
"randbg-time",
1500
)}</label>
<input type="range" data-key="randbg-time" data-content="按钮背景切换时间(毫秒) " min="0" max="10000" step="100" data-default="1500">
</div>
<div class="netdisk-setting-menu-item">
<label data-id="netdisk-randbg-show-time" content="按钮背景停留时间(毫秒) ">按钮背景停留时间(毫秒) ${GM_getValue(
"randbg-show-time",
1200
)}</label>
<input type="range" data-key="randbg-show-time" data-content="按钮背景停留时间(毫秒) " min="0" max="10000" step="100" data-default="1200">
</div>
<div class="netdisk-setting-menu-item">
<label data-id="netdisk-delaytime">检测延时(秒) ${GM_getValue(
"delaytime",
0.8
)}</label>
<input type="range" data-key="delaytime" data-content="检测延时(秒) " min="0.6" step="0.1" max="5.0" data-default="0.8">
</div>
<div class="netdisk-setting-menu-item">
<label>匹配类型</label>
<select data-key="pageMatchRange" data-default="all">
<option data-value="all">全部</option>
<option data-value="innerText">普通文本</option>
<option data-value="innerHTML">超文本</option>
</select>
</div>
<div class="netdisk-setting-menu-item">
<label>弹窗动画</label>
<select data-key="popsAnimation" data-default="pops-anim-fadein-zoom">
<option data-value="pops-anim-spread">spread</option>
<option data-value="pops-anim-shake">shake</option>
<option data-value="pops-anim-rolling-left">rolling-left</option>
<option data-value="pops-anim-rolling-right">rolling-right</option>
<option data-value="pops-anim-slide-top">slide-top</option>
<option data-value="pops-anim-slide-bottom">slide-bottom</option>
<option data-value="pops-anim-slide-left">slide-left</option>
<option data-value="pops-anim-slide-right">slide-right</option>
<option data-value="pops-anim-fadein">fadein</option>
<option data-value="pops-anim-fadein-zoom">fadein-zoom</option>
<option data-value="pops-anim-fadein-alert">fadein-alert</option>
<option data-value="pops-anim-don">don</option>
<option data-value="pops-anim-roll">roll</option>
<option data-value="pops-anim-sandra">sandra</option>
<option data-value="pops-anim-gather">gather</option>
</select>
</div>
<div class="netdisk-setting-menu-item">
<label>Toast位置</label>
<select data-key="qmsg-position" data-default="top">
<option data-value="topleft">左上角</option>
<option data-value="top">顶部</option>
<option data-value="topright">右上角</option>
<option data-value="left">左边</option>
<option data-value="center">中间</option>
<option data-value="right">右边</option>
<option data-value="bottomleft">左下角</option>
<option data-value="bottom">底部</option>
<option data-value="bottomright">右下角</option>
</select>
</div>
<div class="netdisk-setting-menu-item">
<label>Toast同时显示最多数量</label>
<select data-key="qmsg-maxnums" data-default="3">
<option data-value="1">1</option>
<option data-value="2">2</option>
<option data-value="3">3</option>
<option data-value="4">4</option>
<option data-value="5">5</option>
</select>
</div>
<div class="netdisk-setting-menu-item" type="checkbox">
<p>Toast逆序弹出</p>
<div class="netdisk-checkbox" style="position: inherit;top: unset;transform: matrix(1, 0, 0, 1, 0, 0);">
<input type="checkbox" data-key="qmsg-showreverse">
<div class="knobs"><span></span></div><div class="layer"></div>
</div>
</div>
<div class="netdisk-setting-menu-item" type="checkbox">
<p>读取剪贴板</p>
<div class="netdisk-checkbox" style="position: inherit;top: unset;transform: matrix(1, 0, 0, 1, 0, 0);">
<input type="checkbox" data-key="readClipboard">
<div class="knobs"><span></span></div><div class="layer"></div>
</div>
</div>
<div class="netdisk-setting-menu-item" type="checkbox">
<p>PC端拖拽窗口</p>
<div class="netdisk-checkbox" style="position: inherit;top: unset;transform: matrix(1, 0, 0, 1, 0, 0);">
<input type="checkbox" data-key="pcDrag">
<div class="knobs"><span></span></div><div class="layer"></div>
</div>
</div>
</details>
<details class="netdisk-setting-menu" type="百度">
<summary>百度网盘</summary>
<div class="netdisk-setting-menu-item">
<label>网址-Url</label>
<input type="text" data-key="bdurl" placeholder="如:https://www.example.com/">
</div>
<div class="netdisk-setting-menu-item">
<label>参数-Key</label>
<input type="text" data-key="paramSurl" placeholder="如:surl">
</div>
<div class="netdisk-setting-menu-item">
<label>密码-Key</label>
<input type="text" data-key="paramPwd" placeholder="如:pwd">
</div>
<div class="netdisk-setting-menu-item">
<label>密钥-Key</label>
<input type="text" data-key="paramKey" placeholder="如:Password">
</div>
<div class="netdisk-setting-menu-item">
<label>密钥-Value</label>
<input type="text" data-key="paramWebSiteKey" placeholder="密钥,有就填">
</div>
<div class="netdisk-setting-menu-item" type="checkbox">
<p>网站存在密钥验证</p>
<div class="netdisk-checkbox">
<input type="checkbox" data-key="baidu-website-key-enable">
<div class="knobs"><span></span></div><div class="layer"></div>
</div>
</div>
<div class="netdisk-setting-menu-item" type="checkbox">
<p>启用解析</p>
<div class="netdisk-checkbox">
<input type="checkbox" data-key="baidu-static-enable" mutex=".netdisk-checkbox input[data-key='baidu-open-enable']">
<div class="knobs"><span></span></div><div class="layer"></div>
</div>
</div>
<div class="netdisk-setting-menu-item" type="checkbox">
<p>新标签页打开</p>
<div class="netdisk-checkbox">
<input type="checkbox" data-key="baidu-open-enable" mutex=".netdisk-checkbox input[data-key='baidu-static-enable']">
<div class="knobs"><span></span></div><div class="layer"></div>
</div>
</div>
<div class="netdisk-setting-menu-item">
<label data-id="netdisk-innerText_baidu">提取码间隔(innerText)${GM_getValue(
"innerText_baidu",
20
)}</label>
<input type="range" data-key="innerText_baidu" data-content="提取码间隔(innerText)" min="0" max="100" data-default="20">
</div>
<div class="netdisk-setting-menu-item">
<label data-id="netdisk-innerHTML_baidu">提取码间隔(innerHTML)${GM_getValue(
"innerHTML_baidu",
300
)}</label>
<input type="range" data-key="innerHTML_baidu" data-content="提取码间隔(innerHTML)" min="0" max="500" data-default="300">
</div>
</details>
<details class="netdisk-setting-menu" type="蓝奏云">
<summary>蓝奏云</summary>
<div class="netdisk-setting-menu-item" type="checkbox">
<p>单/多文件直链获取</p>
<div class="netdisk-checkbox">
<input type="checkbox" data-key="lanzou-static-enable" mutex=".netdisk-checkbox input[data-key='lanzou-open-enable']">
<div class="knobs"><span></span></div><div class="layer"></div>
</div>
</div>
<div class="netdisk-setting-menu-item" type="checkbox">
<p>新标签页打开</p>
<div class="netdisk-checkbox">
<input type="checkbox" data-key="lanzou-open-enable" mutex=".netdisk-checkbox input[data-key='lanzou-static-enable']">
<div class="knobs"><span></span></div>
<div class="layer"></div>
</div>
</div>
<div class="netdisk-setting-menu-item" type="checkbox">
<p>直链调用scheme</p>
<div class="netdisk-checkbox">
<input type="checkbox" data-key="lanzou-static-scheme-enable">
<div class="knobs"><span></span></div><div class="layer"></div>
</div>
</div>
<div class="netdisk-setting-menu-item" type="scheme">
<p>scheme转发</p>
<input type="text" data-key="lanzou-static-scheme-forward" placeholder="如: jumpwsv://go?package=xx&activity=xx&intentAction=xx&intentData=xx&intentExtra=xx">
</div>
<div class="netdisk-setting-menu-item">
<label data-id="netdisk-innerText_lanzou">提取码间隔(innerText)${GM_getValue(
"innerText_lanzou",
20
)}</label>
<input type="range" data-key="innerText_lanzou" data-content="提取码间隔(innerText)" min="0" max="100" data-default="20">
</div>
<div class="netdisk-setting-menu-item">
<label data-id="netdisk-innerHTML_lanzou">提取码间隔(innerHTML)${GM_getValue(
"innerHTML_lanzou",
300
)}</label>
<input type="range" data-key="innerHTML_lanzou" data-content="提取码间隔(innerHTML)" min="0" max="500" data-default="300">
</div>
</details>
<details class="netdisk-setting-menu" type="天翼云">
<summary>天翼云</summary>
<div class="netdisk-setting-menu-item" type="checkbox">
<p>单文件直链获取</p>
<div class="netdisk-checkbox">
<input type="checkbox" data-key="tianyiyun-static-enable" mutex=".netdisk-checkbox input[data-key='tianyiyun-open-enable']">
<div class="knobs"><span></span></div><div class="layer"></div>
</div>
</div>
<div class="netdisk-setting-menu-item" type="checkbox">
<p>新标签页打开</p>
<div class="netdisk-checkbox">
<input type="checkbox" data-key="tianyiyun-open-enable" mutex=".netdisk-checkbox input[data-key='tianyiyun-static-enable']">
<div class="knobs"><span></span></div><div class="layer"></div>
</div>
</div>
<div class="netdisk-setting-menu-item" type="checkbox">
<p>直链调用scheme</p>
<div class="netdisk-checkbox">
<input type="checkbox" data-key="tianyiyun-scheme-enable">
<div class="knobs"><span></span></div><div class="layer"></div>
</div>
</div>
<div class="netdisk-setting-menu-item" type="scheme">
<p>scheme转发</p>
<input type="text" data-key="tianyiyun-scheme-forward" placeholder="如: jumpwsv://go?package=xx&activity=xx&intentAction=xx&intentData=xx&intentExtra=xx">
</div>
<div class="netdisk-setting-menu-item">
<label data-id="netdisk-innerText_tianyiyun">提取码间隔(innerText)${GM_getValue(
"innerText_tianyiyun",
20
)}</label>
<input type="range" data-key="innerText_tianyiyun" data-content="提取码间隔(innerText)" min="0" max="100" data-default="20">
</div>
<div class="netdisk-setting-menu-item">
<label data-id="netdisk-innerHTML_tianyiyun">提取码间隔(innerHTML)${GM_getValue(
"innerHTML_tianyiyun",
300
)}</label>
<input type="range" data-key="innerHTML_tianyiyun" data-content="提取码间隔(innerHTML)" min="0" max="500" data-default="300">
</div>
</details>
<details class="netdisk-setting-menu" type="和彩云">
<summary>中国移动云盘(原:和彩云)</summary>
<div class="netdisk-setting-menu-item" type="checkbox">
<p>新标签页打开</p>
<div class="netdisk-checkbox">
<input type="checkbox" data-key="hecaiyun-open-enable">
<div class="knobs"><span></span></div><div class="layer"></div>
</div>
</div>
<div class="netdisk-setting-menu-item">
<label data-id="netdisk-innerText_hecaiyun">提取码间隔(innerText)${GM_getValue(
"innerText_hecaiyun",
20
)}</label>
<input type="range" data-key="innerText_hecaiyun" data-content="提取码间隔(innerText)" min="0" max="100" data-default="20">
</div>
<div class="netdisk-setting-menu-item">
<label data-id="netdisk-innerHTML_hecaiyun">提取码间隔(innerHTML)${GM_getValue(
"innerHTML_hecaiyun",
300
)}</label>
<input type="range" data-key="innerHTML_hecaiyun" data-content="提取码间隔(innerHTML)" min="0" max="500" data-default="300">
</div>
</details>
<details class="netdisk-setting-menu" type="阿里云">
<summary>阿里云</summary>
<div class="netdisk-setting-menu-item" type="checkbox">
<p>新标签页打开</p>
<div class="netdisk-checkbox">
<input type="checkbox" data-key="aliyun-open-enable">
<div class="knobs"><span></span></div><div class="layer"></div>
</div>
</div>
<div class="netdisk-setting-menu-item">
<label data-id="netdisk-innerText_aliyun">提取码间隔(innerText)${GM_getValue(
"innerText_aliyun",
20
)}</label>
<input type="range" data-key="innerText_aliyun" data-content="提取码间隔(innerText)" min="0" max="100" data-default="20">
</div>
<div class="netdisk-setting-menu-item">
<label data-id="netdisk-innerHTML_aliyun">提取码间隔(innerHTML)${GM_getValue(
"innerHTML_aliyun",
300
)}</label>
<input type="range" data-key="innerHTML_aliyun" data-content="提取码间隔(innerHTML)" min="0" max="500" data-default="300">
</div>
</details>
<details class="netdisk-setting-menu" type="文叔叔">
<summary>文叔叔</summary>
<div class="netdisk-setting-menu-item" type="checkbox">
<p>单文件直链获取</p>
<div class="netdisk-checkbox">
<input type="checkbox" data-key="wenshushu-static-enable" mutex=".netdisk-checkbox input[data-key='wenshushu-open-enable']">
<div class="knobs"><span></span></div><div class="layer"></div>
</div>
</div>
<div class="netdisk-setting-menu-item" type="checkbox">
<p>新标签页打开</p>
<div class="netdisk-checkbox">
<input type="checkbox" data-key="wenshushu-open-enable" mutex=".netdisk-checkbox input[data-key='wenshushu-static-enable']">
<div class="knobs"><span></span></div><div class="layer"></div>
</div>
</div>
<div class="netdisk-setting-menu-item" type="checkbox">
<p>直链调用scheme</p>
<div class="netdisk-checkbox">
<input type="checkbox" data-key="wenshushu-static-scheme-enable">
<div class="knobs"><span></span></div><div class="layer"></div>
</div>
</div>
<div class="netdisk-setting-menu-item" type="scheme">
<p>scheme转发</p>
<input type="text" data-key="wenshushu-static-scheme-forward" placeholder="如: jumpwsv://go?package=xx&activity=xx&intentAction=xx&intentData=xx&intentExtra=xx">
</div>
<div class="netdisk-setting-menu-item">
<label data-id="netdisk-innerText_wenshushu">提取码间隔(innerText)${GM_getValue(
"innerText_wenshushu",
20
)}</label>
<input type="range" data-key="innerText_wenshushu" data-content="提取码间隔(innerText)" min="0" max="100" data-default="20">
</div>
<div class="netdisk-setting-menu-item">
<label data-id="netdisk-innerHTML_wenshushu">提取码间隔(innerHTML)${GM_getValue(
"innerHTML_wenshushu",
300
)}</label>
<input type="range" data-key="innerHTML_wenshushu" data-content="提取码间隔(innerHTML)" min="0" max="500" data-default="300">
</div>
</details>
<details class="netdisk-setting-menu" type="奶牛">
<summary>奶牛</summary>
<div class="netdisk-setting-menu-item" type="checkbox">
<p>新标签页打开</p>
<div class="netdisk-checkbox">
<input type="checkbox" data-key="nainiu-open-enable">
<div class="knobs"><span></span></div><div class="layer"></div>
</div>
</div>
<div class="netdisk-setting-menu-item">
<label data-id="netdisk-innerText_nainiu">提取码间隔(innerText)${GM_getValue(
"innerText_nainiu",
20
)}</label>
<input type="range" data-key="innerText_nainiu" data-content="提取码间隔(innerText)" min="0" max="100" data-default="20">
</div>
<div class="netdisk-setting-menu-item">
<label data-id="netdisk-innerHTML_nainiu">提取码间隔(innerHTML)${GM_getValue(
"innerHTML_nainiu",
300
)}</label>
<input type="range" data-key="innerHTML_nainiu" data-content="提取码间隔(innerHTML)" min="0" max="500" data-default="300">
</div>
</details>
<details class="netdisk-setting-menu" type="123盘">
<summary>123盘</summary>
<div class="netdisk-setting-menu-item" type="checkbox">
<p>单/多文件直链获取</p>
<div class="netdisk-checkbox">
<input type="checkbox" data-key="_123pan-static-enable" mutex=".netdisk-checkbox input[data-key='_123pan-open-enable']">
<div class="knobs"><span></span></div><div class="layer"></div>
</div>
</div>
<div class="netdisk-setting-menu-item" type="checkbox">
<p>新标签页打开</p>
<div class="netdisk-checkbox">
<input type="checkbox" data-key="_123pan-open-enable" mutex=".netdisk-checkbox input[data-key='_123pan-static-enable']">
<div class="knobs"><span></span></div><div class="layer"></div>
</div>
</div>
<div class="netdisk-setting-menu-item" type="checkbox">
<p>直链调用scheme</p>
<div class="netdisk-checkbox">
<input type="checkbox" data-key="_123pan-static-scheme-enable">
<div class="knobs"><span></span></div><div class="layer"></div>
</div>
</div>
<div class="netdisk-setting-menu-item" type="scheme">
<p>scheme转发</p>
<input type="text" data-key="_123pan-static-scheme-forward" placeholder="如: jumpwsv://go?package=xx&activity=xx&intentAction=xx&intentData=xx&intentExtra=xx">
</div>
<div class="netdisk-setting-menu-item">
<label data-id="netdisk-innerText__123pan">提取码间隔(innerText)${GM_getValue(
"innerText__123pan",
20
)}</label>
<input type="range" data-key="innerText__123pan" data-content="提取码间隔(innerText)" min="0" max="100" data-default="20">
</div>
<div class="netdisk-setting-menu-item">
<label data-id="netdisk-innerHTML__123pan">提取码间隔(innerHTML)${GM_getValue(
"innerHTML__123pan",
300
)}</label>
<input type="range" data-key="innerHTML__123pan" data-content="提取码间隔(innerHTML)" min="0" max="500" data-default="300">
</div>
</details>
<details class="netdisk-setting-menu" type="微云">
<summary>微云</summary>
<div class="netdisk-setting-menu-item" type="checkbox">
<p>新标签页打开</p>
<div class="netdisk-checkbox">
<input type="checkbox" data-key="weiyun-open-enable">
<div class="knobs"><span></span></div><div class="layer"></div>
</div>
</div>
<div class="netdisk-setting-menu-item">
<label data-id="netdisk-innerText_weiyun">提取码间隔(innerText)${GM_getValue(
"innerText_weiyun",
20
)}</label>
<input type="range" data-key="innerText_weiyun" data-content="提取码间隔(innerText)" min="0" max="100" data-default="20">
</div>
<div class="netdisk-setting-menu-item">
<label data-id="netdisk-innerHTML_weiyun">提取码间隔(innerHTML)${GM_getValue(
"innerHTML_weiyun",
300
)}</label>
<input type="range" data-key="innerHTML_weiyun" data-content="提取码间隔(innerHTML)" min="0" max="500" data-default="300">
</div>
</details>
<details class="netdisk-setting-menu" type="迅雷云盘">
<summary>迅雷云盘</summary>
<div class="netdisk-setting-menu-item" type="checkbox">
<p>新标签页打开</p>
<div class="netdisk-checkbox">
<input type="checkbox" data-key="xunlei-open-enable">
<div class="knobs"><span></span></div><div class="layer"></div>
</div>
</div>
<div class="netdisk-setting-menu-item">
<label data-id="netdisk-innerText_xunlei">提取码间隔(innerText)${GM_getValue(
"innerText_xunlei",
20
)}</label>
<input type="range" data-key="innerText_xunlei" data-content="提取码间隔(innerText)" min="0" max="100" data-default="20">
</div>
<div class="netdisk-setting-menu-item">
<label data-id="netdisk-innerHTML_xunlei">提取码间隔(innerHTML)${GM_getValue(
"innerHTML_xunlei",
300
)}</label>
<input type="range" data-key="innerHTML_xunlei" data-content="提取码间隔(innerHTML)" min="0" max="500" data-default="300">
</div>
</details>
<details class="netdisk-setting-menu" type="115盘">
<summary>115盘</summary>
<div class="netdisk-setting-menu-item" type="checkbox">
<p>新标签页打开</p>
<div class="netdisk-checkbox">
<input type="checkbox" data-key="_115pan-open-enable">
<div class="knobs"><span></span></div><div class="layer"></div>
</div>
</div>
<div class="netdisk-setting-menu-item">
<label data-id="netdisk-innerText__115pan">提取码间隔(innerText)${GM_getValue(
"innerText__115pan",
20
)}</label>
<input type="range" data-key="innerText__115pan" data-content="提取码间隔(innerText)" min="0" max="100" data-default="20">
</div>
<div class="netdisk-setting-menu-item">
<label data-id="netdisk-innerHTML__115pan">提取码间隔(innerHTML)${GM_getValue(
"innerHTML__115pan",
300
)}</label>
<input type="range" data-key="innerHTML__115pan" data-content="提取码间隔(innerHTML)" min="0" max="500" data-default="300">
</div>
</details>
<details class="netdisk-setting-menu" type="城通网盘1">
<summary>城通网盘1</summary>
<div class="netdisk-setting-menu-item" type="checkbox">
<p>新标签页打开</p>
<div class="netdisk-checkbox">
<input type="checkbox" data-key="chengtong1-open-enable">
<div class="knobs"><span></span></div><div class="layer"></div>
</div>
</div>
<div class="netdisk-setting-menu-item">
<label data-id="netdisk-innerText__chengtong1">提取码间隔(innerText)${GM_getValue(
"innerText__chengtong1",
20
)}</label>
<input type="range" data-key="innerText__chengtong1" data-content="提取码间隔(innerText)" min="0" max="100" data-default="20">
</div>
<div class="netdisk-setting-menu-item">
<label data-id="netdisk-innerHTML__chengtong1">提取码间隔(innerHTML)${GM_getValue(
"innerHTML__chengtong1",
300
)}</label>
<input type="range" data-key="innerHTML__chengtong1" data-content="提取码间隔(innerHTML)" min="0" max="500" data-default="300">
</div>
</details>
<details class="netdisk-setting-menu" type="城通网盘2">
<summary>城通网盘2</summary>
<div class="netdisk-setting-menu-item" type="checkbox">
<p>新标签页打开</p>
<div class="netdisk-checkbox">
<input type="checkbox" data-key="chengtong2-open-enable">
<div class="knobs"><span></span></div><div class="layer"></div>
</div>
</div>
<div class="netdisk-setting-menu-item">
<label data-id="netdisk-innerText__chengtong2">提取码间隔(innerText)${GM_getValue(
"innerText__chengtong2",
20
)}</label>
<input type="range" data-key="innerText__chengtong2" data-content="提取码间隔(innerText)" min="0" max="100" data-default="20">
</div>
<div class="netdisk-setting-menu-item">
<label data-id="netdisk-innerHTML__chengtong2">提取码间隔(innerHTML)${GM_getValue(
"innerHTML__chengtong2",
300
)}</label>
<input type="range" data-key="innerHTML__chengtong2" data-content="提取码间隔(innerHTML)" min="0" max="500" data-default="300">
</div>
</details>
<details class="netdisk-setting-menu" type="城通网盘3">
<summary>城通网盘3</summary>
<div class="netdisk-setting-menu-item" type="checkbox">
<p>新标签页打开</p>
<div class="netdisk-checkbox">
<input type="checkbox" data-key="chengtong3-open-enable">
<div class="knobs"><span></span></div><div class="layer"></div>
</div>
</div>
<div class="netdisk-setting-menu-item">
<label data-id="netdisk-innerText__chengtong3">提取码间隔(innerText)${GM_getValue(
"innerText__chengtong3",
20
)}</label>
<input type="range" data-key="innerText__chengtong3" data-content="提取码间隔(innerText)" min="0" max="100" data-default="20">
</div>
<div class="netdisk-setting-menu-item">
<label data-id="netdisk-innerHTML__chengtong3">提取码间隔(innerHTML)${GM_getValue(
"innerHTML__chengtong3",
300
)}</label>
<input type="range" data-key="innerHTML__chengtong3" data-content="提取码间隔(innerHTML)" min="0" max="500" data-default="300">
</div>
</details>
<details class="netdisk-setting-menu" type="夸克网盘">
<summary>夸克网盘</summary>
<div class="netdisk-setting-menu-item" type="checkbox">
<p>新标签页打开</p>
<div class="netdisk-checkbox">
<input type="checkbox" data-key="kuake-open-enable">
<div class="knobs"><span></span></div><div class="layer"></div>
</div>
</div>
<div class="netdisk-setting-menu-item">
<label data-id="netdisk-innerText_kuake">提取码间隔(innerText)${GM_getValue(
"innerText_kuake",
20
)}</label>
<input type="range" data-key="innerText_kuake" data-content="提取码间隔(innerText)" min="0" max="100" data-default="20">
</div>
<div class="netdisk-setting-menu-item">
<label data-id="netdisk-innerHTML_kuake">提取码间隔(innerHTML)${GM_getValue(
"innerHTML_kuake",
300
)}</label>
<input type="range" data-key="innerHTML_kuake" data-content="提取码间隔(innerHTML)" min="0" max="500" data-default="300">
</div>
</details>
<details class="netdisk-setting-menu" type="磁力magnet">
<summary>磁力magnet</summary>
<div class="netdisk-setting-menu-item" type="checkbox">
<p>调用scheme</p>
<div class="netdisk-checkbox">
<input type="checkbox" data-key="magnet-scheme-enable">
<div class="knobs"><span></span></div><div class="layer"></div>
</div>
</div>
<div class="netdisk-setting-menu-item" type="scheme">
<p>scheme转发</p>
<input type="text" data-key="magnet-scheme-forward" placeholder="如: jumpwsv://go?package=xx&activity=xx&intentAction=xx&intentData=xx&intentExtra=xx">
</div>
</details>
<details class="netdisk-setting-menu" type="坚果云">
<summary>坚果云</summary>
<div class="netdisk-setting-menu-item" type="checkbox">
<p>单文件直链获取</p>
<div class="netdisk-checkbox">
<input type="checkbox" data-key="jianguoyun-static-enable" mutex=".netdisk-checkbox input[data-key='jianguoyun-open-enable']">
<div class="knobs"><span></span></div><div class="layer"></div>
</div>
</div>
<div class="netdisk-setting-menu-item" type="checkbox">
<p>新标签页打开</p>
<div class="netdisk-checkbox">
<input type="checkbox" data-key="jianguoyun-open-enable" mutex=".netdisk-checkbox input[data-key='jianguoyun-static-enable']">
<div class="knobs"><span></span></div><div class="layer"></div>
</div>
</div>
<div class="netdisk-setting-menu-item" type="checkbox">
<p>直链调用scheme</p>
<div class="netdisk-checkbox">
<input type="checkbox" data-key="jianguoyun-static-scheme-enable">
<div class="knobs"><span></span></div><div class="layer"></div>
</div>
</div>
<div class="netdisk-setting-menu-item" type="scheme">
<p>scheme转发</p>
<input type="text" data-key="jianguoyun-static-scheme-forward" placeholder="如: jumpwsv://go?package=xx&activity=xx&intentAction=xx&intentData=xx&intentExtra=xx">
</div>
<div class="netdisk-setting-menu-item">
<label data-id="netdisk-innerText_jianguoyun">提取码间隔(innerText)${GM_getValue(
"innerText_jianguoyun",
20
)}</label>
<input type="range" data-key="innerText_jianguoyun" data-content="提取码间隔(innerText)" min="0" max="100" data-default="20">
</div>
<div class="netdisk-setting-menu-item">
<label data-id="netdisk-innerHTML_jianguoyun">提取码间隔(innerHTML)${GM_getValue(
"innerHTML_jianguoyun",
300
)}</label>
<input type="range" data-key="innerHTML_jianguoyun" data-content="提取码间隔(innerHTML)" min="0" max="500" data-default="300">
</div>
</details>
</div>
</div>
</div>
`;
UI.uiSettingAlias = pops.alert({
title: {
text: "设置",
position: "center",
},
content: {
text: _settingHtml_,
html: true,
},
btn: {
ok: {
enable: true,
callback: function (event) {
event.close();
},
},
close: {
callback: function (event) {
event.close();
},
},
},
animation: GM_getValue("popsAnimation", "pops-anim-fadein-zoom"),
class: "whitesevPopSetting",
height: "350px",
width: pops.isPhone() ? "350px" : "500px",
drag: GM_getValue("pcDrag", false),
mask: true,
});
function setSettingInputEvent() {
/* 设置复选框是否选中 */
$(".netdisk-setting input").each((index, item) => {
let data_key = item.getAttribute("data-key");
let data_default = item.getAttribute("data-default");
item.value = GM_getValue(data_key, data_default)
? GM_getValue(data_key, data_default)
: "";
switch (item.getAttribute("type")) {
case "checkbox":
item.checked = GM_getValue(data_key) ? true : false;
let mutex = item.getAttribute("mutex");
$(item).on("click", function (event) {
if (mutex) {
let mutexElement = $(mutex);
let mutex_data_key = $(mutex).attr("data-key");
if (item.checked) {
mutexElement.prop("checked", !item.checked);
GM_setValue(mutex_data_key, !item.checked);
}
}
GM_setValue(data_key, item.checked);
});
break;
case "range":
$(item).on("input propertychange", (val) => {
$(`.netdisk-setting label[data-id=netdisk-${data_key}]`).html(
`${item.getAttribute("data-content")}${item.value}`
);
let itSize = $(".netdisk-setting input[data-key=size]").val();
$("#whitesevSuspensionId").css({
width: `${itSize}px`,
height: `${itSize}px`,
opacity: $(
".netdisk-setting input[data-key=opacity]"
).val(),
});
UI.size = itSize;
UI.suspension.setSuspensionDefaultPositionEvent();
GM_setValue(data_key, item.value);
});
default:
$(item).on("input propertychange", (val) => {
GM_setValue(data_key, item.value);
});
}
});
}
function setSettingSelectEvent() {
/* 设置下拉列表的默认值 */
$(".netdisk-setting select").change(function (event) {
let data_key = event.target.getAttribute("data-key");
let data_value =
event.target[event.target.selectedIndex].getAttribute(
"data-value"
);
GM_setValue(data_key, data_value);
});
$(".netdisk-setting-menu-item select").each((index, item) => {
item = $(item);
let dataKey = item.attr("data-key");
let dataDefaultValue = item.attr("data-default");
let getDataValue = GM_getValue(dataKey, dataDefaultValue);
item
.find(`option[data-value=${getDataValue}]`)
.attr("selected", true);
});
}
function setSettingLabelEvent() {
/* 设置点击Label设置range为默认值 */
$(UI.uiSettingAlias.popsElement)
.find("label[data-id*=netdisk-]")
.on("click", function () {
let obj = $(this);
let dataKey = obj.next().attr("data-key");
let dataDefaultValue = obj.next().attr("data-default");
let currentValue = obj.next().val();
pops.confirm({
mask: true,
title: {
text: "提示",
position: "center",
},
content: {
text: `当前设置的值为:${currentValue},是否修改为默认值:${dataDefaultValue} ?`,
},
btn: {
ok: {
callback: function (_event_) {
log.info(
`当前 ==> ${currentValue},默认值 ==> ${dataDefaultValue}`
);
GM_setValue(dataKey, dataDefaultValue);
obj.next().val(dataDefaultValue);
obj.next().trigger("propertychange");
_event_.close();
},
},
},
});
});
$(UI.uiSettingAlias.popsElement)
.find("label[data-id*=netdisk-]")
.each((index, item) => {
$(item).css("cursor", "pointer");
});
}
setSettingInputEvent();
setSettingSelectEvent();
setSettingLabelEvent();
},
setSuspensionEvent() {
/* 设置悬浮按钮事件 */
let needDragEle = document.getElementById("whitesevSuspensionId");
let that = this;
let dragNode = new AnyTouch(needDragEle);
let timerID = null;
let isClicked = false;
let isDouble = false;
let click_deviation_x = 0; /* 点击元素,距离元素左上角的X轴偏移 */
let click_deviation_y = 0; /* 点击元素,距离元素左上角的Y轴偏移 */
dragNode.on("pan", function (event) {
if (!isClicked) {
isClicked = true;
click_deviation_x = event.nativeEvent.offsetX
? parseInt(event.nativeEvent.offsetX)
: parseInt(event.getOffset().x);
click_deviation_y = event.nativeEvent.offsetY
? parseInt(event.nativeEvent.offsetY)
: parseInt(event.getOffset().y);
$("#whitesevSuspensionId").css({
cursor: "move",
transition: "none",
});
}
if (event.phase == "move") {
if (click_deviation_x > 250 || click_deviation_y > 250) {
return;
}
var maxL = $(window).width() - UI.size;
var maxT = $(window).height() - UI.size;
var x = event.x - click_deviation_x;
var y = event.y - click_deviation_y;
x = x < maxL ? x : maxL;
y = y < maxT ? y : maxT;
x = x < 0 ? 0 : x;
y = y < 0 ? 0 : y;
if (top.window == self.window) {
GM_setValue("suspensionX", x);
GM_setValue("suspensionY", y);
}
$("#whitesevSuspensionId").css({
left: x,
top: y,
});
}
if (event.phase == "end") {
isClicked = false;
$("#whitesevSuspensionId").css("cursor", "auto");
let left_px = parseInt(
$("#whitesevSuspensionId").css("left").replace("px", "")
);
let setCSSLeft = 0;
if (left_px >= $(window).width() / 2) {
setCSSLeft = $(window).width() - UI.size;
if (top.window == self.window) {
GM_setValue("isRight", true);
}
} else {
if (top.window == self.window) {
GM_setValue("isRight", false);
}
}
if (top.window == self.window) {
GM_setValue("suspensionX", setCSSLeft);
}
$("#whitesevSuspensionId").css({
left: setCSSLeft,
transition: "left 300ms ease 0s",
});
}
});
dragNode.on(["click", "tap"], function (event) {
if (isDouble) {
/* 双 */
clearTimeout(timerID);
timerID = setTimeout(function () {
isDouble = false;
that.showSettingView();
}, 300);
} else {
isDouble = true;
timerID = setTimeout(function () {
isDouble = false;
UI.view.show();
}, 300);
}
});
$(window).on("click", function (event) {
let targetId = event.target.id;
let targetClassName = event.target.className;
if (targetId != "whitesevSuspensionContextMenu") {
$("#whitesevSuspensionContextMenu").addClass(
"whitesevSuspensionContextMenuHide"
);
}
if (targetClassName == "whitesevSuspensionSetting") {
log.info("打开设置界面");
that.showSettingView();
}
});
$("#whitesevSuspensionId").on("contextmenu", function (event) {
event.preventDefault();
let settingEle = $("#whitesevSuspensionContextMenu");
var maxL1 = $(window).width() - UI.size;
var maxT1 = $(window).height() - UI.size;
var x1 = event.clientX;
var y1 = event.clientY;
/* 不允许超出浏览器范围 */
x1 = x1 < 0 ? 0 : x1;
x1 = x1 < maxL1 ? x1 : maxL1;
y1 = y1 < 0 ? 0 : y1;
y1 = y1 < maxT1 ? y1 : maxT1;
settingEle.removeClass("whitesevSuspensionContextMenuHide");
settingEle.css({
left: x1,
top: y1,
});
});
},
setSuspensionDefaultPositionEvent() {
/* 设置悬浮按钮位置 */
let maxY = $(window).height() - UI.size;
let defaultX = $(window).width() - UI.size;
let defaultY = $(window).height() / 2 - UI.size;
let setX = GM_getValue("suspensionX", defaultX);
let setY = GM_getValue("suspensionY", defaultY);
setX = GM_getValue("isRight") ? defaultX : 0;
setY = setY < maxY ? setY : maxY; /* 超出高度那肯定是最底下了 */
setY = setY < 0 ? 0 : setY;
if (top.window == self.window) {
GM_setValue("suspensionX", setX);
GM_setValue("suspensionY", setY);
}
$("#whitesevSuspensionId").css({
left: setX,
top: setY,
});
},
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);
}
#whitesevSuspensionContextMenu{
position: fixed;
z-index: 10000;
width: 50px;
text-align: center;
padding: 3px 0px;
border-radius: 3px;
font-size: 13px;
font-weight: 500;
background:#fff;
}
#whitesevSuspensionContextMenu:hover{
background: #dfdfdf;
}
.whitesevSuspensionContextMenuHide{
display: none;
}
.whitesevPop-content p[pop]{
height: 100%;
}
`);
},
resizeEvent() {
/* 界面大小改变 */
$(window).resize(() => {
this.setSuspensionDefaultPositionEvent();
});
},
randBg() {
/* 悬浮按钮背景轮播淡入淡出 */
if (this.isRandBg) {
return;
}
let currentList = [];
let currentIndex = 0;
let switchBgTime = 1500; /* 淡入或淡出的持续时间 */
let switchBgShowTime = 1200; /* 淡入或淡出后的延迟切换时间 */
currentList = getRandBgList();
let randBgSrc = currentList[currentIndex];
let randBgNode = $(".whitesevSuspension .netdisk");
randBgNode.css("background-image", `url(${randBgSrc})`);
if (
currentList.length < 2 ||
GM_getValue("randbg-time", switchBgTime) <= 0
) {
return;
}
this.isRandBg = true;
function getRandBgList() {
let _result_list_ = [];
UI.matchIcon.forEach((item) => {
_result_list_ = [..._result_list_, UI.src.icon[item]];
});
return _result_list_;
}
function _show_(_time_, _bg_src_) {
currentList = getRandBgList();
randBgNode.fadeOut(_time_, function () {
currentIndex++;
currentIndex = currentIndex < currentList.length ? currentIndex : 0;
_bg_src_ = currentList[currentIndex];
randBgNode.css("background-image", `url(${_bg_src_})`);
randBgNode.fadeIn(_time_, function () {
setTimeout(() => {
_show_(
parseInt(GM_getValue("randbg-time", switchBgTime)),
_bg_src_
);
}, parseInt(GM_getValue("randbg-show-time", switchBgShowTime)));
});
});
}
_show_(parseInt(GM_getValue("randbg-time", switchBgTime)), randBgSrc);
},
},
view: {
/* 主界面 */
show() {
if (!UI.uiLinkAlias) {
this.addCSS();
this.createView();
this.registerIconGotoPagePosition();
} else {
UI.uiLinkAlias.show();
}
},
addCSS() {
GM_addStyle(`
.netdisk-url-box-all{
}
.netdisk-url-box{
}
.netdisk-url-box:last-child {
padding: 0 0 10px 0;
}
.netdisk-url-div{
display: flex;
align-items: center;
width: 100%;
margin: 10px 0px;
}
.netdisk-icon{
margin: 0px 4px;
display: contents;
}
.netdisk-icon img{
width: 28px;
height: 28px;
font-size: 13px !important;
}
.netdisk-icon img,
.netdisk-url a{
border-radius: 10px;
box-shadow: 0 0.3px 0.6px rgb(0 0 0 / 6%), 0 0.7px 1.3px rgb(0 0 0 / 8%), 0 1.3px 2.5px rgb(0 0 0 / 10%), 0 2.2px 4.5px rgb(0 0 0 / 12%), 0 4.2px 8.4px rgb(0 0 0 / 14%), 0 10px 20px rgb(0 0 0 / 20%);
}
.whitesevPop .netdisk-url{
padding: 5px 0px;
margin: 0px 10px;
}
.netdisk-url a{
color: #ff4848 !important;
min-height: 28px;
overflow-x: hidden;
overflow-y: auto;
font-size: 14px;
border: none;
display: flex;
align-items: center;
width: 100%;
height: 100%;
padding: 2px 10px;
word-break: break-word;
}
.whitesevPop-whitesevPopSetting *:focus-visible {
outline-offset: 0px;
outline:0px;
}
.netdisk-url a[isvisited=true]{
color: #8b8888 !important;
}
.whitesevPop-content p[pop]{
text-indent: 0px;
}
.whitesevPop-button[type="primary"] {
border-color: #2d8cf0;
background-color: #2d8cf0;
}
`);
},
createView() {
let viewAddHTML = "";
UI.matchIcon.forEach((netDiskName) => {
let netDisk = NetDisk.linkDict.get(netDiskName);
$.each(netDisk.getItems(), (shareCode, accessCode) => {
let uiLink = NetDisk.handleLinkShow(
netDiskName,
shareCode,
accessCode
);
viewAddHTML =
viewAddHTML +
this.getViewHTML(
UI.src.icon[netDiskName],
netDiskName,
shareCode,
accessCode,
uiLink
);
});
});
let viewHTML = `
<div class="netdisk-url-box-all">
${viewAddHTML}
</div>`;
UI.uiLinkAlias = pops.alert({
title: {
text: "网盘",
position: "center",
},
content: {
text: viewHTML,
html: true,
},
btn: {
ok: {
callback: function (event) {
event.hide();
},
},
close: {
callback: function (event) {
event.hide();
},
},
},
class: "whitesevPop",
animation: GM_getValue("popsAnimation", "pops-anim-fadein-zoom"),
width: pops.isPhone() ? "350px" : "500px",
drag: GM_getValue("pcDrag", false),
mask: true,
height: "350px",
});
this.setNetDiskUrlClickEvent();
},
getViewHTML(
_netdiskicon_,
_netdiskname_,
_sharecode_,
_accesscode_,
_uilink_
) {
return `
<div class="netdisk-url-box">
<div class="netdisk-url-div">
<div class="netdisk-icon">
<img src="${_netdiskicon_}">
</div>
<div class="netdisk-url">
<a href="javascript:;" isvisited="false" data-netdisk="${_netdiskname_}" 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">${_uilink_}</a>
</div>
</div>
</div>
`;
},
setNetDiskUrlClickEvent() {
/* 设置网盘链接点击事件 */
function clickEvent(clickElement) {
clickElement.target.setAttribute("isvisited", "true");
let netdiskName = clickElement.target.getAttribute("data-netdisk");
let shareCode = clickElement.target.getAttribute("data-sharecode");
let accessCode = clickElement.target.getAttribute("data-accesscode");
let openEnable = GM_getValue(
clickElement.target.getAttribute("data-open-enable-key"),
false
);
let staticEnable = GM_getValue(
clickElement.target.getAttribute("data-static-enable-key"),
false
);
let schemeEnable = GM_getValue(
clickElement.target.getAttribute("data-scheme-enable-key"),
false
);
if (openEnable) {
let url = NetDisk.regular[netdiskName].blank.replace(
/{#shareCode#}/gi,
shareCode
);
url = url.replace(/{#accessCode#}/gi, accessCode);
NetDiskLinkParse.blank(url, accessCode);
} else if (staticEnable) {
NetDiskLinkParse.parse(netdiskName, shareCode, accessCode);
} else if (schemeEnable) {
NetDiskLinkParse.scheme(netdiskName, shareCode, accessCode);
} else {
NetDiskLinkParse.setClipboard(
clickElement.target.outerText,
"已复制"
);
}
}
$("body").on("click", ".netdisk-url a", clickEvent);
},
addLinkView(_netdiskname_, _sharecode_, _accesscode_) {
/* 添加新的链接 */
if (!UI.uiLinkAlias) {
return null;
}
log.info([_netdiskname_, _sharecode_, _accesscode_]);
let icon = UI.src.icon[_netdiskname_];
let uiLink = NetDisk.handleLinkShow(
_netdiskname_,
_sharecode_,
_accesscode_
);
let insertDOM = this.getViewHTML(
icon,
_netdiskname_,
_sharecode_,
_accesscode_,
uiLink
);
let parentDOM = $(
UI.uiLinkAlias.popsElement.querySelector(".netdisk-url-box-all")
);
parentDOM.append(insertDOM);
},
changeLinkView(_netdiskname_, _sharecode_, _accesscode_) {
/* 修改已存在的view */
if (!UI.uiLinkAlias) {
return null;
}
let uiLink = NetDisk.handleLinkShow(
_netdiskname_,
_sharecode_,
_accesscode_
);
let needChangeDOM = $(
UI.uiLinkAlias.popsElement.querySelector(
`.netdisk-url a[data-sharecode='${_sharecode_}']`
)
);
log.info(["修改链接视图", needChangeDOM]);
needChangeDOM.attr("data-accesscode", _accesscode_);
needChangeDOM.html(uiLink);
},
registerIconGotoPagePosition() {
/* 设置点击图标按钮导航至该网盘链接所在网页中位置 */
$(document).on(
"click",
".whitesevPop .netdisk-icon img",
function (event) {
let dataSharecode =
event.target.parentElement.nextElementSibling.firstElementChild.getAttribute(
"data-sharecode"
);
Utils.findWindowPageString(dataSharecode, true);
}
);
},
},
staticView: {
/* 直链弹窗 */
isLoadCSS: false,
addCSS() {
if (!this.isLoadCSS) {
this.isLoadCSS = true;
GM_addStyle(`
.netdisk-static-body{
flex-wrap: wrap;
letter-spacing: 1px;
text-decoration: none;
width: 100%;
padding: 5px 16px;
text-align: left;
}
.netdisk-static-filename{
}
.netdisk-static-filename a{
color: #233df8 !important;
}
.netdisk-static-body .netdisk-static-filename:before{
content: "文件: ";
font-weight: bold;
text-overflow: ellipsis;
display: contents;
position: inherit;
}
.netdisk-static-filesize{
}
.netdisk-static-body .netdisk-static-filesize:before{
content: "大小: ";
font-weight: bold;
display: contents;
position: inherit;
}
`);
}
},
oneFile(title, fileName, fileSize, downloadUrl) {
this.addCSS();
Qmsg.success("成功获取直链");
pops.confirm({
title: {
text: title,
position: "center",
},
content: {
text: `<div class="netdisk-static-body"><div class="netdisk-static-filename"><a target="_blank" href="${downloadUrl}">${fileName}</a></div><div class="netdisk-static-filesize">${fileSize}</div></div>`,
html: true,
},
btn: {
reverse: true,
position: "end",
ok: {
text: "下载",
callback: (event) => {
window.open(
event.popsElement
.querySelector(".netdisk-static-filename a")
.getAttribute("href"),
"_blank"
);
},
},
},
class: "whitesevPopOneFile",
height: "180px",
animation: GM_getValue("popsAnimation", "pops-anim-fadein-zoom"),
width: pops.isPhone() ? "300px" : "400px",
mask: true,
drag: GM_getValue("pcDrag", false),
});
},
moreFile(_title_, _content_) {
this.addCSS();
Qmsg.success("成功获取多文件直链");
pops.alert({
title: {
text: _title_,
position: "center",
},
content: {
text: _content_,
html: true,
},
btn: {
ok: {
text: "关闭",
},
},
class: "whitesevPopMoreFile",
mask: true,
height: "400px",
animation: GM_getValue("popsAnimation", "pops-anim-fadein-zoom"),
width: pops.isPhone() ? "300px" : "400px",
drag: GM_getValue("pcDrag", false),
});
},
},
newAccessCodeView(
title = "密码错误",
netDiskName = "",
shareCode,
okCallBack = () => {}
) {
/* 需要重新输入新密码的弹窗 */
pops.prompt({
title: {
text: "密码缺失",
},
btn: {
reverse: true,
position: "end",
cancel: {
text: "取消",
},
ok: {
callback: (event) => {
/* 把输入的新密码去空格 */
let userInputAccessCode = event.text.replace(/ /g, "");
/* 处理已显示的链接 */
let uiLink = NetDisk.handleLinkShow(
netDiskName,
shareCode,
userInputAccessCode
);
$(
`.netdisk-url a[data-netdisk=${netDiskName}][data-sharecode=${shareCode}]`
).attr("data-accesscode", userInputAccessCode);
$(
`.netdisk-url a[data-netdisk=${netDiskName}][data-sharecode=${shareCode}]`
).html(uiLink);
log.info(`${netDiskName} 重新输入的密码:${userInputAccessCode}`);
okCallBack(userInputAccessCode);
event.close();
},
},
},
content: {
placeholder: "请重新输入密码",
focus: true,
},
width: "350px",
height: "160px",
mask: true,
animation: GM_getValue("popsAnimation", "pops-anim-fadein-zoom"),
drag: GM_getValue("pcDrag", false),
});
Utils.listenKeyPress(
document.querySelector(".pops-prompt-content input"),
(keyName, otherKey) => {
if (keyName === "Enter") {
document.querySelector(".pops-prompt-btn-ok")?.click();
}
}
);
},
monitorDOMInsert() {
WorkerHandle.initWorkerBlobLink();
WorkerHandle.initWorker();
Utils.mutationObserver(document.body, {
callback: async (mutations) => {
if (UI.isHandling) {
/* 当前正在处理文本正则匹配中 */
return null;
}
UI.isHandling = true;
var retStatus = false;
$.each(mutations, (index, item) => {
if (
item?.target?.className?.match(/whitesevPop|netdisk-url-box/gi)
) {
retStatus = true;
return null;
}
});
if (retStatus) {
/* 排除弹窗内部元素 */
return null;
}
let clipboardText = "";
if (GM_getValue("readClipboard", false)) {
clipboardText = await NetDisk.getClipboardText();
}
NetDisk.matchPageLink(clipboardText);
},
config: {
/* 子节点的变动(新增、删除或者更改) */
childList: true,
/* 属性的变动 */
attributes: true,
/* 节点内容或节点文本的变动 */
characterData: true,
/* 是否将观察器应用于该节点的所有后代节点 */
subtree: true,
},
});
NetDisk.matchPageLink(); /* 自执行一次,因为有的页面上没触发mutationObserver */
},
};
var GM_Menu = new Utils.GM_Menu(
{
showSetting: {
text: "打开设置界面",
enable: false,
showText: (_text_, _enable_) => {
return `⚙ ${_text_}`;
},
callback: () => {
UI.suspension.initPop();
UI.suspension.showSettingView();
},
},
},
false,
GM_getValue,
GM_setValue,
GM_registerMenuCommand,
GM_unregisterMenuCommand
);
$(document).ready(function () {
UI.monitorDOMInsert();
});
})();