网盘链接识别

识别网页中显示的网盘链接,目前包括百度网盘、蓝奏云、天翼云、中国移动云盘(原:和彩云)、阿里云、文叔叔、奶牛快传、123盘、腾讯微云、迅雷网盘、115网盘、夸克网盘、城通网盘(部分)、坚果云、UC网盘、BT磁力,支持蓝奏云、天翼云(需登录)、123盘、奶牛、UC网盘(需登录)、坚果云(需登录)和阿里云盘(需登录,且限制在网盘页面解析)直链获取下载,页面动态监控加载的链接,可自定义规则来识别小众网盘/网赚网盘或其它自定义的链接。

当前为 2024-08-14 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         网盘链接识别
// @namespace    https://greasyfork.org/zh-CN/scripts/445489
// @supportURL   https://github.com/WhiteSevs/TamperMonkeyScript/issues
// @icon         data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAAAXNSR0IArs4c6QAACsJJREFUeF7tXW+IHdUVP2c2u8kHIQYL0TRIaK1SgrFFaZsvVkpAo6YR1LJpa9jUd++83SUpSrUNBFRCrVgxNOv+mTOvJBBNmtpamoQG9UNBKLHFDzEtFttKBdOYQENE/Lb75vZd2cVNum/uvXNnZt/MnoGQD+/c8+d3fu+c+2f2PgR+ljQCuKSj5+CBCbDEScAEYAIscQSWePhcAZgASxyBJR4+VwAmQHEIjIyM3DAzM/M1pdSXEfEWALgVANbkaPE0ABwhomdz1GmtSgixHxF3Wg8wC55HxPeVUu8DgP7/jRUrVvxpbGzsY/PQbBK5VwCd9Ha7vVkptRkA9L8yHiKisAxDczaklL8GgAfLsImIryql3gSAqBPnh3nazI0AjUZjbRAEjwLAI3k6aKtLKbUjjuODtvI+cs1m894kSY776Mg49hwAxHkSIRcCSCl10nXy12YMLI9hrxDR/XkoMukQQrQQ8WGTXIGfn0PEZ6IoGvO14U0AKeUJALjH15Ecxr9ARHn2464uCSEOI+K2HHz2VXGUiAZ9lHgRQEp5BgBu9nEgr7FBEGyZmprSZCz8EUIMIuKRwg3ZGfiAiK63E/1/qcwEkFJ+BAArsxrOedzLRPSdnHWmqgvD8EBntj5Ups0UWxeI6NosvmQigBDibUTckMVgAWNKXwHMxSClfBwAtgPA+gLiclX5GhHd6TrImQBhGO5RSu11MHQREY8nSXICEf/R399/bnx8/KLD+CUl2plf3BgEwa1JktyOiN8HgKscAHCuhE4EaDabQ0mSHLBxSCml5weHlFKHWq3WBZsxLHM5AlLKLwLAQwCwCwBWWeLzKBHts5S1fx9ASnkdALxluZPXIiJh6wTLpSMwPDx8U7vd/iEADFtgdTZJko2tVuushawTAZ4EgCdMSpVSW+M4PmaS48/dEZBSWuWgMznfR0R6X8b4WLUA228/Ig5GUXTUaJUFMiMghNiEiK+bFCxbtuxLExMT/zLJ2RLAhnmTRDRiMsif+yMQhuFupdTTaZoQcZfNTqEVAYQQf0TEO1IMXurr69s4OTn5rn94rMEGAYul+Ekiutuky0iAoaGhqwcGBi4ZFD1FRLpK8FMSAkKIHyHiz9PM2bQBIwGklPcBwO9SDH0CAF8hovdKip3NAECj0VgdBMHf05aHSqntcRwfSm0VJjSllD8DgJ90k1NKTcVxbLM8MZnizx0RkFL+BgC6noAi4nNRFD3mSwB96NH1xKnMc3hHfGovbnEoZdweNraAMAxPKaW+0Q1NRFwfRdE7tUe7BwOUUuqTWL3j2u0xHhIZCSCl1K8gdT1pIiKjjh7ErhYujY6OXjM9Pf3ftGBM+TEmT0qpfAzUAukeDsI3P0yAHk6ujWtMABuUaizDBKhxcm1CYwLYoFRjGSZAjZNrExoTwAalGsswAWqcXJvQmAA2KNVYhglQ4+TahMYEsEGpxjK1IYCU8vcAcJvlW8dVTqn+C9+3iGhrHkHUggCmIPIAqhd1mA5qbHw2YWeysehnAWVetGADaMkyzn/Jc6V/dSDAeQBYXTLwvWLOeF5vcrQOBEg9bjYBUPXPTSXaFB8TwIRQj3/OBDC8cNLj+fN2r+oEOE1EX/VBwVTCfHRXYWzBBDDmx7gKMNyF92PfO/pMBPAFKO9Zsyupio7PNz9GAuiAuyzVcrmZo2iA6k4A3/xYEUAb0Xfjtdvt+xBxlVLqeF538jEB8nmrOmt+rAngWvps5ZkA+RDAFu8r5XqBAP9J2f8/R0SfzxrcQuMWgXClxueKVS8QQB8CfbuL48fyOjSZ078IBCg1vsoRYHYSs+BuYN4rgDRbc8CVabMIW5UkwLyZ7O2zAbxR1MWPZVeAeZVH3y5eeHyVJYCr41nlF4sAWf0tetyizwGKDnCx9wHKjs/VHhPgCsR6oS+7JtFHngnABPDhT/XG8hzg8pxxBeAKUL1vsY/HXAG4AvCNJ/M4wC2AW4BPQa3eWG4B3AK4BXAL6F65eCOoelXdyWNuAdwCuAVwC+AWMIcALwN5GejUQisvzHMAngPwHIDnADwH4DlAFw7wPkDlu3x6ADwHyDgHCMPwLqXUJgCYDoLgpampqb9VkSt1JUDW/FgtA6WUvwSAH1yR8Bc7vxSmf9i4Uk8dCeCTHyMBDL8a9j0iOlwlBtSNAL75sSGA/v1Z/TPmCz3/JqIvMAEWDwEppVd+bAhQq3VzDSuAV36YABXfCvYlNBOACbC01s2+35jF6/YLW/aNhysAVwCuAPMRqNpWMFcAx5rsC5ijucLFfePhFsAtgFsAt4AUDviWmMJroKMBjsfxNJABc2RYyeK++VmKc4CevrfPlT9MAEfEZn+cqrR7CR3dcxZnAjhD9unl16XdS5jBPachTAAnuD4Tnr0Bvefu7XMNhwngiljN5JkANUuoazhMAFfEaia/6ATo7+//3Pj4+MWa4VqZcAwEOE9E16UFY7MPkLZu1ro3ENFfK4NYjRwVQtyIiO92CwkR34yiaKMvAY4BwJZuSpRSD8Rx/Nsa4VqZUMIw3KaUSnsr+1dEtM2LAEKIvYi4J4VlB6Mo2lEZ1GrkqBBiEhGbKSE9Q0S7vQggpfwuALyUouRikiTrW63WhRph2/OhSCn1q/qnAeCqlOp8dxzHJ70IMDIycsPMzMw/05QopR6L4/i5nketRg5KKZ8EgCfSQlq+fPnKsbGxj70IoAdLKf8AAJtTmHYmjuNbaoRvT4cyPDx8U7vdPgUAq1Ja86tRFN1lCsS4CtAKwjDcqZTab1DWIiJhMsif+yMgpZwAgGGDpqeISFeJ1MeKADZtQFtRSm2N41ivGvgpCAGb0t8p2ucA4DYi+tDkhhUBZtvA8wDwiFEh4mAURUdNcvy5OwJCiE2I+LrFSKtvv9ZjTYBGo7E2CALdd9ZaODDZ19f3i8nJya6bFBY6WGQeAmEY7lZKPW0BivW334kAs1VAVwBdCWyeSwCg5w2HOvcIvGczgGUuR6DRaKxGRH0Hw0OIuMEGH0TcFUXRmI2sMwFmSXACAO6xNQAAnyilXuysIv4cBMFfoih6x2HskhIdHR29Znp6eo1Saj0iPgAA30qb6S8AzlEiGnQBzboFzFcqpTwDADe7GCpIVm+EHCGiZwvSn6pWCLEfEXcuhu0FbH5ARNe7+pKJALOV4CMAWOlqsCB56sx4w4J0L6h29o2iB8u0mWLrAhFdm8WXzATQxoQQb9v2pizOuYxRSu2I4/igy5isss1m894kSY5nHZ/zuNeI6M6sOr0IoI2GYbhHKbU3qwM5jnulcyx9f476uqoSQrQQ8eEybBlsvOz7G8veBNAONpvNoSRJfgoAaxYRlBeIqJR+3DmHP9w5h089Zi0Yh7N6NUZE+3zt5EKA2TmBfvNE92G9HVw6EYIg2DI1NaVXKIU/QohBRDxSuKGFDexLkuT5VqulSeD95EaAOU+klJ8SQSn1TUS8w9tDOwXepdDOzGdSYRgeUEoNuY7LKH8SEU/29fWdnJiY0LeC5fbkToD5ng0NDV09MDCgSfB1AFiHiOuUUusAINOMtUvUpa8A5pH9cQDYDgDrc8sIgH6vQk+uzyRJcqa/v/9U3kmf72uhBMgRFFZVEAJMgIKArYpaJkBVMlWQn0yAgoCtilomQFUyVZCfTICCgK2KWiZAVTJVkJ9MgIKArYra/wGYigzMiqJYZwAAAABJRU5ErkJggg==
// @version      2024.8.14
// @description  识别网页中显示的网盘链接,目前包括百度网盘、蓝奏云、天翼云、中国移动云盘(原:和彩云)、阿里云、文叔叔、奶牛快传、123盘、腾讯微云、迅雷网盘、115网盘、夸克网盘、城通网盘(部分)、坚果云、UC网盘、BT磁力,支持蓝奏云、天翼云(需登录)、123盘、奶牛、UC网盘(需登录)、坚果云(需登录)和阿里云盘(需登录,且限制在网盘页面解析)直链获取下载,页面动态监控加载的链接,可自定义规则来识别小众网盘/网赚网盘或其它自定义的链接。
// @author       WhiteSevs
// @match        *://*/*
// @run-at       document-end
// @license      GPL-3.0-only
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_xmlhttpRequest
// @grant        GM_download
// @grant        GM_addStyle
// @grant        GM_info
// @grant        GM_registerMenuCommand
// @grant        GM_unregisterMenuCommand
// @grant        unsafeWindow
// @connect      *
// @connect      lanzoub.com
// @connect      lanzouc.com
// @connect      lanzoue.com
// @connect      lanzouf.com
// @connect      lanzoug.com
// @connect      lanzouh.com
// @connect      lanzoui.com
// @connect      lanzouj.com
// @connect      lanzouk.com
// @connect      lanzoul.com
// @connect      lanzoum.com
// @connect      lanzouo.com
// @connect      lanzoup.com
// @connect      lanzouq.com
// @connect      lanzous.com
// @connect      lanzout.com
// @connect      lanzouu.com
// @connect      lanzouv.com
// @connect      lanzouw.com
// @connect      lanzoux.com
// @connect      lanzouy.com
// @connect      lanosso.com
// @connect      lanzn.com
// @connect      lanzog.com
// @connect      lanpw.com
// @connect      lanpv.com
// @connect      lanzv.com
// @connect      wwentua.com
// @connect      ilanzou.com
// @connect      189.cn
// @connect      123pan.com
// @connect      123pan.cn
// @connect      wenshushu.cn
// @connect      jianguoyun.com
// @connect      cowtransfer.com
// @connect      cowcs.com
// @connect      aliyundrive.com
// @connect      baidu.com
// @connect      139.com
// @connect      weiyun.com
// @connect      xunlei.com
// @connect      115.com
// @connect      quark.cn
// @connect      jianguoyun.com
// @connect      uc.cn
// @connect      ctfile.com
// @connect      sharepoint.com
// @exclude      /^http(s|):\/\/s1\.hdslb\.com\/.*$/
// @exclude      /^http(s|):\/\/www\.bilibili\.com\/video.*$/
// @exclude      /^http(s|):\/\/message\.bilibili\.com\/.*$/
// @exclude      /^http(s|):\/\/live\.bilibili\.com\/.*$/
// @exclude      /^http(s|):\/\/.*\.mail\.qq\.com\/.*$/
// @exclude      /^http(s|):\/\/.*video\.qq\.com\/.*$/
// @exclude      /^http(s|):\/\/.*\.vscode-cdn\.net\/.*$/
// @exclude      /^http(s|):\/\/.*vscode\.dev\/.*$/
// @exclude      /^http(s|):\/\/cloudgame\.ds\.163\.com\/.*$/
// @exclude      /^http(s|):\/\/cloudgame\.webapp\.163\.com\/.*$/
// @exclude      /^http(s|):\/\/cg\.163\.com\/.*$/
// @exclude      /^http(s|):\/\/.*\.youtube\.com\/.*$/
// @require      https://update.greasyfork.org/scripts/456470/1320377/%E7%BD%91%E7%9B%98%E9%93%BE%E6%8E%A5%E8%AF%86%E5%88%AB-%E5%9B%BE%E6%A0%87%E5%BA%93.js
// @require      https://update.greasyfork.org/scripts/465550/1360573/JS-%E5%88%86%E9%A1%B5%E6%8F%92%E4%BB%B6.js
// @require      https://fastly.jsdelivr.net/npm/[email protected]/dist/index.umd.js
// @require      https://fastly.jsdelivr.net/npm/@whitesev/[email protected]/dist/index.umd.js
// @require      https://fastly.jsdelivr.net/npm/@whitesev/[email protected]/dist/index.umd.js
// @require      https://fastly.jsdelivr.net/npm/@whitesev/[email protected]/dist/index.umd.js
// @require      https://update.greasyfork.org/scripts/486152/1360580/Crypto-JS.js
// ==/UserScript==

(function () {
	if (typeof unsafeWindow === "undefined") {
		var unsafeWindow =
			globalThis.unsafeWindow ||
			window.unsafeWindow ||
			globalThis ||
			window ||
			self;
	}
	/** 是否是调试模式 */
	const isDebug = true;
	/** @type {import("lib/CryptoJS/index")} */
	const Cryptojs = CryptoJS ?? window.CryptoJS ?? unsafeWindow.CryptoJS;
	/** @type {import("qmsg").default} */
	const Qmsg = window.Qmsg;
	/** @type {import("@whitesev/pops").default} */
	const pops = window.pops;
	const AnyTouch = pops.config.Utils.AnyTouch();
	/** @type {import("@whitesev/utils").default} */
	const utils = window.Utils.noConflict();
	/** @type {import("@whitesev/domutils").default} */
	const DOMUtils = window.DOMUtils.noConflict();
	const log = new utils.Log(GM_info, unsafeWindow.console || console);
	const httpx = new utils.Httpx(GM_xmlhttpRequest);
	const GM_Menu = new utils.GM_Menu({
		autoReload: false,
		GM_getValue,
		GM_setValue,
		GM_registerMenuCommand,
		GM_unregisterMenuCommand,
	});

	/**
	 * 数据配置
	 */
	const NetDiskData = {
		/** 蓝奏云默认主机域名 */
		lanzou_defaultHostName: "www.lanzout.com",
		/** 是否点击网盘小图标寻找shareCode */
		iconDefaultClickEventToFindShareCode: true,
		/** 是否点击网盘小图标寻找shareCode且使用光标选中 */
		iconDefaultClickEventToFindShareCodeWithSelect: true,
		/** 是否点击网盘小图标(循环)寻找shareCode */
		iconDefaultClickEventToFindShareCodeByLoop: true,
		/** 匹配间隔默认时间(s) */
		defaultMatchIntervalTime: 0.8,
		/** 匹配间隔最小时间(s) */
		matchIntervalMinTime: 0.0,
		/** 匹配间隔最打时间(s) */
		matchIntervalMaxTime: 5.0,

		/** 小窗的默认值-宽度 */
		defaultSmallWindowWidth: 250,
		/** 小窗的最小值-宽度 */
		smallWindowMinWidth: 50,
		/** 小窗的最大值-宽度 */
		smallWindowMaxWidth: DOMUtils.width(globalThis),

		/** 小窗的默认值-最大高度 */
		defaultSmallWindowMaxHeight: 200,
		/** 小窗的最小值-最大高度 */
		smallWindowMinMaxHeight: 50,
		/** 小窗的最大值-最大高度 */
		smallWindowMaxMaxHeight: DOMUtils.height(globalThis),

		/** 相同字符系数-默认值 */
		defaultExcludeIdenticalSharedCodesCoefficient: 1,
		/** 相同字符系数-最小值 */
		excludeIdenticalSharedCodesCoefficientMin: 0,
		/** 相同字符系数-最大值 */
		excludeIdenticalSharedCodesCoefficientMax: 1,

		/** 行为模式-默认值:悬浮按钮+小窗 */
		defaultNetdiskBehaviorMode: "suspension_smallwindow",

		/** 子节点的变动(新增、删除或者更改) */
		default_mutationObserver_childList: true,
		/** 节点内容或节点文本的变动 */
		default_mutationObserver_characterData: true,
		/** 是否将观察器应用于该节点的所有后代节点 */
		default_mutationObserver_subtree: true,
	};

	const NetDiskUIMenuData = {
		/**
		 * @returns {string}
		 */
		get netdiskBehaviorMode() {
			return GM_getValue(
				"netdisk-behavior-mode",
				NetDiskData.defaultNetdiskBehaviorMode
			).toLowerCase();
		},
	};

	const NetDiskLocalData = {
		/**
		 * 是否启用该规则
		 * @param {string} name
		 * @param {boolean} defaultValue
		 * @returns
		 */
		enable(name, defaultValue = true) {
			return Boolean(GM_getValue(`${name}-enable`, defaultValue));
		},
		/**
		 * 提取码间隔前的字符长度
		 * @param {string} name
		 * @param {number} defaultValue 默认值: 20
		 */
		innerTextAccessCodeBeforeMaxRange(name, defaultValue = 20) {
			return parseInt(
				GM_getValue(
					`${name}_innerText_accessCode_before_max_range`,
					defaultValue
				)
			);
		},
		/**
		 * 提取码间隔后的字符长度
		 * @param {string} name
		 * @param {number} defaultValue 默认值: 10
		 */
		innerTextAccessCodeAfterMaxRange(name, defaultValue = 10) {
			return parseInt(
				GM_getValue(
					`${name}_innerText_accessCode_after_max_range`,
					defaultValue
				)
			);
		},
		/**
		 * 提取码间隔前的字符长度
		 * @param {string} name
		 * @param {number} defaultValue 默认值: 100
		 */
		innerHTMLAccessCodeBeforeMaxRange(name, defaultValue = 100) {
			return parseInt(
				GM_getValue(
					`${name}_innerHTML_accessCode_before_max_range`,
					defaultValue
				)
			);
		},
		/**
		 * 提取码间隔后的字符长度
		 * @param {string} name
		 * @param {number} defaultValue 默认值: 15
		 */
		innerHTMLAccessCodeAfterMaxRange(name, defaultValue = 15) {
			return parseInt(
				GM_getValue(
					`${name}_innerHTML_accessCode_after_max_range`,
					defaultValue
				)
			);
		},
		/**
		 * 是否进行校验链接有效性
		 * @param {string} name
		 * @param {boolean} [defaultValue=false]
		 * @returns
		 */
		checkLinkValidity(name, defaultValue = false) {
			return Boolean(GM_getValue(`${name}-check-link-valid`, defaultValue));
		},
	};

	const NetDisk = {
		/**
		 * 是否初始化
		 * @type {boolean}
		 */
		isInit: false,
		/**
		 * 链接字典,识别规则->识别到的访问码|分享码|下标
		 * @type {import("@whitesev/utils/dist/src/Dictionary").UtilsDictionary<string,import("@whitesev/utils/dist/src/Dictionary").UtilsDictionary<string,NetDiskDictData>>}
		 */
		linkDict: void 0,
		/**
		 * (临时)链接字典
		 * @type {import("@whitesev/utils/dist/src/Dictionary").UtilsDictionary<string,import("@whitesev/utils/dist/src/Dictionary").UtilsDictionary<string,NetiDiskHandleObject>>}
		 */
		tempLinkDict: void 0,
		/**
		 * 是否正在匹配链接中
		 */
		isMatching: false,
		/**
		 * 用于存储已匹配到的网盘规则名
		 * 只有单独的名
		 * @type {Set<string>}
		 */
		matchLink: void 0,
		/**
		 * 是否成功匹配到链接
		 */
		hasMatchLink: false,
		/**
		 * 剪贴板内容
		 */
		clipboardText: "",
		/**
		 * 是否允许匹配window.location.href
		 */
		allowMatchLocationHref: false,
		/**
		 * 使用该正则判断提取到的shareCode是否正确
		 */
		shareCodeNotMatchRegexpList: [
			/(vipstyle|notexist|ajax|file|download|ptqrshow|xy-privacy|comp|web|undefined|1125|unproved|console|account|favicon|setc)/g,
		],
		/**
		 * 使用该正则判断提取到的accessCode是否正确
		 */
		accessCodeNotMatchRegexpList: [/^(font)/gi],
		/**
		 * 当没有accessCode时,使用该正则去除不需要的字符串
		 */
		noAccessCodeRegExp:
			/( |提取码:|\n密码:{#accessCode#}|{#accessCode#}|{#encodeURI-accessCode#}|{#encodeURIComponent-accessCode#}|{#decodeURI-accessCode#}|{#encodeURIComponent-accessCode#}|\?pwd=|&pwd=)/gi,
		/**
		 * @type {NetDiskRegular}
		 */
		regular: {
			baidu: [
				{
					enable: NetDiskLocalData.enable("baidu"),
					link_innerText: `pan.baidu.com/s/[0-9a-zA-Z-_]{6,24}([\\s\\S]{0,${NetDiskLocalData.innerTextAccessCodeBeforeMaxRange(
						"baidu"
					)}}(密码|访问码|提取码|\\?pwd=)[\\s\\S]{0,${NetDiskLocalData.innerTextAccessCodeAfterMaxRange(
						"baidu"
					)}}[0-9a-zA-Z]{4}|)`,
					link_innerHTML: `pan.baidu.com/s/[0-9a-zA-Z-_]{6,24}([\\s\\S]{0,${NetDiskLocalData.innerHTMLAccessCodeBeforeMaxRange(
						"baidu"
					)}}(密码|访问码|提取码|\\?pwd=)[\\s\\S]{0,${NetDiskLocalData.innerHTMLAccessCodeAfterMaxRange(
						"baidu"
					)}}[0-9a-zA-Z]{4}|)`,
					shareCode: /pan\.baidu\.com\/s\/([0-9a-zA-Z-_]+)/gi,
					shareCodeNeedRemoveStr: /pan\.baidu\.com\/s\//gi,
					checkAccessCode: /(密码|访问码|提取码|pwd=)[\s\S]+/g,
					accessCode: /([0-9a-zA-Z]{4})/gi,
					uiLinkShow: "pan.baidu.com/s/{#shareCode#}?pwd={#accessCode#}",
					blank: "https://pan.baidu.com/s/{#shareCode#}?pwd={#accessCode#}",
					copyUrl: "https://pan.baidu.com/s/{#shareCode#}?pwd={#accessCode#}",
					checkLinkValidity: NetDiskLocalData.checkLinkValidity("baidu"),
				},
				{
					enable: NetDiskLocalData.enable("baidu"),
					link_innerText: `pan.baidu.com/(share|wap)/init\\?surl=[0-9a-zA-Z-_]{5,24}([\\s\\S]{0,${NetDiskLocalData.innerTextAccessCodeBeforeMaxRange(
						"baidu"
					)}}(密码|访问码|提取码|&pwd=)[\\s\\S]{0,${NetDiskLocalData.innerTextAccessCodeAfterMaxRange(
						"baidu"
					)}}[0-9a-zA-Z]{4}|)`,
					link_innerHTML: `pan.baidu.com/(share|wap)/init\\?surl=[0-9a-zA-Z-_]{5,24}([\\s\\S]{0,${NetDiskLocalData.innerHTMLAccessCodeBeforeMaxRange(
						"baidu"
					)}}(密码|访问码|提取码|&pwd=)[\\s\\S]{0,${NetDiskLocalData.innerHTMLAccessCodeAfterMaxRange(
						"baidu"
					)}}[0-9a-zA-Z]{4}|)`,
					shareCode:
						/pan\.baidu\.com\/(share|wap)\/init\?surl=([0-9a-zA-Z-_]+)/gi,
					shareCodeNeedRemoveStr: /pan\.baidu\.com\/(share|wap)\/init\?surl=/gi,
					checkAccessCode: /(密码|访问码|提取码|&pwd=)[\s\S]+/g,
					accessCode: /([0-9a-zA-Z]{4})/gi,
					uiLinkShow:
						"pan.baidu.com/share/init?surl={#shareCode#}&pwd={#accessCode#}",
					blank:
						"https://pan.baidu.com/share/init?surl={#shareCode#}&pwd={#accessCode#}",
					copyUrl:
						"https://pan.baidu.com/share/init?surl={#shareCode#}&pwd={#accessCode#}",
					checkLinkValidity: NetDiskLocalData.checkLinkValidity("baidu"),
				},
			],
			lanzou: [
				{
					enable: NetDiskLocalData.enable("lanzou"),
					link_innerText: `(lanzou[a-z]{0,1}|lan[a-z]{2}).com/(tp/|u/|)([a-zA-Z0-9_-]{5,22}|[%0-9a-zA-Z]{4,90}|[\\u4e00-\\u9fa5]{1,20})([\\s\\S]{0,${NetDiskLocalData.innerTextAccessCodeBeforeMaxRange(
						"lanzou"
					)}}(密码|访问码|提取码)[\\s\\S]{0,${NetDiskLocalData.innerTextAccessCodeAfterMaxRange(
						"lanzou"
					)}}[a-zA-Z0-9]{3,6}|)`,
					link_innerHTML: `(lanzou[a-z]{0,1}|lan[a-z]{2}).com/(tp/|u/|)([a-zA-Z0-9_-]{5,22}|[%0-9a-zA-Z]{4,90}|[\\u4e00-\\u9fa5]{1,20})([\\s\\S]{0,${NetDiskLocalData.innerHTMLAccessCodeBeforeMaxRange(
						"lanzou"
					)}}(密码|访问码|提取码)[\\s\\S]{0,${NetDiskLocalData.innerHTMLAccessCodeAfterMaxRange(
						"lanzou"
					)}}[a-zA-Z0-9]{3,6}|)`,
					shareCode:
						/(lanzou[a-z]{0,1}|lan[a-z]{2}).com\/(tp\/|u\/|)([a-zA-Z0-9_\-]{5,22}|[%0-9a-zA-Z]{4,90}|[\u4e00-\u9fa5]{1,20})/gi,
					shareCodeNeedRemoveStr:
						/(lanzou[a-z]{0,1}|lan[a-z]{2}).com\/(tp\/|u\/|)/gi,
					shareCodeExcludeRegular: ["lanzouyx"],
					checkAccessCode: /(密码|访问码|提取码)[\s\S]+/g,
					accessCode: /([0-9a-zA-Z]{3,})/gi,
					uiLinkShow: `${GM_getValue(
						"lanzou-host-name",
						NetDiskData.lanzou_defaultHostName
					)}/{#shareCode#} 提取码: {#accessCode#}`,
					blank: `https://${GM_getValue(
						"lanzou-host-name",
						NetDiskData.lanzou_defaultHostName
					)}/{#shareCode#}`,
					copyUrl: `https://${GM_getValue(
						"lanzou-host-name",
						NetDiskData.lanzou_defaultHostName
					)}/{#shareCode#}\n密码:{#accessCode#}`,
					checkLinkValidity: NetDiskLocalData.checkLinkValidity("lanzou"),
				},
				{
					enable: NetDiskLocalData.enable("lanzou"),
					link_innerText: `(lanzou[a-z]{0,1}|lan[a-z]{2}).com/s/([a-zA-Z0-9_-]{5,22}|[%0-9a-zA-Z]{4,90}|[\\u4e00-\\u9fa5]{1,20})([\\s\\S]{0,${NetDiskLocalData.innerTextAccessCodeBeforeMaxRange(
						"lanzou"
					)}}(密码|访问码|提取码)[\\s\\S]{0,${NetDiskLocalData.innerTextAccessCodeAfterMaxRange(
						"lanzou"
					)}}[a-zA-Z0-9]{3,6}|)`,
					link_innerHTML: `(lanzou[a-z]{0,1}|lan[a-z]{2}).com/s/([a-zA-Z0-9_-]{5,22}|[%0-9a-zA-Z]{4,90}|[\\u4e00-\\u9fa5]{1,20})([\\s\\S]{0,${NetDiskLocalData.innerHTMLAccessCodeBeforeMaxRange(
						"lanzou"
					)}}(密码|访问码|提取码)[\\s\\S]{0,${NetDiskLocalData.innerHTMLAccessCodeAfterMaxRange(
						"lanzou"
					)}}[a-zA-Z0-9]{3,6}|)`,
					shareCode:
						/(lanzou[a-z]{0,1}|lan[a-z]{2}).com\/s\/([a-zA-Z0-9_\-]{5,22}|[%0-9a-zA-Z]{4,90}|[\u4e00-\u9fa5]{1,20})/gi,
					shareCodeNeedRemoveStr: /(lanzou[a-z]{0,1}|lan[a-z]{2}).com\/s\//gi,
					shareCodeExcludeRegular: ["lanzouyx"],
					checkAccessCode: /(密码|访问码|提取码)[\s\S]+/g,
					accessCode: /([0-9a-zA-Z]{3,})/gi,
					uiLinkShow: `${GM_getValue(
						"lanzou-host-name",
						NetDiskData.lanzou_defaultHostName
					)}/s/{#shareCode#} 提取码: {#accessCode#}`,
					blank: `https://${GM_getValue(
						"lanzou-host-name",
						NetDiskData.lanzou_defaultHostName
					)}/s/{#shareCode#}`,
					copyUrl: `https://${GM_getValue(
						"lanzou-host-name",
						NetDiskData.lanzou_defaultHostName
					)}/s/{#shareCode#}\n密码:{#accessCode#}`,
					checkLinkValidity: NetDiskLocalData.checkLinkValidity("lanzou"),
				},
			],
			lanzouyx: [
				{
					enable: NetDiskLocalData.enable("lanzouyx"),
					link_innerText: `ilanzou.com/s/([a-zA-Z0-9_-]{5,22})([\\s\\S]{0,${NetDiskLocalData.innerTextAccessCodeBeforeMaxRange(
						"lanzouyx"
					)}}(密码|访问码|提取码|\\?code=)[\\s\\S]{0,${NetDiskLocalData.innerTextAccessCodeAfterMaxRange(
						"lanzouyx"
					)}}[a-zA-Z0-9]{3,6}|)`,
					link_innerHTML: `ilanzou.com/s/([a-zA-Z0-9_-]{5,22})([\\s\\S]{0,${NetDiskLocalData.innerHTMLAccessCodeBeforeMaxRange(
						"lanzouyx"
					)}}(密码|访问码|提取码|\\?code=)[\\s\\S]{0,${NetDiskLocalData.innerHTMLAccessCodeAfterMaxRange(
						"lanzouyx"
					)}}[a-zA-Z0-9]{3,6}|)`,
					shareCode: /ilanzou.com\/s\/([a-zA-Z0-9_\-]{5,22})/gi,
					shareCodeNeedRemoveStr: /ilanzou.com\/s\//gi,
					checkAccessCode: /(密码|访问码|提取码|\?code=)[\s\S]+/g,
					accessCode: /([0-9a-zA-Z]{3,})/gi,
					uiLinkShow: `www.ilanzou.com/s/{#shareCode#} 提取码: {#accessCode#}`,
					blank: `https://www.ilanzou.com/s/{#shareCode#}?code={#accessCode#}`,
					copyUrl: `https://www.ilanzou.com/s/{#shareCode#}?code={#accessCode#}`,
					checkLinkValidity: NetDiskLocalData.checkLinkValidity("lanzouyx"),
				},
			],
			tianyiyun: [
				{
					enable: NetDiskLocalData.enable("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,${NetDiskLocalData.innerTextAccessCodeBeforeMaxRange(
						"tianyiyun"
					)}}(密码|访问码|提取码)[\\s\\S]{0,${NetDiskLocalData.innerTextAccessCodeAfterMaxRange(
						"tianyiyun"
					)}}[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,${NetDiskLocalData.innerHTMLAccessCodeBeforeMaxRange(
						"tianyiyun"
					)}}(密码|访问码|提取码)[\\s\\S]{0,${NetDiskLocalData.innerHTMLAccessCodeAfterMaxRange(
						"tianyiyun"
					)}}[0-9a-zA-Z]{4}|)`,
					shareCode:
						/cloud.189.cn\/web\/share\?code=([0-9a-zA-Z_\-]){8,14}|cloud.189.cn\/t\/([a-zA-Z0-9_\-]{8,14})/gi,
					shareCodeNeedRemoveStr:
						/cloud\.189\.cn\/t\/|cloud.189.cn\/web\/share\?code=/gi,
					checkAccessCode: /(密码|访问码|提取码)[\s\S]+/g,
					accessCode: /([0-9a-zA-Z]{4})/gi,
					uiLinkShow: "cloud.189.cn/t/{#shareCode#} 提取码: {#accessCode#}",
					blank: "https://cloud.189.cn/t/{#shareCode#}",
					copyUrl: "https://cloud.189.cn/t/{#shareCode#}\n密码:{#accessCode#}",
					checkLinkValidity: NetDiskLocalData.checkLinkValidity("tianyiyun"),
				},
			],
			hecaiyun: [
				{
					enable: NetDiskLocalData.enable("hecaiyun"),
					link_innerText: `caiyun.139.com/m/i\\?([a-zA-Z0-9_-]{8,14})([\\s\\S]{0,${NetDiskLocalData.innerTextAccessCodeBeforeMaxRange(
						"hecaiyun"
					)}}(密码|访问码|提取码)[\\s\\S]{0,${NetDiskLocalData.innerTextAccessCodeAfterMaxRange(
						"hecaiyun"
					)}}[0-9a-zA-Z]{4}|)`,
					link_innerHTML: `caiyun.139.com/m/i\\?([a-zA-Z0-9_-]{8,14})([\\s\\S]{0,${NetDiskLocalData.innerHTMLAccessCodeBeforeMaxRange(
						"hecaiyun"
					)}}(密码|访问码|提取码)[\\s\\S]{0,${NetDiskLocalData.innerHTMLAccessCodeAfterMaxRange(
						"hecaiyun"
					)}}[0-9a-zA-Z]{4}|)`,
					shareCode: /caiyun\.139\.com\/m\/i\?([a-zA-Z0-9_\-]{8,14})/gi,
					shareCodeNeedRemoveStr: /caiyun\.139\.com\/m\/i\?/gi,
					checkAccessCode: /(密码|访问码|提取码)[\s\S]+/g,
					accessCode: /([0-9a-zA-Z]{4})/gi,
					uiLinkShow: "caiyun.139.com/m/i?{#shareCode#} 提取码: {#accessCode#}",
					blank: "https://caiyun.139.com/m/i?{#shareCode#}",
					copyUrl:
						"https://caiyun.139.com/m/i?{#shareCode#}\n密码:{#accessCode#}",
					checkLinkValidity: NetDiskLocalData.checkLinkValidity("hecaiyun"),
				},
				{
					enable: NetDiskLocalData.enable("hecaiyun"),
					link_innerText: `yun.139.com/link/w/i/([a-zA-Z0-9_-]{8,14})([\\s\\S]{0,${NetDiskLocalData.innerTextAccessCodeBeforeMaxRange(
						"hecaiyun"
					)}}(密码|访问码|提取码)[\\s\\S]{0,${NetDiskLocalData.innerTextAccessCodeAfterMaxRange(
						"hecaiyun"
					)}}[0-9a-zA-Z]{4}|)`,
					link_innerHTML: `yun.139.com/link/w/i/([a-zA-Z0-9_-]{8,14})([\\s\\S]{0,${NetDiskLocalData.innerHTMLAccessCodeBeforeMaxRange(
						"hecaiyun"
					)}}(密码|访问码|提取码)[\\s\\S]{0,${NetDiskLocalData.innerHTMLAccessCodeAfterMaxRange(
						"hecaiyun"
					)}}[0-9a-zA-Z]{4}|)`,
					shareCode: /yun\.139\.com\/link\/w\/i\/([a-zA-Z0-9_\-]{8,14})/gi,
					shareCodeNeedRemoveStr: /yun\.139\.com\/link\/w\/i\//gi,
					checkAccessCode: /(密码|访问码|提取码)[\s\S]+/g,
					accessCode: /([0-9a-zA-Z]{4})/gi,
					uiLinkShow:
						"yun.139.com/link/w/i/{#shareCode#} 提取码: {#accessCode#}",
					blank: "https://yun.139.com/link/w/i/{#shareCode#}",
					copyUrl:
						"https://yun.139.com/link/w/i/{#shareCode#}\n密码:{#accessCode#}",
					checkLinkValidity: NetDiskLocalData.checkLinkValidity("hecaiyun"),
				},
			],
			aliyun: [
				{
					enable: NetDiskLocalData.enable("aliyun"),
					link_innerText: `aliyundrive.com/s/([a-zA-Z0-9_-]{8,14})([\\s\\S]{0,${NetDiskLocalData.innerTextAccessCodeBeforeMaxRange(
						"aliyun"
					)}}(密码|访问码|提取码)[\\s\\S]{0,${NetDiskLocalData.innerTextAccessCodeAfterMaxRange(
						"aliyun"
					)}}[0-9a-zA-Z]{4}|)`,
					link_innerHTML: `aliyundrive.com/s/([a-zA-Z0-9_-]{8,14})([\\s\\S]{0,${NetDiskLocalData.innerHTMLAccessCodeBeforeMaxRange(
						"aliyun"
					)}}(密码|访问码|提取码)[\\s\\S]{0,${NetDiskLocalData.innerHTMLAccessCodeAfterMaxRange(
						"aliyun"
					)}}[0-9a-zA-Z]{4}|)`,
					shareCode: /aliyundrive\.com\/s\/([a-zA-Z0-9_\-]{8,14})/g,
					shareCodeNeedRemoveStr: /aliyundrive\.com\/s\//gi,
					checkAccessCode: /(密码|访问码|提取码)[\s\S]+/g,
					accessCode: /([0-9a-zA-Z]{4})/gi,
					uiLinkShow: "aliyundrive.com/s/{#shareCode#} 提取码: {#accessCode#}",
					blank: "https://www.aliyundrive.com/s/{#shareCode#}",
					copyUrl:
						"https://www.aliyundrive.com/s/{#shareCode#}\n密码:{#accessCode#}",
					checkLinkValidity: NetDiskLocalData.checkLinkValidity("aliyun"),
				},
				{
					enable: NetDiskLocalData.enable("aliyun"),
					link_innerText: `aliyundrive.com/t/([a-zA-Z0-9_-]{8,14})([\\s\\S]{0,${NetDiskLocalData.innerTextAccessCodeBeforeMaxRange(
						"aliyun"
					)}}(密码|访问码|提取码)[\\s\\S]{0,${NetDiskLocalData.innerTextAccessCodeAfterMaxRange(
						"aliyun"
					)}}[0-9a-zA-Z]{4}|)`,
					link_innerHTML: `aliyundrive.com/t/([a-zA-Z0-9_-]{8,14})([\\s\\S]{0,${NetDiskLocalData.innerHTMLAccessCodeBeforeMaxRange(
						"aliyun"
					)}}(密码|访问码|提取码)[\\s\\S]{0,${NetDiskLocalData.innerHTMLAccessCodeAfterMaxRange(
						"aliyun"
					)}}[0-9a-zA-Z]{4}|)`,
					shareCode: /aliyundrive\.com\/t\/([a-zA-Z0-9_\-]{8,14})/g,
					shareCodeNeedRemoveStr: /aliyundrive\.com\/t\//gi,
					checkAccessCode: /(密码|访问码|提取码)[\s\S]+/g,
					accessCode: /([0-9a-zA-Z]{4})/gi,
					uiLinkShow: "aliyundrive.com/t/{#shareCode#} 提取码: {#accessCode#}",
					blank: "https://www.aliyundrive.com/t/{#shareCode#}",
					copyUrl:
						"https://www.aliyundrive.com/t/{#shareCode#}\n密码:{#accessCode#}",
					checkLinkValidity: NetDiskLocalData.checkLinkValidity("aliyun"),
				},
				{
					enable: NetDiskLocalData.enable("aliyun"),
					link_innerText: `alipan.com/s/([a-zA-Z0-9_-]{8,14})([\\s\\S]{0,${NetDiskLocalData.innerTextAccessCodeBeforeMaxRange(
						"aliyun"
					)}}(密码|访问码|提取码)[\\s\\S]{0,${NetDiskLocalData.innerTextAccessCodeAfterMaxRange(
						"aliyun"
					)}}[0-9a-zA-Z]{4}|)`,
					link_innerHTML: `alipan.com/s/([a-zA-Z0-9_-]{8,14})([\\s\\S]{0,${NetDiskLocalData.innerHTMLAccessCodeBeforeMaxRange(
						"aliyun"
					)}}(密码|访问码|提取码)[\\s\\S]{0,${NetDiskLocalData.innerHTMLAccessCodeAfterMaxRange(
						"aliyun"
					)}}[0-9a-zA-Z]{4}|)`,
					shareCode: /alipan\.com\/s\/([a-zA-Z0-9_\-]{8,14})/g,
					shareCodeNeedRemoveStr: /alipan\.com\/s\//gi,
					checkAccessCode: /(密码|访问码|提取码)[\s\S]+/g,
					accessCode: /([0-9a-zA-Z]{4})/gi,
					uiLinkShow: "alipan.com/s/{#shareCode#} 提取码: {#accessCode#}",
					blank: "https://www.alipan.com/s/{#shareCode#}",
					copyUrl:
						"https://www.alipan.com/s/{#shareCode#}\n密码:{#accessCode#}",
					checkLinkValidity: NetDiskLocalData.checkLinkValidity("aliyun"),
				},
			],
			wenshushu: [
				{
					enable: NetDiskLocalData.enable("wenshushu"),
					link_innerText: `(wenshushu.cn/f/([a-zA-Z0-9_-]{8,14})|wenshushu.cn/k/([a-zA-Z0-9_-]{8,14}))([\\s\\S]{0,${NetDiskLocalData.innerTextAccessCodeBeforeMaxRange(
						"wenshushu"
					)}}(密码|访问码|提取码)[\\s\\S]{0,${NetDiskLocalData.innerTextAccessCodeAfterMaxRange(
						"wenshushu"
					)}}[0-9a-zA-Z]{4}|)`,
					link_innerHTML: `(wenshushu.cn/f/([a-zA-Z0-9_-]{8,14})|wenshushu.cn/k/([a-zA-Z0-9_-]{8,14}))([\\s\\S]{0,${NetDiskLocalData.innerHTMLAccessCodeBeforeMaxRange(
						"wenshushu"
					)}}(密码|访问码|提取码)[\\s\\S]{0,${NetDiskLocalData.innerHTMLAccessCodeAfterMaxRange(
						"wenshushu"
					)}}[0-9a-zA-Z]{4}|)`,
					shareCode:
						/wenshushu.cn\/f\/([a-zA-Z0-9_-]{8,14})|wenshushu.cn\/k\/([a-zA-Z0-9_-]{8,14})/gi,
					shareCodeNeedRemoveStr: /wenshushu.cn\/f\/|wenshushu.cn\/k\//gi,
					checkAccessCode: /(密码|访问码|提取码)[\s\S]+/g,
					accessCode: /[0-9a-zA-Z]{4}/gi,
					uiLinkShow: "www.wenshushu.cn/f/{#shareCode#} 提取码: {#accessCode#}",
					blank: "https://www.wenshushu.cn/f/{#shareCode#}",
					copyUrl:
						"https://www.wenshushu.cn/f/{#shareCode#}\n密码:{#accessCode#}",
					checkLinkValidity: NetDiskLocalData.checkLinkValidity("wenshushu"),
				},
				{
					enable: NetDiskLocalData.enable("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})|ws59.cn/f/([a-zA-Z0-9_-]{8,14}))([\\s\\S]{0,${NetDiskLocalData.innerTextAccessCodeBeforeMaxRange(
						"wenshushu"
					)}}(密码|访问码|提取码)[\\s\\S]{0,${NetDiskLocalData.innerTextAccessCodeAfterMaxRange(
						"wenshushu"
					)}}[0-9a-zA-Z]{4}|)`,
					link_innerHTML: `(wss.ink/f/([a-zA-Z0-9_-]{8,14})|ws28.cn/f/([a-zA-Z0-9_-]{8,14})|wss1.cn/f/([a-zA-Z0-9_-]{8,14})|ws59.cn/f/([a-zA-Z0-9_-]{8,14}))([\\s\\S]{0,${NetDiskLocalData.innerHTMLAccessCodeBeforeMaxRange(
						"wenshushu"
					)}}(密码|访问码|提取码)[\\s\\S]{0,${NetDiskLocalData.innerHTMLAccessCodeAfterMaxRange(
						"wenshushu"
					)}}[0-9a-zA-Z]{4}|)`,
					shareCode:
						/wss.ink\/f\/([a-zA-Z0-9_-]{8,14})|ws28.cn\/f\/([a-zA-Z0-9_-]{8,14})|wss1.cn\/f\/([a-zA-Z0-9_-]{8,14})|ws59.cn\/f\/([a-zA-Z0-9_-]{8,14})/gi,
					shareCodeNeedRemoveStr:
						/wss.ink\/f\/|ws28.cn\/f\/|wss1.cn\/f\/|ws59.cn\/f\//gi,
					checkAccessCode: /(密码|访问码|提取码)[\s\S]+/g,
					accessCode: /[0-9a-zA-Z]{4}/gi,
					uiLinkShow: "www.wenshushu.cn/f/{#shareCode#} 提取码: {#accessCode#}",
					blank: "https://www.wenshushu.cn/f/{#shareCode#}",
					copyUrl:
						"https://www.wenshushu.cn/f/{#shareCode#}\n密码:{#accessCode#}",
					checkLinkValidity: NetDiskLocalData.checkLinkValidity("wenshushu"),
				},
			],
			nainiu: [
				{
					enable: NetDiskLocalData.enable("nainiu"),
					link_innerText: `cowtransfer.com/s/([a-zA-Z0-9_-]{8,14})([\\s\\S]{0,${NetDiskLocalData.innerTextAccessCodeBeforeMaxRange(
						"nainiu"
					)}}(密码|访问码|提取码)[\\s\\S]{0,${NetDiskLocalData.innerTextAccessCodeAfterMaxRange(
						"nainiu"
					)}}[0-9a-zA-Z]{4,6}|)`,
					link_innerHTML: `cowtransfer.com/s/([a-zA-Z0-9_-]{8,14})([\\s\\S]{0,${NetDiskLocalData.innerHTMLAccessCodeBeforeMaxRange(
						"nainiu"
					)}}(密码|访问码|提取码)[\\s\\S]{0,${NetDiskLocalData.innerHTMLAccessCodeAfterMaxRange(
						"nainiu"
					)}}[0-9a-zA-Z]{4,6}|)`,
					shareCode: /cowtransfer.com\/s\/([a-zA-Z0-9_\-]{8,14})/gi,
					shareCodeNeedRemoveStr: /cowtransfer\.com\/s\//gi,
					checkAccessCode: /(密码|访问码|提取码)[\s\S]+/g,
					accessCode: /([0-9a-zA-Z]{4,6})/gi,
					uiLinkShow: "cowtransfer.com/s/{#shareCode#} 提取码: {#accessCode#}",
					blank: "https://cowtransfer.com/s/{#shareCode#}",
					copyUrl:
						"https://cowtransfer.com/s/{#shareCode#}\n密码:{#accessCode#}",
					checkLinkValidity: NetDiskLocalData.checkLinkValidity("nainiu"),
				},
			],
			_123pan: [
				{
					enable: NetDiskLocalData.enable("_123pan"),
					link_innerText: `123pan.com/s/([a-zA-Z0-9_-]{8,14})([\\s\\S]{0,${NetDiskLocalData.innerTextAccessCodeBeforeMaxRange(
						"_123pan"
					)}}(密码|访问码|提取码)[\\s\\S]{0,${NetDiskLocalData.innerTextAccessCodeAfterMaxRange(
						"_123pan"
					)}}[0-9a-zA-Z]{4}|)`,
					link_innerHTML: `123pan.com/s/([a-zA-Z0-9_-]{8,14})([\\s\\S]{0,${NetDiskLocalData.innerHTMLAccessCodeBeforeMaxRange(
						"_123pan"
					)}}(密码|访问码|提取码)[\\s\\S]{0,${NetDiskLocalData.innerHTMLAccessCodeAfterMaxRange(
						"_123pan"
					)}}[0-9a-zA-Z]{4}|)`,
					shareCode: /123pan.com\/s\/([a-zA-Z0-9_\-]{8,14})/gi,
					shareCodeNeedRemoveStr: /123pan.com\/s\//gi,
					checkAccessCode: /(密码|访问码|提取码)[\s\S]+/g,
					accessCode: /([0-9a-zA-Z]{4})/gi,
					uiLinkShow: "123pan.com/s/{#shareCode#} 提取码: {#accessCode#}",
					blank: "https://123pan.com/s/{#shareCode#}",
					copyUrl: "https://123pan.com/s/{#shareCode#}\n密码:{#accessCode#}",
					checkLinkValidity: NetDiskLocalData.checkLinkValidity("_123pan"),
				},
			],
			weiyun: [
				{
					enable: NetDiskLocalData.enable("weiyun"),
					link_innerText: `weiyun.com/[0-9a-zA-Z-_]{7,24}([\\s\\S]{0,${NetDiskLocalData.innerTextAccessCodeBeforeMaxRange(
						"weiyun"
					)}(访问码|密码|提取码)[\\s\\S]{0,${NetDiskLocalData.innerTextAccessCodeAfterMaxRange(
						"weiyun"
					)}[0-9a-zA-Z]{4,6}|)`,
					link_innerHTML: `weiyun.com/[0-9a-zA-Z-_]{7,24}([\\s\\S]{0,${NetDiskLocalData.innerHTMLAccessCodeBeforeMaxRange(
						"weiyun"
					)}(访问码|密码|提取码)[\\s\\S]{0,${NetDiskLocalData.innerHTMLAccessCodeAfterMaxRange(
						"weiyun"
					)}[0-9a-zA-Z]{4,6}|)`,
					shareCode: /weiyun.com\/([0-9a-zA-Z\-_]{7,24})/gi,
					shareCodeNeedRemoveStr: /weiyun.com\//gi,
					checkAccessCode: /(提取码|密码|访问码)[\s\S]+/g,
					accessCode: /([0-9a-zA-Z]{4,6})/gi,
					uiLinkShow: "share.weiyun.com/{#shareCode#} 提取码: {#accessCode#}",
					blank: "https://share.weiyun.com/{#shareCode#}",
					copyUrl:
						"https://share.weiyun.com/{#shareCode#}\n密码:{#accessCode#}",
					checkLinkValidity: NetDiskLocalData.checkLinkValidity("weiyun"),
				},
			],
			xunlei: [
				{
					enable: NetDiskLocalData.enable("xunlei"),
					link_innerText: `xunlei.com/s/[0-9a-zA-Z-_]{8,30}([\\s\\S]{0,${NetDiskLocalData.innerTextAccessCodeBeforeMaxRange(
						"xunlei"
					)}}(\\?pwd=|访问码|提取码|密码|)[\\s\\S]{0,${NetDiskLocalData.innerTextAccessCodeAfterMaxRange(
						"xunlei"
					)}}[0-9a-zA-Z]{4}|)`,
					link_innerHTML: `xunlei.com\/s\/[0-9a-zA-Z\-_]{8,30}([\\s\\S]{0,${NetDiskLocalData.innerHTMLAccessCodeBeforeMaxRange(
						"xunlei"
					)}}(\\?pwd=|访问码|提取码|密码|)[\\s\\S]{0,${NetDiskLocalData.innerHTMLAccessCodeAfterMaxRange(
						"xunlei"
					)}}[0-9a-zA-Z]{4}|)`,
					shareCode: /xunlei.com\/s\/([0-9a-zA-Z\-_]{8,30})/gi,
					shareCodeNeedRemoveStr: /xunlei.com\/s\//gi,
					checkAccessCode: /(\?pwd=|提取码|密码|访问码)[\s\S]+/g,
					accessCode: /([0-9a-zA-Z]{4})/gi,
					uiLinkShow:
						"pan.xunlei.com/s/{#shareCode#}?pwd={#accessCode#} 提取码: {#accessCode#}",
					blank: "https://pan.xunlei.com/s/{#shareCode#}?pwd={#accessCode#}",
					copyUrl: "https://pan.xunlei.com/s/{#shareCode#}?pwd={#accessCode#}",
					checkLinkValidity: NetDiskLocalData.checkLinkValidity("xunlei"),
				},
			],
			_115pan: [
				{
					enable: NetDiskLocalData.enable("_115pan"),
					link_innerText: `115.com/s/[0-9a-zA-Z-_]{8,24}([\\s\\S]{0,${NetDiskLocalData.innerTextAccessCodeBeforeMaxRange(
						"_115pan"
					)}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,${NetDiskLocalData.innerTextAccessCodeAfterMaxRange(
						"_115pan"
					)}}[0-9a-zA-Z]{4}|)`,
					link_innerHTML: `115.com\/s\/[0-9a-zA-Z-_]{8,24}([\\s\\S]{0,${NetDiskLocalData.innerHTMLAccessCodeBeforeMaxRange(
						"_115pan"
					)}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,${NetDiskLocalData.innerHTMLAccessCodeAfterMaxRange(
						"_115pan"
					)}}[0-9a-zA-Z]{4}|)`,
					shareCode: /115.com\/s\/([0-9a-zA-Z\-_]{8,24})/gi,
					shareCodeNeedRemoveStr: /115.com\/s\//gi,
					checkAccessCode: /(提取码|密码|\?password=|访问码)[\s\S]+/gi,
					accessCode: /(\?password=|)([0-9a-zA-Z]{4})/i,
					uiLinkShow: "115.com/s/{#shareCode#} 提取码: {#accessCode#}",
					blank: "https://115.com/s/{#shareCode#}",
					copyUrl: "https://115.com/s/{#shareCode#}\n密码:{#accessCode#}",
					checkLinkValidity: NetDiskLocalData.checkLinkValidity("_115pan"),
				},
			],
			chengtong: [
				/* d */
				{
					enable: NetDiskLocalData.enable("chengtong"),
					link_innerText: `(ct.ghpym.com|pan.jc-box.com|download.jamcz.com)/d/[0-9a-zA-Z-_]{8,26}([\\s\\S]{0,${NetDiskLocalData.innerTextAccessCodeBeforeMaxRange(
						"_chengtong"
					)}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,${NetDiskLocalData.innerTextAccessCodeAfterMaxRange(
						"chengtong"
					)}}[0-9a-zA-Z]{4,6}|)`,
					link_innerHTML: `(ct.ghpym.com|pan.jc-box.com|download.jamcz.com)/d/[0-9a-zA-Z-_]{8,26}([\\s\\S]{0,${NetDiskLocalData.innerHTMLAccessCodeBeforeMaxRange(
						"_chengtong"
					)}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,${NetDiskLocalData.innerHTMLAccessCodeAfterMaxRange(
						"chengtong"
					)}}[0-9a-zA-Z]{4,6}|)`,
					shareCode:
						/(ct.ghpym.com|pan.jc-box.com|download.jamcz.com)\/d\/([0-9a-zA-Z\-_]{8,26})/gi,
					shareCodeNeedRemoveStr:
						/(ct.ghpym.com|pan.jc-box.com|download.jamcz.com)\/d\//gi,
					checkAccessCode: /(提取码|密码|访问码)[\s\S]+/gi,
					accessCode: /([0-9a-zA-Z]{4,6})/gi,
					paramMatch: /([a-zA-Z0-9\.]+)\/d\//i,
					uiLinkShow: "{#$1#}/d/{#shareCode#} 提取码: {#accessCode#}",
					blank: "https://{#$1#}/d/{#shareCode#}",
					copyUrl: "https://{#$1#}/d/{#shareCode#}\n密码:{#accessCode#}",
					checkLinkValidity: NetDiskLocalData.checkLinkValidity("chengtong"),
				},
				/* d */
				{
					enable: NetDiskLocalData.enable("chengtong"),
					link_innerText: `ctfile.com/d/[0-9a-zA-Z-_]{8,26}([\\s\\S]{0,${NetDiskLocalData.innerTextAccessCodeBeforeMaxRange(
						"_chengtong"
					)}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,${NetDiskLocalData.innerTextAccessCodeAfterMaxRange(
						"chengtong"
					)}}[0-9a-zA-Z]{4,6}|)`,
					link_innerHTML: `ctfile.com/d/[0-9a-zA-Z-_]{8,26}([\\s\\S]{0,${NetDiskLocalData.innerHTMLAccessCodeBeforeMaxRange(
						"_chengtong"
					)}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,${NetDiskLocalData.innerHTMLAccessCodeAfterMaxRange(
						"chengtong"
					)}}[0-9a-zA-Z]{4,6}|)`,
					shareCode: /ctfile.com\/d\/([0-9a-zA-Z\-_]{8,26})/gi,
					shareCodeNeedRemoveStr: /ctfile.com\/d\//gi,
					checkAccessCode: /(提取码|密码|访问码)[\s\S]+/gi,
					accessCode: /([0-9a-zA-Z]{4,6})/gi,
					uiLinkShow: "url95.ctfile.com/d/{#shareCode#} 提取码: {#accessCode#}",
					blank: "https://url95.ctfile.com/d/{#shareCode#}",
					copyUrl:
						"https://url95.ctfile.com/d/{#shareCode#}\n密码:{#accessCode#}",
					checkLinkValidity: NetDiskLocalData.checkLinkValidity("chengtong"),
				},
				/* file */
				{
					enable: NetDiskLocalData.enable("chengtong"),
					link_innerText: `(2k.us|u062.com|545c.com|t00y.com)/file/[0-9a-zA-Z-_]{8,26}([\\s\\S]{0,${NetDiskLocalData.innerTextAccessCodeBeforeMaxRange(
						"_chengtong"
					)}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,${NetDiskLocalData.innerTextAccessCodeAfterMaxRange(
						"chengtong"
					)}}[0-9a-zA-Z]{4,6}|)`,
					link_innerHTML: `(2k.us|u062.com|545c.com|t00y.com)/file/[0-9a-zA-Z-_]{8,26}([\\s\\S]{0,${NetDiskLocalData.innerHTMLAccessCodeBeforeMaxRange(
						"_chengtong"
					)}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,${NetDiskLocalData.innerHTMLAccessCodeAfterMaxRange(
						"chengtong"
					)}}[0-9a-zA-Z]{4,6}|)`,
					shareCode:
						/(2k.us|u062.com|545c.com|t00y.com)\/file\/([0-9a-zA-Z\-_]{8,26})/gi,
					shareCodeNeedRemoveStr:
						/(2k.us|u062.com|545c.com|t00y.com)\/file\//gi,
					checkAccessCode: /(提取码|密码|访问码)[\s\S]+/gi,
					accessCode: /([0-9a-zA-Z]{4,6})/gi,
					uiLinkShow: "u062.com/file/{#shareCode#} 提取码: {#accessCode#}",
					blank: "https://u062.com/file/{#shareCode#}",
					copyUrl: "https://u062.com/file/{#shareCode#}\n密码:{#accessCode#}",
					checkLinkValidity: NetDiskLocalData.checkLinkValidity("chengtong"),
				},
				/* f */
				{
					enable: NetDiskLocalData.enable("chengtong"),
					link_innerText: `(pan.jc-box.com|545c.com|down.jc-box.com|download.cx05.cc)/f/[0-9a-zA-Z-_]{8,26}([\\s\\S]{0,${NetDiskLocalData.innerTextAccessCodeBeforeMaxRange(
						"_chengtong"
					)}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,${NetDiskLocalData.innerTextAccessCodeAfterMaxRange(
						"chengtong"
					)}}[0-9a-zA-Z]{4,6}|)`,
					link_innerHTML: `(pan.jc-box.com|545c.com|down.jc-box.com|download.cx05.cc)/f/[0-9a-zA-Z-_]{8,26}([\\s\\S]{0,${NetDiskLocalData.innerHTMLAccessCodeBeforeMaxRange(
						"_chengtong"
					)}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,${NetDiskLocalData.innerHTMLAccessCodeAfterMaxRange(
						"chengtong"
					)}}[0-9a-zA-Z]{4,6}|)`,
					shareCode:
						/(pan.jc-box.com|545c.com|down.jc-box.com|download.cx05.cc)\/f\/([0-9a-zA-Z\-_]{8,26})/gi,
					shareCodeNeedRemoveStr:
						/(pan.jc-box.com|545c.com|down.jc-box.com|download.cx05.cc)\/f\//gi,
					checkAccessCode: /(提取码|密码|访问码)[\s\S]+/gi,
					accessCode: /([0-9a-zA-Z]{4,6})/gi,
					paramMatch: /([0-9a-zA-Z\.+])\/f\//i,
					uiLinkShow: "{#$1#}/f/{#shareCode#} 提取码: {#accessCode#}",
					blank: "http://{#$1#}/f/{#shareCode#}",
					copyUrl: "http://{#$1#}/f/{#shareCode#}\n密码:{#accessCode#}",
					checkLinkValidity: NetDiskLocalData.checkLinkValidity("chengtong"),
				},
				/* f */
				{
					enable: NetDiskLocalData.enable("chengtong"),
					link_innerText: `(ctfile.com|089u.com)/f/[0-9a-zA-Z-_]{8,26}([\\s\\S]{0,${NetDiskLocalData.innerTextAccessCodeBeforeMaxRange(
						"_chengtong"
					)}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,${NetDiskLocalData.innerTextAccessCodeAfterMaxRange(
						"chengtong"
					)}}[0-9a-zA-Z]{4,6}|)`,
					link_innerHTML: `(ctfile.com|089u.com)/f/[0-9a-zA-Z-_]{8,26}([\\s\\S]{0,${NetDiskLocalData.innerHTMLAccessCodeBeforeMaxRange(
						"_chengtong"
					)}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,${NetDiskLocalData.innerHTMLAccessCodeAfterMaxRange(
						"chengtong"
					)}}[0-9a-zA-Z]{4,6}|)`,
					shareCode: /(ctfile.com|089u.com)\/f\/([0-9a-zA-Z\-_]{8,26})/gi,
					shareCodeNeedRemoveStr: /(ctfile.com|089u.com)\/f\//gi,
					checkAccessCode: /(提取码|密码|访问码)[\s\S]+/gi,
					accessCode: /([0-9a-zA-Z]{4,6})/gi,
					uiLinkShow: "url95.ctfile.com/f/{#shareCode#} 提取码: {#accessCode#}",
					blank: "https://url95.ctfile.com/f/{#shareCode#}",
					copyUrl:
						"https://url95.ctfile.com/f/{#shareCode#}\n密码:{#accessCode#}",
					checkLinkValidity: NetDiskLocalData.checkLinkValidity("chengtong"),
				},
				/* dir */
				{
					enable: NetDiskLocalData.enable("chengtong"),
					link_innerText: `(089u.com|474b.com)/dir/[0-9a-zA-Z-_]{8,26}([\\s\\S]{0,${NetDiskLocalData.innerTextAccessCodeBeforeMaxRange(
						"_chengtong"
					)}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,${NetDiskLocalData.innerTextAccessCodeAfterMaxRange(
						"chengtong"
					)}}[0-9a-zA-Z]{4,6}|)`,
					link_innerHTML: `(089u.com|474b.com)/dir/[0-9a-zA-Z-_]{8,26}([\\s\\S]{0,${NetDiskLocalData.innerHTMLAccessCodeBeforeMaxRange(
						"_chengtong"
					)}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,${NetDiskLocalData.innerHTMLAccessCodeAfterMaxRange(
						"chengtong"
					)}}[0-9a-zA-Z]{6}|)`,
					shareCode: /(089u.com|474b.com)\/dir\/([0-9a-zA-Z\-_]{8,26})/gi,
					shareCodeNeedRemoveStr: /(089u.com|474b.com)\/dir\//gi,
					checkAccessCode: /(提取码|密码|访问码)[\s\S]+/gi,
					accessCode: /([0-9a-zA-Z]{6})/gi,
					uiLinkShow: "089u.com/dir/{#shareCode#} 提取码: {#accessCode#}",
					blank: "https://089u.com/dir/{#shareCode#}",
					copyUrl: "https://089u.com/dir/{#shareCode#}\n密码:{#accessCode#}",
					checkLinkValidity: NetDiskLocalData.checkLinkValidity("chengtong"),
				},
			],
			kuake: [
				{
					enable: NetDiskLocalData.enable("kuake"),
					link_innerText: `quark.cn/s/[0-9a-zA-Z-_]{8,24}([\\s\\S]{0,${NetDiskLocalData.innerTextAccessCodeBeforeMaxRange(
						"kuake"
					)}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,${NetDiskLocalData.innerTextAccessCodeAfterMaxRange(
						"kuake"
					)}}[0-9a-zA-Z]{4}|)`,
					link_innerHTML: `quark.cn/s/[0-9a-zA-Z-_]{8,24}([\\s\\S]{0,${NetDiskLocalData.innerHTMLAccessCodeBeforeMaxRange(
						"kuake"
					)}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,${NetDiskLocalData.innerHTMLAccessCodeAfterMaxRange(
						"kuake"
					)}}[0-9a-zA-Z]{4}|)`,
					shareCode: /quark.cn\/s\/([0-9a-zA-Z\-_]{8,24})/gi,
					shareCodeNeedRemoveStr: /quark.cn\/s\//gi,
					checkAccessCode: /(提取码|密码|访问码)[\s\S]+/gi,
					accessCode: /([0-9a-zA-Z]{4})/gi,
					uiLinkShow: "quark.cn/s/{#shareCode#} 提取码: {#accessCode#}",
					blank: "https://pan.quark.cn/s/{#shareCode#}",
					copyUrl: "https://pan.quark.cn/s/{#shareCode#}\n密码:{#accessCode#}",
					checkLinkValidity: NetDiskLocalData.checkLinkValidity("kuake"),
				},
			],
			magnet: [
				{
					enable: NetDiskLocalData.enable("magnet"),
					link_innerText: `magnet:\\?xt=urn:btih:[0-9a-fA-F]{32,40}`,
					link_innerHTML: `magnet:\\?xt=urn:btih:[0-9a-fA-F]{32,40}`,
					shareCode: /magnet:\?xt=urn:btih:([0-9a-fA-F]{32,40})/gi,
					shareCodeNeedRemoveStr: /magnet:\?xt=urn:btih:/gi,
					checkAccessCode: /(提取码|密码|访问码)[\s\S]+/gi,
					accessCode: /([0-9a-zA-Z]{4})/gi,
					uiLinkShow: "magnet:?xt=urn:btih:{#shareCode#}",
					blank: "magnet:?xt=urn:btih:{#shareCode#}",
					copyUrl: "magnet:?xt=urn:btih:{#shareCode#}",
					checkLinkValidity: NetDiskLocalData.checkLinkValidity("magnet"),
				},
			],
			jianguoyun: [
				{
					enable: NetDiskLocalData.enable("jianguoyun"),
					link_innerText: `jianguoyun.com/p/[0-9a-zA-Z-_]{16,24}([\\s\\S]{0,${NetDiskLocalData.innerTextAccessCodeBeforeMaxRange(
						"jianguoyun"
					)}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,${NetDiskLocalData.innerTextAccessCodeAfterMaxRange(
						"jianguoyun"
					)}}[0-9a-zA-Z]+|)`,
					link_innerHTML: `jianguoyun.com/p/[0-9a-zA-Z-_]{16,24}([\\s\\S]{0,${NetDiskLocalData.innerHTMLAccessCodeBeforeMaxRange(
						"jianguoyun"
					)}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,${NetDiskLocalData.innerHTMLAccessCodeAfterMaxRange(
						"jianguoyun"
					)}}[0-9a-zA-Z]+|)`,
					shareCode: /jianguoyun.com\/p\/([0-9a-zA-Z\-_]{16,24})/gi,
					shareCodeNeedRemoveStr: /jianguoyun.com\/p\//gi,
					checkAccessCode: /(提取码|密码|访问码)[\s\S]+/gi,
					accessCode: /([0-9a-zA-Z]{3,6})/gi,
					uiLinkShow: "jianguoyun.com/p/{#shareCode#} 提取码: {#accessCode#}",
					blank: "https://www.jianguoyun.com/p/{#shareCode#}",
					copyUrl:
						"https://www.jianguoyun.com/p/{#shareCode#}\n密码:{#accessCode#}",
					checkLinkValidity: NetDiskLocalData.checkLinkValidity("jianguoyun"),
				},
			],
			onedrive: [
				{
					enable: NetDiskLocalData.enable("onedrive"),
					link_innerText: `[0-9a-zA-Z-_]+.sharepoint.com/[0-9a-zA-Z-_:]+/[0-9a-zA-Z-_:]+/personal/[0-9a-zA-Z-_]+/[0-9a-zA-Z-_]+([\\s\\S]{0,${NetDiskLocalData.innerTextAccessCodeBeforeMaxRange(
						"onedrive"
					)}}(访问码|密码|提取码|\\?password=\\?e=)[\\s\\S]{0,${NetDiskLocalData.innerTextAccessCodeAfterMaxRange(
						"onedrive"
					)}}[0-9a-zA-Z]+|)`,
					link_innerHTML: `[0-9a-zA-Z-_]+.sharepoint.com/[0-9a-zA-Z-_:]+/[0-9a-zA-Z-_:]+/personal/[0-9a-zA-Z-_]+/[0-9a-zA-Z-_]+([\\s\\S]{0,${NetDiskLocalData.innerHTMLAccessCodeBeforeMaxRange(
						"onedrive"
					)}}(访问码|密码|提取码|\\?password=\\?e=)[\\s\\S]{0,${NetDiskLocalData.innerHTMLAccessCodeAfterMaxRange(
						"onedrive"
					)}}[0-9a-zA-Z]+|)`,
					shareCode:
						/[0-9a-zA-Z-_]+\/[0-9a-zA-Z-_:]+\/[0-9a-zA-Z-_:]+\/personal\/[0-9a-zA-Z-_]+\/([0-9a-zA-Z\-_]+)/gi,
					shareCodeNeedRemoveStr:
						/[0-9a-zA-Z-_]+\/[0-9a-zA-Z-_:]+\/[0-9a-zA-Z-_:]+\/personal\/[0-9a-zA-Z-_]+\//gi,
					checkAccessCode: /(提取码|密码|访问码|\?password=|\?e=)[\s\S]+/gi,
					accessCode: /([0-9a-zA-Z]{4,8})/gi,
					paramMatch:
						/([0-9a-zA-Z-_]+).sharepoint.com\/([0-9a-zA-Z-_:]+)\/([0-9a-zA-Z-_:]+)\/personal\/([0-9a-zA-Z-_]+)\/([0-9a-zA-Z-_]+)/i,
					uiLinkShow:
						"{#$1#}.sharepoint.com/{#$2#}/{#$3#}/personal/{#$4#}/{#shareCode#} 提取码: {#accessCode#}",
					blank:
						"https://{#$1#}.sharepoint.com/{#$2#}/{#$3#}/personal/{#$4#}/{#shareCode#}?e={#accessCode#}",
					copyUrl:
						"https://{#$1#}.sharepoint.com/{#$2#}/{#$3#}/personal/{#$4#}/{#shareCode#}\n密码:{#accessCode#}",
					checkLinkValidity: NetDiskLocalData.checkLinkValidity("onedrive"),
				},
			],
			uc: [
				{
					enable: NetDiskLocalData.enable("uc"),
					link_innerText: `(drive|fast).uc.cn/s/[0-9a-zA-Z]{8,24}([\\s\\S]{0,${NetDiskLocalData.innerTextAccessCodeBeforeMaxRange(
						"uc"
					)}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,${NetDiskLocalData.innerTextAccessCodeAfterMaxRange(
						"uc"
					)}}[0-9a-zA-Z]+|)`,
					link_innerHTML: `(drive|fast).uc.cn/s/[0-9a-zA-Z]{8,24}([\\s\\S]{0,${NetDiskLocalData.innerHTMLAccessCodeBeforeMaxRange(
						"uc"
					)}}(访问码|密码|提取码|\\?password=)[\\s\\S]{0,${NetDiskLocalData.innerHTMLAccessCodeAfterMaxRange(
						"uc"
					)}}[0-9a-zA-Z]+|)`,
					shareCode: /(drive|fast).uc.cn\/s\/([0-9a-zA-Z]{8,24})/gi,
					shareCodeNeedRemoveStr: /(drive|fast).uc.cn\/s\//gi,
					checkAccessCode: /(提取码|密码|访问码)[\s\S]+/gi,
					accessCode: /([0-9a-zA-Z]+)/gi,
					uiLinkShow: "drive.uc.cn/s/{#shareCode#} 提取码: {#accessCode#}",
					blank: "https://drive.uc.cn/s/{#shareCode#}",
					copyUrl: "https://drive.uc.cn/s/{#shareCode#}\n密码:{#accessCode#}",
					checkLinkValidity: NetDiskLocalData.checkLinkValidity("uc"),
				},
			],
		},
		/**
		 * 初始化
		 */
		init() {
			if (!this.isInit) {
				this.isInit = true;
				this.matchLink = new Set();
				this.initLinkDict();
			}
		},
		/**
		 * 初始化字典
		 */
		initLinkDict() {
			NetDisk.linkDict = new utils.Dictionary();
			NetDisk.tempLinkDict = new utils.Dictionary();
			Object.keys(NetDisk.regular).forEach((netDiskName) => {
				NetDisk.linkDict.set(netDiskName, new utils.Dictionary());
				NetDisk.tempLinkDict.set(netDiskName, new utils.Dictionary());
			});
		},
		/**
		 * 删除某些需要忽略的text或html,如:设置、直链弹窗
		 * @param {string} text 需要进行处理的字符串
		 * @param {boolean} isHTML 是否是html属性
		 * @returns {string}
		 */
		ignoreStrRemove(text, isHTML = false) {
			let ignoreNodeList = [];
			ignoreNodeList.forEach((ignoreElement) => {
				if (ignoreElement == void 0) {
					return;
				}
				if (isHTML) {
					if (ignoreElement.innerHTML != void 0) {
						text = text.replaceAll(ignoreElement.innerHTML, "");
					}
				} else {
					let text = ignoreElement.innerText || ignoreElement.textContent;
					if (text != void 0) {
						text = text.replaceAll(text, "");
					}
				}
			});
			return text;
		},
		/**
		 * 处理链接,将匹配到的链接转为参数和密码存入字典中
		 * @param {string} netDiskName 网盘名称
		 * @param {number} netDiskIndex 网盘名称的索引下标
		 * @param {string} matchText 正在进行匹配的文本
		 * @returns 返回值可能为空
		 */
		handleLink(netDiskName, netDiskIndex, matchText) {
			let shareCode = this.handleShareCode(
				netDiskName,
				netDiskIndex,
				matchText
			);
			if (utils.isNull(shareCode)) {
				return;
			}
			let accessCode = this.handleAccessCode(
				netDiskName,
				netDiskIndex,
				matchText
			);
			accessCode = this.handleAccessCodeByUserRule(
				netDiskName,
				accessCode,
				matchText
			);
			return {
				shareCode: shareCode,
				accessCode: accessCode,
			};
		},
		/**
		 * 对传入的url进行处理,返回shareCode
		 * @param {string} netDiskName 网盘名称
		 * @param {number} netDiskIndex 网盘名称索引下标
		 * @param {string} matchText 正在进行匹配的文本
		 */
		handleShareCode(netDiskName, netDiskIndex, matchText) {
			/* 当前执行的规则 */
			let netDiskMatchRegular = NetDisk.regular[netDiskName][netDiskIndex];
			let shareCodeMatch = matchText
				.match(netDiskMatchRegular.shareCode)
				?.filter((item) => utils.isNotNull(item));
			if (utils.isNull(shareCodeMatch)) {
				log.error([
					`匹配shareCode为空`,
					{
						匹配的文本: matchText,
						规则: netDiskMatchRegular,
						正在使用的规则: netDiskMatchRegular.shareCode,
						网盘名称: netDiskName,
						网盘名称索引下标: netDiskIndex,
					},
				]);
				return;
			}
			/* 匹配到的网盘链接,取第一个值就行 */
			let shareCode = shareCodeMatch[0];
			if (netDiskMatchRegular.shareCodeNeedRemoveStr) {
				/* 删除ShareCode前面不需要的字符串 */
				shareCode = shareCode.replace(
					netDiskMatchRegular.shareCodeNeedRemoveStr,
					""
				);
			}
			let shareCodeNotMatch = netDiskMatchRegular.shareCodeNotMatch;
			if (shareCodeNotMatch != void 0 && shareCode.match(shareCodeNotMatch)) {
				log.error(`不可能的shareCode => ${shareCode}`);
				return;
			}
			for (const shareCodeNotMatchRegexp of NetDisk.shareCodeNotMatchRegexpList) {
				if (shareCode.match(shareCodeNotMatchRegexp)) {
					log.error(`不可能的shareCode => ${shareCode}`);
					return;
				}
			}
			/* %E7%BD%91%E7%9B%98 => 网盘 */
			shareCode = decodeURI(shareCode);
			if (
				GM_getValue("excludeIdenticalSharedCodes") &&
				utils.isSameChars(
					shareCode,
					GM_getValue(
						"excludeIdenticalSharedCodesCoefficient",
						NetDiskData.defaultExcludeIdenticalSharedCodesCoefficient
					)
				)
			) {
				/* 排除掉由相同字符组成的分享码 */
				return;
			}
			/* 排除掉以http|https结尾的分享码 */
			if (shareCode.endsWith("http") || shareCode.endsWith("https")) {
				return;
			}
			return shareCode;
		},
		/**
		 * 对传入的url进行处理,返回accessCode
		 * @param {string} netDiskName 网盘名称
		 * @param {number} netDiskIndex 网盘名称索引下标
		 * @param {string} matchText 正在进行匹配的文本
		 * @returns {string} "xxxx" || ""
		 */
		handleAccessCode(netDiskName, netDiskIndex, matchText) {
			/* 当前执行正则匹配的规则 */
			let netDiskMatchRegular = this.regular[netDiskName][netDiskIndex];
			let accessCode = "";
			if (!netDiskMatchRegular.checkAccessCode) {
				/* 不存在匹配提取码的正则 */
				return "";
			}
			let accessCodeMatch = matchText.match(
				netDiskMatchRegular.checkAccessCode
			);
			if (accessCodeMatch) {
				/* 匹配出带提取码的字符串 */
				let accessCodeMatchValue = accessCodeMatch[accessCodeMatch.length - 1];
				/* 进去提取码匹配,且过滤掉null或undefined或空字符串 */
				let accessCodeMatchArray = accessCodeMatchValue
					.match(netDiskMatchRegular.accessCode)
					?.filter((item) => utils.isNotNull(item));
				if (utils.isNull(accessCodeMatchArray)) {
					return "";
				}
				if (accessCodeMatchArray.length) {
					/* 取第一个值 */
					/**
					 * 例如,匹配到的字符串是密码:oanm   大于150m
					 * 如果是最后一个,那么会匹配到150m
					 */
					accessCode = accessCodeMatchArray[0];
					if (accessCode.startsWith("http")) {
						/* 排除不可能的accessCode */
						accessCode = "";
					}
				}
			}
			if (utils.isNotNull(accessCode)) {
				for (const accessCodeNotMatchRegexp of NetDisk.accessCodeNotMatchRegexpList) {
					if (accessCode.match(accessCodeNotMatchRegexp)) {
						accessCode = "";
						break;
					}
				}
				if (
					netDiskMatchRegular.acceesCodeNotMatch &&
					accessCode.match(netDiskMatchRegular.acceesCodeNotMatch)
				) {
					accessCode = "";
				}
			}
			return accessCode;
		},
		/**
		 * 对accessCode二次处理,使用自定义的访问码规则
		 * @param {string} netDiskName 网盘名称
		 * @param {string} accessCode 访问码
		 * @param {string} matchText 匹配到的文本
		 * @returns {string}
		 */
		handleAccessCodeByUserRule(netDiskName, accessCode, matchText) {
			let regularList = NetDiskUI.accessCodeRule.getValue();
			let result = accessCode;
			let currentUrl = window.location.href;
			/* 先遍历本地的自定义的访问码规则 */
			for (
				let regularIndex = 0;
				regularIndex < regularList.length;
				regularIndex++
			) {
				let rule = regularList[regularIndex];
				let urlRegexp = new RegExp(rule.urlRegexp, "i");
				/* 如果网址匹配成功则进行下一步 */
				if (!currentUrl.match(urlRegexp)) {
					continue;
				}
				/* 循环遍历自定义的访问码规则的网盘信息 */
				for (let index = 0; index < rule.netdisk.length; index++) {
					let netDiskRegular = rule.netdisk[index];
					/* 自定义规则的value(也就是网盘的字母名)和参数netDiskName相同,则直接返回设定的值 */
					if (netDiskRegular.value === netDiskName) {
						log.success(`使用自定义规则中的提取码 ${netDiskName} ${result}`);
						return rule.accessCode;
					}
				}
			}
			/* 不存在 */
			return result;
		},
		/**
		 * 获取在弹窗中显示出的链接
		 * @param {string} netDiskName 网盘名称,指NetDisk.regular的内部键名
		 * @param {number} netDiskIndex 网盘名称索引下标
		 * @param {string} shareCode 分享码
		 * @param {string} accessCode 访问码
		 * @param {?string} matchText 匹配到的文本
		 * @returns {string}
		 */
		handleLinkShow(
			netDiskName,
			netDiskIndex,
			shareCode,
			accessCode,
			matchText
		) {
			let netDiskMatchRegular = NetDisk.regular[netDiskName][netDiskIndex];
			if (netDiskMatchRegular == void 0) {
				Qmsg.error("BUG: 获取uiLink规则失败");
				log.error([
					"BUG: 分析参数",
					netDiskName,
					netDiskIndex,
					shareCode,
					accessCode,
				]);
				throw "获取uiLink规则失败";
			}
			let uiLink = this.replaceParam(netDiskMatchRegular["uiLinkShow"], {
				shareCode: shareCode,
			});
			if (accessCode && accessCode != "") {
				uiLink = this.replaceParam(uiLink, {
					accessCode: accessCode,
				});
			} else {
				uiLink = uiLink.replace(NetDisk.noAccessCodeRegExp, "");
			}
			if (netDiskMatchRegular.paramMatch) {
				/**
				 * 当前字典
				 */
				let currentDict = NetDisk.linkDict.get(netDiskName).get(shareCode);
				matchText = matchText ?? currentDict?.matchText;
				if (utils.isNotNull(matchText)) {
					let paramMatchArray = matchText.match(netDiskMatchRegular.paramMatch);
					let replaceParamData = {};
					for (let index = 0; index < paramMatchArray.length; index++) {
						replaceParamData[`$${index}`] = paramMatchArray[index];
					}
					uiLink = this.replaceParam(uiLink, replaceParamData);
				}
			}
			return uiLink;
		},
		/**
		 * 参数替换,区分大小写
		 *
		 * 例如
		 * + {#shareCode#} => xxxx
		 * + {#accessCode#} => xxxx
		 * + {#$1#} => xxxx
		 * @param {string} text
		 * @param {{}} [data={}]
		 */
		replaceParam(text, data = {}) {
			if (typeof text !== "string") {
				return text;
			}
			Object.keys(data).forEach((key) => {
				let replacedText = data[key];
				if (utils.isNotNull(replacedText)) {
					try {
						text = text.replaceAll(
							`{#encodeURI-${key}#}`,
							encodeURI(replacedText)
						);
					} catch (error) {
						log.error(["encodeURI-替换的文本失败", [replacedText]]);
					}

					try {
						text = text.replaceAll(
							`{#encodeURIComponent-${key}#}`,
							encodeURIComponent(replacedText)
						);
					} catch (error) {
						log.error(["encodeURIComponent-替换的文本失败", [replacedText]]);
					}
					try {
						text = text.replaceAll(
							`{#decodeURI-${key}#}`,
							decodeURI(replacedText)
						);
					} catch (error) {
						log.error(["decodeURI-替换的文本失败", [replacedText]]);
					}
					try {
						text = text.replaceAll(
							`{#decodeURIComponent-${key}#}`,
							decodeURIComponent(replacedText)
						);
					} catch (error) {
						log.error(["encodeURIComponent-替换的文本失败", [replacedText]]);
					}
					text = text.replaceAll(`{#${key}#}`, replacedText);
				}
			});
			return text;
		},
		/**
		 * 获取剪贴板文本
		 * @returns {Promise<string>}
		 */
		async getClipboardText() {
			/** 读取剪贴板 */
			function readClipboardText(resolve) {
				navigator.clipboard
					.readText()
					.then((clipboardText) => {
						resolve(clipboardText);
					})
					.catch(
						/** @param {TypeError} error */
						(error) => {
							log.error(["读取剪贴板内容失败👉", error]);
							resolve("");
						}
					);
			}
			/** 申请读取剪贴板的权限 */
			function requestPermissionsWithClipboard(resolve) {
				navigator.permissions
					.query({
						name: "clipboard-read",
					})
					.then((permissionStatus) => {
						readClipboardText(resolve);
					})
					.catch(
						/** @param {TypeError} error */
						(error) => {
							log.error([
								"申请剪贴板权限失败,尝试直接读取👉",
								error.message ?? error.name ?? error.stack,
							]);
							/* 该权限申请Api可能在该环境下不生效,尝试直接读取剪贴板 */
							readClipboardText(resolve);
						}
					);
			}
			function checkClipboardApi() {
				if (typeof navigator?.clipboard?.readText !== "function") {
					return false;
				}
				if (typeof navigator?.permissions?.query !== "function") {
					return false;
				}
				return true;
			}
			return new Promise((resolve) => {
				if (!checkClipboardApi()) {
					resolve("");
					return;
				}
				if (document.hasFocus()) {
					requestPermissionsWithClipboard(resolve);
				} else {
					window.addEventListener(
						"focus",
						() => {
							requestPermissionsWithClipboard(resolve);
						},
						{
							once: true,
						}
					);
				}
			});
		},
		/**
		 * 获取已匹配到的链接的存储的对象
		 * @param {string} accessCode 访问码
		 * @param {number} [netDiskIndex=0] 下标,默认0
		 * @param {boolean} [isForceAccessCode=false] 是否锁定访问码不允许修改,默认false
		 * @param {string} matchText 匹配到的文本
		 * @returns {NetDiskDictData}
		 */
		getLinkDickObj(
			accessCode,
			netDiskIndex = 0,
			isForceAccessCode = false,
			matchText
		) {
			return {
				accessCode: accessCode,
				netDiskIndex: netDiskIndex,
				isForceAccessCode: isForceAccessCode,
				matchText: matchText,
			};
		},
	};

	const NetDiskDebug = {
		/**
		 * 对传入的url进行处理,返回shareCode
		 * @param {string} matchText 正在进行匹配的文本
		 * @param {NetDiskRegularOption} regular 当前执行的规则
		 * @param {(logData: NetDiskDebugLogData)=>void} logCallBack 日志回调
		 */
		handleShareCode(matchText, regular, logCallBack) {
			let shareCodeMatch = matchText
				.match(regular.shareCode)
				?.filter((item) => utils.isNotNull(item));
			logCallBack({
				status: true,
				msg: [
					`正则: shareCode`,
					"作用: 获取shareCode",
					"结果: ",
					shareCodeMatch,
				],
			});
			if (utils.isNull(shareCodeMatch)) {
				logCallBack({
					status: false,
					msg: `匹配shareCode为空`,
				});
				return;
			}
			/* 匹配到的网盘链接,取第一个值就行 */
			let shareCode = shareCodeMatch[0];
			logCallBack({
				status: true,
				msg: [`取第一个值: ` + shareCode],
			});
			if (regular.shareCodeNeedRemoveStr) {
				/* 删除ShareCode前面不需要的字符串 */
				shareCode = shareCode.replace(regular.shareCodeNeedRemoveStr, "");
				logCallBack({
					status: true,
					msg: [
						`正则: shareCodeNeedRemoveStr`,
						"作用: 删除ShareCode前面不需要的字符串",
						`结果: ${shareCode}`,
					],
				});
			}
			let shareCodeNotMatch = regular.shareCodeNotMatch;
			if (shareCodeNotMatch != void 0 && shareCode.match(shareCodeNotMatch)) {
				log.error(`不可能的shareCode => ${shareCode}`);
				logCallBack({
					status: false,
					msg: [
						`正则: shareCodeNotMatch`,
						"作用: 用于判断提取到的shareCode是否是错误的shareCode",
						`结果: true 该shareCode不是正确的`,
					],
				});
				return;
			}
			for (const shareCodeNotMatchRegexp of NetDisk.shareCodeNotMatchRegexpList) {
				if (shareCode.match(shareCodeNotMatchRegexp)) {
					log.error(`不可能的shareCode => ${shareCode}`);
					logCallBack({
						status: false,
						msg: [
							`正则: 内置的shareCodeNotMatchRegexpList`,
							"作用: 使用该正则判断提取到的shareCode是否正确",
							`结果: true 该shareCode不是正确的`,
						],
					});
					return;
				}
			}
			/* %E7%BD%91%E7%9B%98 => 网盘 */
			shareCode = decodeURI(shareCode);
			logCallBack({
				status: true,
				msg: ["对shareCode进行解码: " + shareCode],
			});
			if (
				GM_getValue("excludeIdenticalSharedCodes") &&
				utils.isSameChars(
					shareCode,
					GM_getValue(
						"excludeIdenticalSharedCodesCoefficient",
						NetDiskData.defaultExcludeIdenticalSharedCodesCoefficient
					)
				)
			) {
				/* 排除掉由相同字符组成的分享码 */
				logCallBack({
					status: false,
					msg: ["已开启【排除分享码】且该分享码命中该规则"],
				});
				return;
			}
			/* 排除掉以http|https结尾的分享码 */
			if (shareCode.endsWith("http") || shareCode.endsWith("https")) {
				logCallBack({
					status: false,
					msg: ["该分享码以http|https结尾"],
				});
				return;
			}
			logCallBack({
				status: true,
				msg: "处理完毕的shareCode: " + shareCode,
			});
			return shareCode;
		},
		/**
		 * 对传入的url进行处理,返回accessCode
		 * @param {string} matchText 正在进行匹配的文本
		 * @param {NetDiskRegularOption} regular 当前执行的规则
		 * @param {(logData: NetDiskDebugLogData)=>void} logCallBack 日志回调
		 */
		handleAccessCode(matchText, regular, logCallBack) {
			let accessCode = "";
			if (!regular.checkAccessCode) {
				/* 不存在匹配提取码的正则 */
				logCallBack({
					status: true,
					msg: "因未配置规则checkAccessCode,默认accessCode的值为空",
				});
				return "";
			}
			let accessCodeMatch = matchText.match(regular.checkAccessCode);
			logCallBack({
				status: true,
				msg: [
					`正则: checkAccessCode`,
					"作用: 用来判断link_innerText或者link_innerHTML匹配到的字符串中是否存在密码",
					`结果: `,
					accessCodeMatch,
				],
			});
			if (accessCodeMatch) {
				/* 匹配出带提取码的字符串 */
				let accessCodeMatchValue = accessCodeMatch[accessCodeMatch.length - 1];
				logCallBack({
					status: true,
					msg: "取最后一个值: " + accessCodeMatchValue,
				});
				/* 进去提取码匹配,且过滤掉null或undefined或空字符串 */
				let accessCodeMatchArray = accessCodeMatchValue
					.match(regular.accessCode)
					?.filter((item) => utils.isNotNull(item));
				logCallBack({
					status: true,
					msg: [
						`正则: accessCode`,
						"作用: 用来提取link_innerText或者link_innerHTML匹配到的字符串中的密码",
						`结果: `,
						accessCodeMatchArray,
					],
				});
				if (utils.isNull(accessCodeMatchArray)) {
					logCallBack({
						status: true,
						msg: "因↑匹配到的结果为空,默认accessCode的值为空",
					});
					return "";
				}
				if (accessCodeMatchArray.length) {
					/* 取第一个值 */
					/**
					 * 例如,匹配到的字符串是密码:oanm   大于150m
					 * 如果是最后一个,那么会匹配到150m
					 */
					accessCode = accessCodeMatchArray[0];
					logCallBack({
						status: true,
						msg: "取第一个值: " + accessCode,
					});
					if (accessCode.startsWith("http")) {
						/* 排除不可能的accessCode */
						logCallBack({
							status: true,
							msg: "排除不可能的accessCode,重置accessCode的值为空",
						});
						accessCode = "";
					}
				}
			}
			if (utils.isNotNull(accessCode)) {
				for (const accessCodeNotMatchRegexp of NetDisk.accessCodeNotMatchRegexpList) {
					if (accessCode.match(accessCodeNotMatchRegexp)) {
						accessCode = "";
						logCallBack({
							status: true,
							msg: [
								`正则: 内置的accessCodeNotMatchRegexpList`,
								"作用: 使用该正则判断提取到的accessCode是否正确",
								`结果: true 重置accessCode为空`,
							],
						});
						break;
					}
				}
				if (
					regular.acceesCodeNotMatch &&
					accessCode.match(regular.acceesCodeNotMatch)
				) {
					accessCode = "";
					logCallBack({
						status: true,
						msg: [
							`正则: acceesCodeNotMatch`,
							"作用: 用于判断提取到的accessCode是否是错误的accessCode",
							`结果: true 重置accessCode为空`,
						],
					});
				}
			}

			logCallBack({
				status: true,
				msg: "处理完毕的accessCode: " + accessCode,
			});
			return accessCode;
		},
		/**
		 * 获取在弹窗中显示出的链接
		 * @param {string} matchText 匹配到的文本
		 * @param {NetDiskRegularOption} regular 当前执行的规则
		 * @param {string} shareCode 分享码
		 * @param {string} accessCode 访问码
		 * @param {(logData: NetDiskDebugLogData)=>void} logCallBack 日志回调
		 */
		handleLinkShow(matchText, regular, shareCode, accessCode, logCallBack) {
			let uiLink = NetDisk.replaceParam(regular["uiLinkShow"], {
				shareCode: shareCode,
			});
			logCallBack({
				status: true,
				msg: [
					`正则: uiLinkShow`,
					"作用: 用于显示在弹窗中的字符串",
					"备注: 对shareCode进行参数替换",
					`结果: ${uiLink}`,
				],
			});
			if (accessCode && accessCode != "") {
				uiLink = NetDisk.replaceParam(uiLink, {
					accessCode: accessCode,
				});
				logCallBack({
					status: true,
					msg: [
						`正则: uiLinkShow`,
						"作用: 用于显示在弹窗中的字符串",
						"备注: 对accessCode进行参数替换",
						`结果: ${uiLink}`,
					],
				});
			} else {
				uiLink = uiLink.replace(NetDisk.noAccessCodeRegExp, "");
				logCallBack({
					status: true,
					msg: [
						`正则: 内置的noAccessCodeRegExp`,
						"作用: 因accessCode为空,使用该正则去除不需要的字符串",
						`结果: ${uiLink}`,
					],
				});
			}
			if (regular.paramMatch) {
				if (utils.isNotNull(matchText)) {
					let paramMatchArray = matchText.match(regular.paramMatch);
					let replaceParamData = {};
					for (let index = 0; index < paramMatchArray.length; index++) {
						replaceParamData[`$${index}`] = paramMatchArray[index];
					}
					uiLink = NetDisk.replaceParam(uiLink, replaceParamData);
					logCallBack({
						status: true,
						msg: [
							`正则: paramMatch`,
							`作用: 用于对matchText进行提取需要的关键内容,替换关键字:{#$1#}、{#$2#}...`,
							`参数: ` + JSON.stringify(replaceParamData, void 0, 4),
							`结果: ${uiLink}`,
						],
					});
				}
			}

			logCallBack({
				status: true,
				msg: "处理完毕的uiLink: " + uiLink,
			});
			return uiLink;
		},
		/**
		 * 获取新标签页打开的URL
		 * @param {string} matchText 匹配到的文本
		 * @param {NetDiskRegularOption} regular 当前执行的规则
		 * @param {string} shareCode 分享码
		 * @param {string} accessCode 访问码
		 * @param {(logData: NetDiskDebugLogData)=>void} logCallBack 日志回调
		 */
		handleBlank(matchText, regular, shareCode, accessCode, logCallBack) {
			let blankUrl = NetDisk.replaceParam(regular["blank"], {
				shareCode: shareCode,
			});
			logCallBack({
				status: true,
				msg: [
					`正则: blank`,
					"作用: 用于点击跳转的链接",
					"备注: 对shareCode进行参数替换",
					`结果: ${blankUrl}`,
				],
			});
			if (accessCode && accessCode != "") {
				blankUrl = NetDisk.replaceParam(blankUrl, {
					accessCode: accessCode,
				});
				logCallBack({
					status: true,
					msg: [
						`正则: blank`,
						"作用: 用于点击跳转的链接",
						"备注: 对accessCode进行参数替换",
						`结果: ${blankUrl}`,
					],
				});
			} else {
				blankUrl = blankUrl.replace(NetDisk.noAccessCodeRegExp, "");
				logCallBack({
					status: true,
					msg: [
						`正则: 内置的noAccessCodeRegExp`,
						"作用: 因accessCode为空,使用该正则去除不需要的字符串",
						`结果: ${blankUrl}`,
					],
				});
			}
			if (regular.paramMatch) {
				if (utils.isNotNull(matchText)) {
					let paramMatchArray = matchText.match(regular.paramMatch);
					let replaceParamData = {};
					for (let index = 0; index < paramMatchArray.length; index++) {
						replaceParamData[`$${index}`] = paramMatchArray[index];
					}
					blankUrl = NetDisk.replaceParam(blankUrl, replaceParamData);
					logCallBack({
						status: true,
						msg: [
							`正则: paramMatch`,
							`作用: 用于对matchText进行提取需要的关键内容,替换关键字:{#$1#}、{#$2#}...`,
							`参数: ` + JSON.stringify(replaceParamData, void 0, 4),
							`结果: ${blankUrl}`,
						],
					});
				}
			}

			logCallBack({
				status: true,
				msg: "处理完毕的blank: " + blankUrl,
			});
			return blankUrl;
		},
		/**
		 * 获取复制到剪贴板的字符串
		 * @param {string} matchText 匹配到的文本
		 * @param {NetDiskRegularOption} regular 当前执行的规则
		 * @param {string} shareCode 分享码
		 * @param {string} accessCode 访问码
		 * @param {(logData: NetDiskDebugLogData)=>void} logCallBack 日志回调
		 */
		handleCopyUrl(matchText, regular, shareCode, accessCode, logCallBack) {
			let copyUrl = NetDisk.replaceParam(regular["copyUrl"], {
				shareCode: shareCode,
			});
			logCallBack({
				status: true,
				msg: [
					`正则: copyUrl`,
					"作用: 用于复制到剪贴板的链接",
					"备注: 对shareCode进行参数替换",
					`结果: ${copyUrl}`,
				],
			});
			if (accessCode && accessCode != "") {
				copyUrl = NetDisk.replaceParam(copyUrl, {
					accessCode: accessCode,
				});
				logCallBack({
					status: true,
					msg: [
						`正则: copyUrl`,
						"作用: 用于复制到剪贴板的链接",
						"备注: 对accessCode进行参数替换",
						`结果: ${copyUrl}`,
					],
				});
			} else {
				copyUrl = copyUrl.replace(NetDisk.noAccessCodeRegExp, "");
				logCallBack({
					status: true,
					msg: [
						`正则: 内置的noAccessCodeRegExp`,
						"作用: 因accessCode为空,使用该正则去除不需要的字符串",
						`结果: ${copyUrl}`,
					],
				});
			}
			if (regular.paramMatch) {
				if (utils.isNotNull(matchText)) {
					let paramMatchArray = matchText.match(regular.paramMatch);
					let replaceParamData = {};
					for (let index = 0; index < paramMatchArray.length; index++) {
						replaceParamData[`$${index}`] = paramMatchArray[index];
					}
					copyUrl = NetDisk.replaceParam(copyUrl, replaceParamData);
					logCallBack({
						status: true,
						msg: [
							`正则: paramMatch`,
							`作用: 用于对matchText进行提取需要的关键内容,替换关键字:{#$1#}、{#$2#}...`,
							`参数: ` + JSON.stringify(replaceParamData, void 0, 4),
							`结果: ${copyUrl}`,
						],
					});
				}
			}

			logCallBack({
				status: true,
				msg: "处理完毕的copyUrl: " + copyUrl,
			});
			return copyUrl;
		},
	};

	/** 网盘-校验链接有效性 */
	const NetDiskCheckLinkValidity = {
		$data: {
			isSubscribing: false,
			/**
			 * @type {NetDiskCheckLinkValidityOption[]}
			 */
			subscribe: [],
		},
		/**
		 * 网盘检查的状态码
		 */
		status: {
			loading: {
				code: 1,
				msg: "验证中",
				setView(ele, checkInfo) {
					NetDiskCheckLinkValidity.setViewCheckValid(ele, "loading");
					ele.innerHTML = pops.config.iconSVG.loading;
				},
			},
			success: {
				code: 200,
				msg: "该链接有效",
				setView(ele, checkInfo) {
					NetDiskCheckLinkValidity.setViewCheckValid(ele, "success");
					ele.innerHTML = /*html*/ `
					<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
						<path
						fill="currentColor"
						d="M874.119618 149.859922A510.816461 510.816461 0 0 0 511.997 0.00208a509.910462 509.910462 0 0 0-362.119618 149.857842c-199.817789 199.679789-199.817789 524.581447 0 724.260236a509.969462 509.969462 0 0 0 362.119618 149.857842A508.872463 508.872463 0 0 0 874.119618 874.120158c199.836789-199.679789 199.836789-524.581447 0-724.260236zM814.94268 378.210681L470.999043 744.132295a15.359984 15.359984 0 0 1-5.887994 4.095996c-1.751998 1.180999-2.913997 2.362998-5.276994 2.913997a34.499964 34.499964 0 0 1-13.469986 2.914997 45.547952 45.547952 0 0 1-12.897986-2.303998l-4.095996-2.363997a45.291952 45.291952 0 0 1-7.009992-4.095996l-196.902793-193.789796a34.126964 34.126964 0 0 1-10.555989-25.186973c0-9.37399 3.583996-18.74698 9.98399-25.186974a36.429962 36.429962 0 0 1 50.372947 0l169.98382 167.423824L763.389735 330.220732a37.059961 37.059961 0 0 1 50.371947-1.732998 33.647965 33.647965 0 0 1 11.165988 25.186973 35.544963 35.544963 0 0 1-9.98399 24.575974v-0.04z m0 0"></path>
					</svg>
					`;
					NetDiskCheckLinkValidity.setViewAgainCheckClickEvent(ele, checkInfo);
				},
			},
			/**
			 * @type {NetDiskCheckLinkValidityStatus}
			 */
			error: {
				code: -404,
				msg: "网络异常",
				setView(ele, checkInfo) {
					NetDiskCheckLinkValidity.setViewCheckValid(ele, "error");
					ele.innerHTML = /*html*/ `
					<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
						<path
						fill="currentColor"
						d="M511.808 692.224c-18.048 0-35.136 3.968-50.432 11.392-25.472 12.416-46.528 33.92-57.792 60.032-5.632 14.144-9.024 29.504-9.024 45.952 0 65.152 52.672 117.824 117.248 117.824 65.28 0 117.952-52.672 117.952-117.824 0-64.64-52.672-117.376-117.952-117.376z m0 178.496c-33.408 0-60.608-27.712-60.608-61.12 0-33.472 27.2-60.672 60.608-60.672s61.248 27.2 61.248 60.672c0 33.472-27.776 61.12-61.248 61.12zM286.784 661.632c3.968 3.392 8.512 5.632 12.992 5.632L438.08 523.328c-60.032 14.72-114.432 49.344-155.328 98.624-9.536 11.84-7.872 30.08 4.032 39.68zM622.912 534.656l-43.008 45.312c45.312 13.056 86.72 40.256 117.376 78.208 5.632 6.784 13.568 10.24 22.08 10.24 6.272 0 12.416-2.24 18.176-6.784 11.904-9.6 13.568-27.84 3.392-39.68-31.808-39.104-72.704-69.12-118.016-87.296zM511.808 391.168c17.024 0 33.408 1.216 49.856 3.456l47.68-49.856c-31.744-6.848-64.064-10.24-97.536-10.24-142.784 0-277.12 63.488-367.232 174.656-10.24 11.904-8.576 30.08 3.904 39.68 5.12 4.48 11.328 6.784 18.176 6.784 7.936 0 15.872-3.968 21.568-10.816 79.872-97.536 197.76-153.664 323.584-153.664zM751.616 400.32l-40.256 41.92c47.04 24.96 89.536 60.032 124.096 102.592 10.24 12.48 27.84 14.208 40.256 3.968 11.968-9.6 13.632-27.84 3.968-39.68-36.16-44.8-79.872-81.088-128.064-108.8zM705.152 244.928l42.56-44.672c-73.664-28.992-153.6-44.224-235.904-44.224-196.672 0-380.864 87.872-505.6 239.744-9.6 12.48-7.872 30.08 3.968 40.256 5.632 3.968 11.904 6.208 18.112 6.208 7.936 0 16.448-3.392 22.144-10.176C163.84 292.608 332.096 212.672 511.808 212.672c66.944 0 132.16 10.752 193.344 32.256zM1017.472 395.776c-40.192-49.92-87.296-92.416-139.456-126.976l-39.68 41.344C889.408 343.04 935.36 383.808 973.888 432c9.6 11.904 27.776 13.568 39.68 3.968 11.84-10.176 14.144-27.712 3.904-40.192zM937.408 104.512c-11.328-10.944-29.312-10.496-40.064 0.832L179.008 854.72c-10.816 11.328-10.496 29.248 0.896 40.064 5.44 5.312 12.48 7.872 19.584 7.872 7.488 0 14.848-2.88 20.416-8.704L938.24 144.576c10.88-11.328 10.496-29.248-0.832-40.064z"></path>
					</svg>
					`;
					NetDiskCheckLinkValidity.setViewAgainCheckClickEvent(ele, checkInfo);
				},
			},
			/** 该链接已失效 */
			failed: {
				code: 0,
				msg: "该链接已失效",
				setView(ele, checkInfo) {
					NetDiskCheckLinkValidity.setViewCheckValid(ele, "failed");
					ele.innerHTML = /*html*/ `
					<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
						<path
							fill="currentColor"
							d="M549.044706 512l166.189176-166.249412a26.383059 26.383059 0 0 0 0-36.98447 26.383059 26.383059 0 0 0-37.044706 0L512 475.015529l-166.249412-166.249411a26.383059 26.383059 0 0 0-36.98447 0 26.383059 26.383059 0 0 0 0 37.044706L475.015529 512l-166.249411 166.249412a26.383059 26.383059 0 0 0 0 36.98447 26.383059 26.383059 0 0 0 37.044706 0L512 548.984471l166.249412 166.249411a26.383059 26.383059 0 0 0 36.98447 0 26.383059 26.383059 0 0 0 0-37.044706L548.984471 512zM512 1024a512 512 0 1 1 0-1024 512 512 0 0 1 0 1024z"></path>
					</svg>
					`;
					NetDiskCheckLinkValidity.setViewAgainCheckClickEvent(ele, checkInfo);
				},
			},
			needAccessCode: {
				code: 201,
				msg: "该链接缺失提取码",
				setView(ele, checkInfo) {
					NetDiskCheckLinkValidity.setViewCheckValid(ele, "needAccessCode");
					ele.innerHTML = /*html*/ `
					<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
						<path
						fill="currentColor"
						d="M757.810429 373.751333 325.645708 373.751333l0-83.895759c0-103.694687 81.507362-184.922686 185.559183-184.922686 78.121242 0 146.053424 46.74565 173.062568 119.090329 3.865028 10.352789 15.384385 15.609513 25.742291 11.746532 10.351766-3.866051 15.609513-15.390525 11.744485-25.742291C688.844707 121.877815 606.198405 64.918545 511.204891 64.918545c-61.918211 0-119.246895 23.662933-161.423483 66.63156-41.3692 42.142819-64.151066 98.363262-64.151066 158.305469l0 83.895759-20.007683 0c-60.774155 0-110.042255 49.267077-110.042255 110.042255l0 366.139981c0 60.774155 49.267077 110.042255 110.042255 110.042255l492.187769 0c60.775178 0 110.042255-49.267077 110.042255-110.042255L867.852684 483.793588C867.852684 423.01841 818.585607 373.751333 757.810429 373.751333zM827.837318 849.933569c0 38.674834-31.352055 70.02689-70.02689 70.02689L265.62266 919.960459c-38.674834 0-70.02689-31.352055-70.02689-70.02689L195.59577 483.793588c0-38.674834 31.352055-70.02689 70.02689-70.02689l492.187769 0c38.674834 0 70.02689 31.352055 70.02689 70.02689L827.837318 849.933569z"></path>
						<path
						fill="currentColor"
						d="M509.715981 583.832002c-11.048637 0-20.007683 8.959046-20.007683 20.007683l0 110.042255c0 11.048637 8.958022 20.007683 20.007683 20.007683s20.007683-8.958022 20.007683-20.007683L529.723663 603.839685C529.723663 592.790024 520.765641 583.832002 509.715981 583.832002z"></path>
					</svg>
					`;
					NetDiskCheckLinkValidity.setViewAgainCheckClickEvent(ele, checkInfo);
				},
			},
			unknown: {
				code: -200,
				msg: "未知检查情况",
				setView(ele, checkInfo) {
					NetDiskCheckLinkValidity.setViewCheckValid(ele, "unknown");
					ele.innerHTML = /*html*/ `
					<svg viewBox="0 0 1025 1024" xmlns="http://www.w3.org/2000/svg">
						<path
						fill="currentColor"
						d="M512.473172 1023.995242A511.814852 511.814852 0 0 1 313.545134 40.351073a512.244696 512.244696 0 0 1 398.855715 943.658633 508.815937 508.815937 0 0 1-199.927677 39.985536z m0-943.658634C274.559237 80.336608 80.629391 274.266455 80.629391 512.18039s193.929846 431.843781 431.843781 431.843781 431.843781-193.929846 431.843781-431.843781S751.386745 80.336608 512.473172 80.336608z"></path>
						<path
						fill="currentColor"
						d="M506.475342 716.10662a39.985535 39.985535 0 0 1-39.985536-39.985535v-76.972156c0-79.971071 64.976495-144.947566 144.947566-144.947565a77.971794 77.971794 0 0 0 0-155.943588H445.4974a56.979388 56.979388 0 0 0-56.979387 56.979388 39.985535 39.985535 0 0 1-79.971071 0c0-74.972879 60.977941-136.950458 136.950458-136.950459h164.940333c86.968539 0 157.942864 70.974325 157.942865 157.942865s-69.974687 157.942864-157.942865 157.942864a64.976495 64.976495 0 0 0-64.976494 64.976495v76.972156a39.985535 39.985535 0 0 1-38.985897 39.985535zM505.475703 742.097218a48.982281 48.982281 0 1 0 48.982281 48.982281 48.982281 48.982281 0 0 0-48.982281-48.982281z"></path>
					</svg>
					`;
					NetDiskCheckLinkValidity.setViewAgainCheckClickEvent(ele, checkInfo);
				},
			},
		},
		netDisk: {
			baidu: {
				/**
				 * @param {number} netDiskIndex 网盘名称索引下标
				 * @param {string} shareCode 分享码
				 * @param {string} accessCode 访问码
				 */
				async init(netDiskIndex, shareCode, accessCode) {
					let url = NetDiskParse.getBlankUrl(
						"baidu",
						netDiskIndex,
						shareCode,
						accessCode
					);
					let getResp = await httpx.get(url, {
						headers: {
							"User-Agent": utils.getRandomPCUA(),
							Host: "pan.baidu.com",
							Referer: url,
							Origin: "https://pan.baidu.com",
						},
						onerror() {},
						ontimeout() {},
					});
					let responseText = getResp.data.responseText;
					if (!getResp.status) {
						if (utils.isNull(responseText)) {
							return NetDiskCheckLinkValidity.status.error;
						}
					}
					if (getResp.data.finalUrl.includes("404.html")) {
						return NetDiskCheckLinkValidity.status.error;
					}
					if (responseText.includes("过期时间:")) {
						return NetDiskCheckLinkValidity.status.success;
					} else if (responseText.includes("输入提取")) {
						return NetDiskCheckLinkValidity.status.needAccessCode;
					} else if (
						responseText.includes("不存在") ||
						responseText.includes("已失效")
					) {
						return NetDiskCheckLinkValidity.status.failed;
					} else {
						return NetDiskCheckLinkValidity.status.unknown;
					}
				},
			},
			lanzou: {
				/**
				 * @param {number} netDiskIndex 网盘名称索引下标
				 * @param {string} shareCode 分享码
				 * @param {string} accessCode 访问码
				 */
				async init(netDiskIndex, shareCode, accessCode) {
					let url = NetDiskParse.getBlankUrl(
						"lanzou",
						netDiskIndex,
						shareCode,
						accessCode
					);
					let urlObj = new URL(url);

					let getResp = await httpx.get(url, {
						headers: {
							"User-Agent": utils.getRandomPCUA(),
							Host: urlObj.hostname,
							Origin: urlObj.origin,
							Referer: url,
						},
						onerror() {},
						ontimeout() {},
					});
					if (!getResp.status) {
						return NetDiskCheckLinkValidity.status.error;
					}
					let data = getResp.data.responseText;
					if (utils.isNull(data)) {
						return NetDiskCheckLinkValidity.status.failed;
					} else if (data.includes("输入密码")) {
						return NetDiskCheckLinkValidity.status.needAccessCode;
					} else if (data.includes("来晚啦") || data.includes("不存在")) {
						return NetDiskCheckLinkValidity.status.failed;
					} else {
						return NetDiskCheckLinkValidity.status.success;
					}
				},
			},
			lanzouyx: {
				/**
				 * @param {number} netDiskIndex 网盘名称索引下标
				 * @param {string} shareCode 分享码
				 * @param {string} accessCode 访问码
				 */
				async init(netDiskIndex, shareCode, accessCode) {
					let LanZouYX = new NetDiskParse.netDisk.lanzouyx();
					LanZouYX.uuid = LanZouYX.getEncodeUUID();
					LanZouYX.shareCodeId = LanZouYX.getDecodeShareCodeId(shareCode);
					let devType = 3;
					let devModel = "Chrome";
					let extra = 2;
					let timestamp = LanZouYX.getEncodeTimeStamp();
					let type = 0;

					let offset = 1;
					let limit = 60;
					let postResp = await httpx.post(
						`https://api.ilanzou.com/unproved/recommend/list?devType=${devType}&devModel=${devModel}&uuid=${LanZouYX.uuid}&extra=${extra}&timestamp=${timestamp}&shareId=${LanZouYX.shareCodeId}&type=${type}&offset=${offset}&limit=${limit}`,
						{
							headers: {
								Accept: "application/json, text/plain, */*",
								Origin: "https://www.ilanzou.com",
								Referer: "https://www.ilanzou.com/",
								"Sec-Fetch-Site": "same-site",
								Host: "api.ilanzou.com",
								"User-Agent": utils.getRandomPCUA(),
							},
							responseType: "json",
							onerror() {},
							ontimeout() {},
						}
					);
					if (!postResp.status) {
						return NetDiskCheckLinkValidity.status.error;
					}
					let data = utils.toJSON(postResp.data.responseText);
					log.success(["获取链接信息:", data]);
					if (data["code"] !== 200) {
						return NetDiskCheckLinkValidity.status.error;
					}
					if (!data["list"].length) {
						return NetDiskCheckLinkValidity.status.failed;
					}
					return NetDiskCheckLinkValidity.status.success;
				},
			},
			tianyiyun: {
				/**
				 * @param {number} netDiskIndex 网盘名称索引下标
				 * @param {string} shareCode 分享码
				 * @param {string} accessCode 访问码
				 */
				async init(netDiskIndex, shareCode, accessCode) {
					let postResp = await httpx.post(
						"https://api.cloud.189.cn/open/share/getShareInfoByCodeV2.action",
						{
							data: `shareCode=${shareCode}`,
							headers: {
								Accept: "application/json;charset=UTF-8",
								"Content-Type": "application/x-www-form-urlencoded",
								"User-Agent": utils.getRandomPCUA(),
								"Sign-Type": 1,
								Referer: "https://cloud.189.cn/web/share?code=" + shareCode,
								Origin: "https://cloud.189.cn",
							},
							onerror() {},
							ontimeout() {},
						}
					);
					let responseText = postResp.data.responseText;
					if (!postResp.status && utils.isNull(responseText)) {
						return NetDiskCheckLinkValidity.status.error;
					}
					if (
						responseText.includes("ShareInfoNotFound") ||
						responseText.includes("ShareNotFound") ||
						responseText.includes("FileNotFound") ||
						responseText.includes("ShareAuditWaiting") ||
						responseText.includes("ShareExpiredError") ||
						responseText.includes("ShareAuditNotPass")
					) {
						return NetDiskCheckLinkValidity.status.failed;
					}
					if (responseText.includes("needAccessCode")) {
						return NetDiskCheckLinkValidity.status.needAccessCode;
					}
					return NetDiskCheckLinkValidity.status.success;
				},
			},
			hecaiyun: {
				/**
				 * @param {number} netDiskIndex 网盘名称索引下标
				 * @param {string} shareCode 分享码
				 * @param {string} accessCode 访问码
				 */
				async init(netDiskIndex, shareCode, accessCode) {
					let resp = await httpx.post(
						"https://caiyun.139.com/stapi/custom/outlink/brief",
						{
							data: "linkId=" + shareCode,
							headers: {
								"Content-Type": "application/x-www-form-urlencoded",
								"User-Agent": utils.getRandomPCUA(),
								Host: "caiyun.139.com",
								Referer: NetDiskParse.getBlankUrl(
									"hecaiyun",
									netDiskIndex,
									shareCode,
									accessCode
								),
								Origin: "https://caiyun.139.com",
							},
							ontimeout() {},
							onerror() {},
						}
					);
					if (!resp.status) {
						return NetDiskCheckLinkValidity.status.error;
					}
					let data = utils.toJSON(resp.data.responseText);
					if (data.code == 0) {
						if (data.data.isPasswd === "1") {
							return NetDiskCheckLinkValidity.status.needAccessCode;
						} else {
							return NetDiskCheckLinkValidity.status.success;
						}
					} else {
						return NetDiskCheckLinkValidity.status.failed;
					}
				},
			},
			aliyun: {
				/**
				 * @param {number} netDiskIndex 网盘名称索引下标
				 * @param {string} shareCode 分享码
				 * @param {string} accessCode 访问码
				 */
				async init(netDiskIndex, shareCode, accessCode) {
					let postResp = await httpx.post(
						"https://api.aliyundrive.com/adrive/v3/share_link/get_share_by_anonymous?share_id=" +
							shareCode,
						{
							data: JSON.stringify({
								share_id: shareCode,
							}),
							headers: {
								Accept: "application/json, text/plain, */*",
								"Content-Type": "application/json",
								"User-Agent": utils.getRandomPCUA(),
								Referer: "https://www.aliyundrive.com/",
								Origin: "https://www.aliyundrive.com",
							},
							onerror() {},
							ontimeout() {},
						}
					);
					let data = utils.toJSON(postResp.data.responseText);
					if (!postResp.status && utils.isNull(data)) {
						return NetDiskCheckLinkValidity.status.error;
					}
					if (
						data["code"] === "ParamFlowException" ||
						data["code"] === "NotFound.ShareLink" ||
						data["code"] === "ShareLink.Cancelled"
					) {
						return NetDiskCheckLinkValidity.status.failed;
					} else if (
						data["file_count"] === 0 ||
						data["file_infos"]?.length === 0
					) {
						return NetDiskCheckLinkValidity.status.failed;
					}
					return NetDiskCheckLinkValidity.status.success;
				},
			},
			wenshushu: {
				/**
				 * @param {number} netDiskIndex 网盘名称索引下标
				 * @param {string} shareCode 分享码
				 * @param {string} accessCode 访问码
				 */
				async init(netDiskIndex, shareCode, accessCode) {
					let postResp = await httpx.post(
						"https://www.wenshushu.cn/ap/task/mgrtask",
						{
							data: JSON.stringify({
								tid: shareCode,
							}),
							headers: {
								"Content-Type": "application/json",
								"User-Agent": utils.getRandomPCUA(),
								"x-token": "wss:7pmakczzw6i",
								Host: "www.wenshushu.cn",
								Origin: "https://www.wenshushu.cn",
								Referer: NetDiskParse.getBlankUrl(
									"wenshushu",
									netDiskIndex,
									shareCode,
									accessCode
								),
							},
							responseType: "json",
							ontimeout() {},
							onerror() {},
						}
					);
					if (!postResp.status && utils.isNull(postResp.data.responseText)) {
						return NetDiskCheckLinkValidity.status.error;
					}
					let data = utils.toJSON(postResp.data.responseText);
					if (data.code !== 0) {
						return NetDiskCheckLinkValidity.status.failed;
					}
					return NetDiskCheckLinkValidity.status.success;
				},
			},
			nainiu: {
				/**
				 * @param {number} netDiskIndex 网盘名称索引下标
				 * @param {string} shareCode 分享码
				 * @param {string} accessCode 访问码
				 */
				async init(netDiskIndex, shareCode, accessCode) {
					let getResp = await httpx.get(
						"https://cowtransfer.com/core/api/transfer/share?uniqueUrl=" +
							shareCode,
						{
							headers: {
								"User-Agent": utils.getRandomPCUA(),
								Host: "cowtransfer.com",
								Origin: "https://cowtransfer.com/",
								Referer: "https://cowtransfer.com/",
							},
						}
					);
					if (!getResp.status && utils.isNull(getResp.data.responseText)) {
						return NetDiskCheckLinkValidity.status.error;
					}
					let data = utils.toJSON(getResp.data.responseText);
					if (data.code != "0000") {
						return NetDiskCheckLinkValidity.status.failed;
					}
					if (data.data.needPassword && data.data.needPassword) {
						return NetDiskCheckLinkValidity.status.needAccessCode;
					}
					return NetDiskCheckLinkValidity.status.success;
				},
			},
			_123pan: {
				/**
				 * @param {number} netDiskIndex 网盘名称索引下标
				 * @param {string} shareCode 分享码
				 * @param {string} accessCode 访问码
				 */
				async init(netDiskIndex, shareCode, accessCode) {
					let getResp = await httpx.get(
						"https://www.123pan.com/api/share/info?shareKey=" + shareCode,
						{
							headers: {
								"User-Agent": utils.getRandomPCUA(),
								Host: "www.123pan.com",
								Origin: "https://www.123pan.com/",
								Referer: "https://www.123pan.com/",
							},
							onerror() {},
							ontimeout() {},
							responseType: "json",
						}
					);
					if (!getResp.status && utils.isNull(getResp.data.responseText)) {
						return NetDiskCheckLinkValidity.status.error;
					}
					let data = utils.toJSON(getResp.data.responseText);
					if (
						getResp.data.responseText.includes("分享页面不存在") ||
						data["code"] !== 0
					) {
						return NetDiskCheckLinkValidity.status.failed;
					}
					if (data["data"]["HasPwd"]) {
						return NetDiskCheckLinkValidity.status.needAccessCode;
					}
					return NetDiskCheckLinkValidity.status.success;
				},
			},
			weiyun: {
				/**
				 * @param {number} netDiskIndex 网盘名称索引下标
				 * @param {string} shareCode 分享码
				 * @param {string} accessCode 访问码
				 */
				async init(netDiskIndex, shareCode, accessCode) {
					let url = NetDiskParse.getBlankUrl(
						"weiyun",
						netDiskIndex,
						shareCode,
						accessCode
					);
					let getResp = await httpx.get(url, {
						headers: {
							"User-Agent": utils.getRandomPCUA(),
							Host: "share.weiyun.com",
							Origin: "https://share.weiyun.com",
							Referer: url,
						},
						onerror() {},
						ontimeout() {},
					});

					if (!getResp.status && utils.isNull(getResp.data.responseText)) {
						return NetDiskCheckLinkValidity.status.error;
					}
					let respText = getResp.data.responseText;
					if (
						respText.includes("已删除") ||
						respText.includes("违反相关法规") ||
						respText.includes("已过期") ||
						respText.includes("已经删除") ||
						respText.includes("目录无效")
					) {
						return NetDiskCheckLinkValidity.status.failed;
					}
					if (
						respText.includes('"need_pwd":1') ||
						respText.includes('"pwd":"')
					) {
						return NetDiskCheckLinkValidity.status.needAccessCode;
					}
					return NetDiskCheckLinkValidity.status.success;
				},
			},
			xunlei: {
				/**
				 * @param {number} netDiskIndex 网盘名称索引下标
				 * @param {string} shareCode 分享码
				 * @param {string} accessCode 访问码
				 */
				async init(netDiskIndex, shareCode, accessCode) {
					let postResp = await httpx.post(
						"https://xluser-ssl.xunlei.com/v1/shield/captcha/init",
						{
							data: JSON.stringify({
								client_id: "Xqp0kJBXWhwaTpB6",
								device_id: "925b7631473a13716b791d7f28289cad",
								action: "get:/drive/v1/share",
								meta: {
									package_name: "pan.xunlei.com",
									client_version: "1.45.0",
									captcha_sign: "1.fe2108ad808a74c9ac0243309242726c",
									timestamp: "1645241033384",
								},
							}),
							headers: {
								"User-Agent": utils.getRandomPCUA(),
								Host: "pan.xunlei.com",
								Referer: NetDiskParse.getBlankUrl(
									"xunlei",
									netDiskIndex,
									shareCode,
									accessCode
								),
								Origin: "https://pan.xunlei.com",
							},
							onerror() {},
							ontimeout() {},
						}
					);
					if (!postResp.status && utils.isNull(postResp.data.responseText)) {
						return NetDiskCheckLinkValidity.status.error;
					}
					let data = utils.toJSON(postResp.data.responseText);
					let token = data["captcha_token"];
					let getResp = await httpx.get(
						"https://api-pan.xunlei.com/drive/v1/share?share_id=" + shareCode,
						{
							headers: {
								"User-Agent": utils.getRandomPCUA(),
								Host: "pan.xunlei.com",
								Referer: NetDiskParse.getBlankUrl(
									"xunlei",
									netDiskIndex,
									shareCode,
									accessCode
								),
								Origin: "https://pan.xunlei.com",
								"x-captcha-token": token,
								"x-client-id": "Xqp0kJBXWhwaTpB6",
								"x-device-id": "925b7631473a13716b791d7f28289cad",
							},
							onerror() {},
							ontimeout() {},
						}
					);

					if (!getResp.status && utils.isNull(getResp.data.responseText)) {
						return NetDiskCheckLinkValidity.status.error;
					}
					let responseText = getResp.data.responseText;
					if (
						responseText.includes("NOT_FOUND") ||
						responseText.includes("SENSITIVE_RESOURCE") ||
						responseText.includes("EXPIRED") ||
						responseText.includes("DELETED")
					) {
						return NetDiskCheckLinkValidity.status.failed;
					} else if (responseText.includes("PASS_CODE_EMPTY")) {
						return NetDiskCheckLinkValidity.status.needAccessCode;
					}
					return NetDiskCheckLinkValidity.status.success;
				},
			},
			_115pan: {
				/**
				 * @param {number} netDiskIndex 网盘名称索引下标
				 * @param {string} shareCode 分享码
				 * @param {string} accessCode 访问码
				 */
				async init(netDiskIndex, shareCode, accessCode) {
					let getResp = await httpx.get(
						`https://webapi.115.com/share/snap?share_code=${shareCode}&offset=0&limit=20&receive_code=&cid=`,
						{
							headers: {
								Accept: "application/json, text/javascript, */*;",
								"User-Agent": utils.getRandomPCUA(),
								Host: "webapi.115.com",
								Referer: "https://115.com/",
								Origin: "https://115.com",
							},
							ontimeout() {},
							onerror() {},
						}
					);
					if (!getResp.status) {
						if (utils.isNull(getResp.data.responseText)) {
							return NetDiskCheckLinkValidity.status.failed;
						}
						return NetDiskCheckLinkValidity.status.error;
					}
					let data = utils.toJSON(getResp.data.responseText);
					if (data.state) {
						return NetDiskCheckLinkValidity.status.success;
					}
					if (typeof data.error === "string") {
						if (data.error.includes("访问码")) {
							return NetDiskCheckLinkValidity.status.needAccessCode;
						} else if (
							data.error.includes("链接") ||
							data.error.includes("分享已取消")
						) {
							return NetDiskCheckLinkValidity.status.failed;
						}
					}

					return NetDiskCheckLinkValidity.status.unknown;
				},
			},
			chengtong: {
				/**
				 * @param {number} netDiskIndex 网盘名称索引下标
				 * @param {string} shareCode 分享码
				 * @param {string} accessCode 访问码
				 */
				async init(netDiskIndex, shareCode, accessCode) {
					/* 城通通用的检查api */
					/* ref是来源 */
					let blankUrl = NetDiskParse.getBlankUrl(
						"chengtong",
						netDiskIndex,
						shareCode,
						accessCode
					);
					let blankUrlObj = new URL(blankUrl);
					/* f是文件 d是文件夹 */
					const path = blankUrlObj.pathname.split("/")[1].trim();
					let url = "";
					if (path === "f" || path === "file") {
						/* 文件 */
						url = `https://webapi.ctfile.com/getfile.php?path=${path}&f=${shareCode}&passcode=${accessCode}&token=0&r=${Math.random()}&ref=`;
					} else if (path === "d" || path === "dir") {
						/* 文件夹 */
						url = `https://webapi.ctfile.com/getdir.php?path=${path}&d=${shareCode}&folder_id=&passcode=${accessCode}&token=0&r=${Math.random()}&ref=`;
					} else {
						log.warn("未知path", [netDiskIndex, shareCode, accessCode]);
						return NetDiskCheckLinkValidity.status.unknown;
					}
					let getResp = await httpx.get(url, {
						headers: {
							Host: "webapi.ctfile.com",
							Origin: "https://url95.ctfile.com",
							Referer: blankUrl,
							Accept: "application/json, text/javascript, */*; q=0.01",
							"User-Agent": utils.getRandomPCUA(),
						},
						ontimeout() {},
						onerror() {},
					});
					let responseText = getResp.data.responseText;
					if (!getResp.status && utils.isNull(responseText)) {
						return NetDiskCheckLinkValidity.status.error;
					}
					let data = utils.toJSON(responseText);
					if (data["code"] === 200) {
						return NetDiskCheckLinkValidity.status.success;
					}
					if (data["code"] === 401) {
						return NetDiskCheckLinkValidity.status.needAccessCode;
					}
					if (data["code"] === 404 || data["code"] === 503) {
						return NetDiskCheckLinkValidity.status.failed;
					}
					return NetDiskCheckLinkValidity.status.unknown;
				},
			},
			kuake: {
				/**
				 * @param {number} netDiskIndex 网盘名称索引下标
				 * @param {string} shareCode 分享码
				 * @param {string} accessCode 访问码
				 */
				async init(netDiskIndex, shareCode, accessCode) {
					let url =
						"https://drive.quark.cn/1/clouddrive/share/sharepage/token?pr=ucpro&fr=pc";
					let postResp = await httpx.post(url, {
						data: JSON.stringify({
							pwd_id: shareCode,
							passcode: "",
						}),
						headers: {
							Accept: "application/json, text/plain, */*",
							"Content-Type": "application/json;charset=UTF-8",
							"User-Agent": utils.getRandomPCUA(),
							Origin: "https://pan.quark.cn",
							Referer: NetDiskParse.getBlankUrl(
								"kuake",
								netDiskIndex,
								shareCode,
								accessCode
							),
						},
						onerror() {},
						ontimeout() {},
					});
					if (!postResp.status && utils.isNull(postResp.data.responseText)) {
						return NetDiskCheckLinkValidity.status.error;
					}
					let data = utils.toJSON(postResp.data.responseText);
					if (data.message.includes("需要提取码")) {
						return NetDiskCheckLinkValidity.status.needAccessCode;
					} else if (data.message.includes("ok")) {
						return NetDiskCheckLinkValidity.status.success;
					} else {
						return NetDiskCheckLinkValidity.status.failed;
					}
				},
			},
			jianguoyun: {
				/**
				 * @param {number} netDiskIndex 网盘名称索引下标
				 * @param {string} shareCode 分享码
				 * @param {string} accessCode 访问码
				 */
				async init(netDiskIndex, shareCode, accessCode) {
					let url = NetDiskParse.getBlankUrl(
						"jianguoyun",
						netDiskIndex,
						shareCode,
						accessCode
					);
					let getResp = await httpx.get(url, {
						headers: {
							"User-Agent": utils.getRandomPCUA(),
							Host: "www.jianguoyun.com",
							Referer: NetDiskParse.getBlankUrl(
								"jianguoyun",
								netDiskIndex,
								shareCode,
								accessCode
							),
							Origin: "https://www.jianguoyun.com",
						},
						onerror() {},
						ontimeout() {},
					});
					let responseText = getResp.data.responseText;
					if (!getResp.status && utils.isNull(responseText)) {
						return NetDiskCheckLinkValidity.status.error;
					}
					if (responseText.includes("<h1>啊噢!")) {
						return NetDiskCheckLinkValidity.status.failed;
					}
					return NetDiskCheckLinkValidity.status.success;
				},
			},
			onedrive: {
				/**
				 * @param {number} netDiskIndex 网盘名称索引下标
				 * @param {string} shareCode 分享码
				 * @param {string} accessCode 访问码
				 */
				async init(netDiskIndex, shareCode, accessCode) {
					let url = NetDiskParse.getBlankUrl(
						"onedrive",
						netDiskIndex,
						shareCode,
						accessCode
					);
					let urlObj = new URL(url);
					let getResp = await httpx.get(url, {
						headers: {
							"User-Agent": utils.getRandomPCUA(),
							Host: urlObj.hostname,
							Referer: url,
							Origin: urlObj.origin,
						},
						onerror() {},
						ontimeout() {},
					});
					if (!getResp.status) {
						let status = getResp.data?.status?.toString();
						if (status === "429") {
							return NetDiskCheckLinkValidity.status.error;
						} else if (status === "404") {
							return NetDiskCheckLinkValidity.status.failed;
						}
						return NetDiskCheckLinkValidity.status.error;
					}
					let responseText = getResp.data.responseText;
					if (utils.isNotNull(responseText)) {
						try {
							let respDOM = DOMUtils.parseHTML(responseText, true, true);
							if (respDOM.querySelector("title")?.innerHTML?.includes("错误")) {
								return NetDiskCheckLinkValidity.status.failed;
							}
						} catch (error) {}
					}
					return NetDiskCheckLinkValidity.status.success;
				},
			},
			uc: {
				/**
				 * @param {number} netDiskIndex 网盘名称索引下标
				 * @param {string} shareCode 分享码
				 * @param {string} accessCode 访问码
				 */
				async init(netDiskIndex, shareCode, accessCode) {
					let resp = await httpx.get("https://drive.uc.cn/s/" + shareCode, {
						headers: {
							"User-Agent": utils.getRandomAndroidUA(),
							Host: "drive.uc.cn",
							Referer: NetDiskParse.getBlankUrl(
								"uc",
								netDiskIndex,
								shareCode,
								accessCode
							),
							Origin: "https://drive.uc.cn",
						},
						ontimeout() {},
						onerror() {},
					});
					let responseText = resp.data.responseText;
					if (!resp.status && utils.isNull(responseText)) {
						return NetDiskCheckLinkValidity.status.error;
					}
					let respDoc = DOMUtils.parseHTML(responseText, true, true);
					if (respDoc.querySelector(".h5-page-main")) {
						// 存在错误
						/** @type {HTMLDivElement} */
						let $h5PageMain = respDoc.querySelector(".h5-page-main");
						let errorText = $h5PageMain.textContent;
						if (
							errorText.includes("失效") ||
							errorText.includes("不存在") ||
							errorText.includes("违规") ||
							errorText.includes("删除")
						) {
							return NetDiskCheckLinkValidity.status.failed;
						} else {
							return NetDiskCheckLinkValidity.status.unknown;
						}
					} else if (respDoc.querySelector(".main-body .input-wrap input")) {
						return NetDiskCheckLinkValidity.status.needAccessCode;
					} else {
						return NetDiskCheckLinkValidity.status.success;
					}
				},
			},
		},
		/**
		 * 校验链接的有效性,这里是用于订阅-消费
		 * @param {HTMLDivElement} netDiskViewBox
		 * @param {string} netDiskName
		 * @param {number} netDiskIndex
		 * @param {string} shareCode
		 * @param {string} accessCode
		 */
		async check(
			netDiskViewBox,
			netDiskName,
			netDiskIndex,
			shareCode,
			accessCode
		) {
			this.$data.subscribe.push({
				netDiskViewBox,
				netDiskName,
				netDiskIndex,
				shareCode,
				accessCode,
			});

			if (this.$data.isSubscribing) {
				return;
			}
			this.$data.isSubscribing = true;
			for (let index = 0; index < this.$data.subscribe.length; index++) {
				const checkInfo = this.$data.subscribe[index];
				await this.checkLinkValidity(checkInfo, true);
				await utils.sleep(250);
				this.$data.subscribe.splice(index, 1);
				index--;
			}
			this.$data.isSubscribing = false;
		},
		/**
		 * 开始校验链接的有效性
		 * @param {NetDiskCheckLinkValidityOption} checkInfo
		 * @param {boolean} isForceCheck 是否强制检测
		 */
		async checkLinkValidity(checkInfo, isForceCheck) {
			let $netDiskStatus =
				checkInfo.netDiskViewBox.querySelector(".netdisk-status");
			if (this.isViewCheckValid($netDiskStatus) && !isForceCheck) {
				return;
			}
			let regular =
				NetDisk.regular[checkInfo.netDiskName][checkInfo.netDiskIndex];
			if (!regular["checkLinkValidity"]) {
				log.error(["未配置checkLinkValidity", checkInfo]);
				return;
			}
			let netDiskCheck = this.netDisk[checkInfo.netDiskName];
			if (
				!netDiskCheck ||
				(netDiskCheck && typeof netDiskCheck.init !== "function")
			) {
				/* 没有配置该网盘的校验有效性 */
				log.error(["没有配置该网盘的校验有效性", checkInfo]);
				return;
			}
			this.status.loading.setView($netDiskStatus);
			/**
			 * @type {NetDiskCheckLinkValidityStatus}
			 */
			let result = await netDiskCheck.init(
				checkInfo.netDiskIndex,
				checkInfo.shareCode,
				checkInfo.accessCode
			);
			if (!result) {
				log.error(["该验证函数的返回值不是有效值", [result, checkInfo]]);
				return;
			}
			result.setView($netDiskStatus, checkInfo);
		},
		/**
		 * 添加重复检查
		 * @param {HTMLDivElement} ele
		 * @param {NetDiskCheckLinkValidityOption} checkInfo
		 */
		setViewAgainCheckClickEvent(ele, checkInfo) {
			DOMUtils.on(
				ele,
				"click",
				void 0,
				function () {
					const $netDiskUrlDiv = ele.closest(".netdisk-url-div");
					const $netDiskLink = $netDiskUrlDiv.querySelector(".netdisk-link");
					const linkData = NetDiskUI.getElementNetDiskLinkData($netDiskLink);
					linkData["netDiskViewBox"] = checkInfo.netDiskViewBox;
					NetDiskCheckLinkValidity.checkLinkValidity(linkData, true);
				},
				{ once: true }
			);
		},
		/**
		 * 判断元素当前是否处于验证状态且验证是error或未验证状态
		 * + true 已验证(成功/需要密码)
		 * + false 尚未验证/验证超时/验证网络异常
		 * @param {HTMLDivElement} ele
		 */
		isViewCheckValid(ele) {
			if (!ele.hasAttribute("data-check-valid")) {
				return false;
			}
			if (ele.getAttribute("data-check-valid") === "error") {
				return false;
			}
			return true;
		},
		/**
		 * 设置当前的验证状态
		 * @param {HTMLDivElement} ele
		 * @param {string} value
		 */
		setViewCheckValid(ele, value) {
			ele.setAttribute("data-check-valid", value);
		},
		/**
		 * 取消设置当前的验证状态
		 * @param {HTMLDivElement} ele
		 */
		removeViewCheckValid(ele) {
			ele.removeAttribute("data-check-valid");
		},
		/**
		 * 判断状态码是成功的
		 * @param {NetDiskCheckLinkValidityStatus} statusInfo
		 */
		isStatusSuccess(statusInfo) {
			if (Math.floor(statusInfo.code / 100) === 2) {
				return true;
			}
			return false;
		},
		/**
		 * 根据code获取code的名字
		 * @param {NetDiskCheckLinkValidityStatus} statusInfo
		 */
		getStatusName(statusInfo) {
			for (const statusName of Object.keys(NetDiskCheckLinkValidity.status)) {
				let _statusInfo_ = NetDiskCheckLinkValidity.status[statusName];
				if (statusInfo.code === _statusInfo_.code) {
					return statusName;
				}
			}
		},
	};

	/** 网盘-直链解析 */
	const NetDiskParse = {
		netDisk: {
			/**
			 * 百度网盘
			 * @constructor
			 * @returns {object}
			 */
			baidu: function () {
				let that = this;
				/**
				 * 所在规则的下标
				 */
				this.netDiskIndex = 0;
				/**
				 * 分享码
				 */
				this.shareCode = "";
				/**
				 * 提取码
				 */
				this.accessCode = "";
				/**
				 * 入口
				 * @param {number} netDiskIndex 网盘名称索引下标
				 * @param {string} shareCode
				 * @param {string} accessCode
				 * @returns
				 */
				this.init = function (netDiskIndex, shareCode, accessCode) {
					log.info([netDiskIndex, shareCode, accessCode]);
					that.netDiskIndex = netDiskIndex;
					that.shareCode = shareCode;
					that.accessCode = accessCode;
					let url = GM_getValue("baidu-baiduwp-php-url");
					let postForm = GM_getValue("baidu-baiduwp-php-post-form");
					let enableCopy = GM_getValue("baidu-baiduwp-php-copy-url");
					if (!url) {
						Qmsg.error("请先在设置中配置百度网盘-网址");
						return void 0;
					}
					if (!postForm) {
						Qmsg.error("请先在设置中配置百度网盘-表单参数");
						return void 0;
					}
					postForm = NetDisk.replaceParam(postForm, {
						shareCode: shareCode,
						accessCode: accessCode,
					});
					let formElement = document.createElement("form");
					/* POST的表单数据 */
					let formData = {};
					let urlParams = new URLSearchParams(postForm);
					/* 解析网址 */
					formElement.action = url;
					formElement.method = "post";
					formElement.style.display = "none";
					formElement.target = "_blank";
					for (let [key, value] of urlParams) {
						let textAreaElement = document.createElement("textarea");
						textAreaElement.name = key;
						textAreaElement.value = value;
						formElement.appendChild(textAreaElement);
						formData[key] = value;
					}
					log.info(["表单数据", formData]);
					document.body.appendChild(formElement);
					log.info(["访问网址", url]);
					if (enableCopy) {
						NetDiskParse.copyText(
							"baidu",
							netDiskIndex,
							shareCode,
							accessCode,
							"1.5秒后跳转至解析站"
						);
						setTimeout(() => {
							formElement.submit();
						}, 1500);
					} else {
						formElement.submit();
					}
				};
				return this;
			},
			/**
			 * 蓝奏云
			 * 流程:判断是否是多文件
			 * 单文件 => 请求https://蓝奏云域名/{shareToken} 判断链接类型和是否能正常获取
			 *        => 请求https://蓝奏云域名/ajaxm.php 获取下载参数,下载参数例如:https://蓝奏云文件域名/file/?xxxxxxxxx
			 * 多文件 => 先请求https://蓝奏云域名/{shareToken} 获取文件sign => 请求https://蓝奏云域名/filemoreajax.php 获取json格式的文件参数,
			 * 参数内容如{"info":"success","text":[{"duan":"xx","icon":"","id":"".....},{},{}]}
			 * @constructor
			 * @returns {object}
			 */
			lanzou: function () {
				let that = this;
				/**
				 * 所在规则的下标
				 */
				this.netDiskIndex = 0;
				/**
				 * 分享码
				 */
				this.shareCode = "";
				/**
				 * 提取码
				 */
				this.accessCode = "";
				/* 蓝奏云域名 */
				let LanZouHostName = GM_getValue(
					"lanzou-host-name",
					NetDiskData.lanzou_defaultHostName
				);
				/**
				 * 路由
				 */
				this.router = {
					default(pathName = "") {
						if (pathName.startsWith("/")) {
							pathName = pathName.replace(/^\//, "");
						}
						return `https://${LanZouHostName}/${pathName}`;
					},
					tp(pathName = "") {
						if (pathName.startsWith("/")) {
							pathName = pathName.replace(/^\//, "");
						}
						return `https://${LanZouHostName}/tp/${pathName}`;
					},
					s(pathName = "") {
						if (pathName.startsWith("/")) {
							pathName = pathName.replace(/^\//, "");
						}
						return `https://${LanZouHostName}/s/${pathName}`;
					},
				};
				this.regexp = {
					unicode: {
						/**
						 * 判断该链接是否是中文
						 */
						match: /[%\u4e00-\u9fa5]+/g,
						tip: "中文链接",
						isUnicode: false,
					},
					/**
					 * 蓝奏文件取消分享
					 */
					noFile: {
						match: /div>来晚啦...文件取消分享了<\/div>/g,
						tip: "来晚啦...文件取消分享了",
					},
					/**
					 * 蓝奏文件链接错误
					 */
					noExists: {
						match: /div>文件不存在,或已删除<\/div>/g,
						tip: "文件不存在,或已删除",
					},
					/**
					 * 2023-9-19 蓝奏云修改分享规则,需要vip用户才可以分享 apk、ipa 链接
					 */
					needVipToShare: {
						match: /class="fbox">非会员.+请先开通会员/gi,
						tip: "该链接为非会员用户分享的文件,目前无法下载",
					},
					/**
					 * 蓝奏多文件
					 */
					moreFile: {
						match: /<span id=\"filemore\" onclick=\"more\(\);\">/g,
					},
					/**
					 * 蓝奏设置了密码的单文件请求需要的sign值
					 */
					sign: {
						match:
							/var[\s]*(posign|postsign|vidksek|skdklds)[\s]*=[\s]*'(.+?)';/,
					},
					/**
					 * 蓝奏文件名
					 */
					fileName: {
						match: /<title>(.*)<\/title>/,
					},
					/**
					 * 蓝奏文件大小
					 */
					fileSize: {
						match: /<span class=\"mtt\">\((.*)\)<\/span>/,
					},
					/**
					 * 蓝奏文件直链host
					 */
					loadDownHost: {
						match: /var[\s]*(vkjxld)[\s]*=[\s]*'(.+?)'/i,
					},
					/**
					 * 蓝奏文件直链
					 */
					loadDown: {
						match:
							/var[\s]*(loaddown|oreferr|spototo|domianload|hyggid)[\s]*=[\s]*'(.+?)'/i,
					},
					/**
					 * 蓝奏云之苹果使用类型的文件
					 */
					appleDown: {
						match: /var[\s]*appitem[\s]*=[\s]*'(.+?)'/i,
					},
					/**
					 * 蓝奏云文件上传时间
					 */
					uploadTime: {
						match: /mt2\"\>时间:<\/span>(.+?)[\s]*<span/i,
					},
				};
				/**
				 * 入口
				 * @param {number} netDiskIndex
				 * @param {string} shareCode
				 * @param {string} accessCode
				 */
				this.init = async function (netDiskIndex, shareCode, accessCode) {
					log.info([netDiskIndex, shareCode, accessCode]);
					that.netDiskIndex = netDiskIndex;
					that.shareCode = shareCode;
					that.accessCode = accessCode;
					that.regexp.unicode.isUnicode = Boolean(
						that.shareCode.match(that.regexp.unicode.match)
					);
					if (netDiskIndex === 2) {
						await that.getMoreFile(that.router.s(that.shareCode));
					} else {
						await that.getFileLink();
					}
				};
				/**
				 * 获取文件链接
				 * @param {boolean} getShareCodeByPageAgain
				 * @returns
				 */
				this.getFileLink = async function (getShareCodeByPageAgain = false) {
					let url = that.router.default(that.shareCode);
					log.info("蓝奏云-获取文件下载链接" + url);
					let getResp = await httpx.get({
						url: url,
						headers: {
							Accept: "*/*",
							"User-Agent": utils.getRandomPCUA(),
							Referer: url,
						},
						onerror() {},
					});
					if (!getResp.status) {
						log.error(getResp);
						if (getResp.type === "ontimeout") {
							return;
						}
						if (utils.isNull(getResp.data.responseText)) {
							Qmsg.error("请求异常");
							return;
						}
						if (
							getResp.data.responseText.includes(
								"div>文件不存在,或者已被删除</div>"
							)
						) {
							Qmsg.error("文件不存在,或者已被删除");
						} else {
							Qmsg.error("未知情况");
						}
						return;
					}
					let respData = getResp.data;
					if (respData.readyState !== 4) {
						log.error(respData);
						Qmsg.error("请求失败,请重试");
						return;
					}
					if (respData.responseText == void 0) {
						log.error(respData);
						Qmsg.error("获取网页内容为空");
						return;
					}
					if (!that.checkPageCode(respData)) {
						return;
					}
					if (that.isMoreFile(respData)) {
						await that.getMoreFile();
					} else {
						log.info(respData);
						let pageText = respData.responseText;
						if (getShareCodeByPageAgain) {
							let shareCodeNewMatch = pageText.match(
								/var[\s]*link[\s]*=[\s]*\'tp\/(.+?)\';/i
							);
							that.shareCode = shareCodeNewMatch[shareCodeNewMatch.length - 1];
							log.info(`新参数 => ${that.shareCode}`);
						}
						let pageDOM = DOMUtils.parseHTML(pageText, true, true);
						let pageIframeElement =
							pageDOM.querySelector('iframe[class^="ifr"]') ||
							pageDOM.querySelector('iframe[class^="n_downlink"]');
						if (pageIframeElement) {
							let iframeUrl = pageIframeElement.getAttribute("src");
							log.error([
								"该链接需要重新通过iframe地址访问获取信息",
								iframeUrl,
							]);
							Qmsg.info("正在请求下载信息");
							let fileName =
								pageDOM.querySelector("body div.d > div")?.innerText ||
								pageDOM.querySelector("#filenajax")?.innerText ||
								pageDOM
									.querySelector("title")
									?.textContent?.replace(/ - 蓝奏云$/i, "");
							let fileSize =
								pageText.match(/文件大小:<\/span>(.+?)<br>/i) ||
								pageDOM.querySelector("div.n_box div.n_file div.n_filesize")
									?.innerText ||
								pageDOM.querySelector(
									".d2 table tr td .fileinfo:nth-child(1) .fileinforight"
								)?.innerText;
							let fileUploadTime =
								pageText.match(/上传时间:<\/span>(.+?)<br>/i) ||
								pageDOM.querySelector(
									"#file[class=''] .n_file_info span.n_file_infos"
								)?.innerText ||
								pageDOM.querySelector(
									".d2 table tr td .fileinfo:nth-child(3) .fileinforight"
								)?.innerText ||
								pageDOM.querySelector(
									"#file[class='filter'] .n_file_info span.n_file_infos"
								)?.innerText;
							if (fileSize) {
								if (Array.isArray(fileSize)) {
									fileSize = fileSize[fileSize.length - 1];
								}
								if (typeof fileSize === "string") {
									fileSize = fileSize.replaceAll("大小:", "");
								}
							} else {
								log.error("解析文件大小信息失败");
							}
							if (fileUploadTime) {
								if (Array.isArray(fileUploadTime)) {
									fileUploadTime = fileUploadTime[fileUploadTime.length - 1];
								}
								if (
									fileUploadTime.toString().toLowerCase().startsWith("android")
								) {
									log.error("解析出的文件上传时间信息是Android/xxxx开头");
									fileUploadTime = void 0;
								}
							} else {
								log.error("解析文件上传时间信息失败");
							}
							let downloadUrl = await that.getLinkByIframe(iframeUrl, {
								fileName,
								fileSize,
								fileUploadTime,
							});
							if (downloadUrl) {
								if (NetDiskFilterScheme.isForwardDownloadLink("lanzou")) {
									downloadUrl = NetDiskFilterScheme.parseDataToSchemeUri(
										"lanzou",
										downloadUrl
									);
								}
								NetDiskUI.staticView.oneFile({
									title: "蓝奏云单文件直链",
									fileName: fileName,
									fileSize: fileSize,
									downloadUrl: downloadUrl,
									fileUploadTime: fileUploadTime,
								});
							}
						} else {
							await that.getLink(respData);
						}
					}
				};
				/**
				 * 页面检查,看看是否存在文件失效情况
				 * @param {object} response
				 * @returns {boolean}
				 * + true 未失效
				 * + false 已失效
				 */
				this.checkPageCode = function (response) {
					let pageText = response.responseText;
					if (pageText.match(that.regexp.noFile.match)) {
						Qmsg.error(that.regexp.noFile.tip);
						return false;
					}
					if (pageText.match(that.regexp.noExists.match)) {
						Qmsg.error(that.regexp.noExists.tip);
						return false;
					}
					if (pageText.match(that.regexp.needVipToShare.match)) {
						Qmsg.error(that.regexp.needVipToShare.tip);
						return false;
					}
					return true;
				};
				/**
				 * 判断是否是多文件的链接
				 * @param {object} response
				 * @returns {boolean}
				 * + true 多文件
				 * + false 单文件
				 */
				this.isMoreFile = function (response) {
					let pageText = response.responseText;
					if (pageText.match(that.regexp.moreFile.match)) {
						log.info("该链接为多文件");
						return true;
					} else {
						log.info("该链接为单文件");
						return false;
					}
				};
				/**
				 * 获取链接
				 * @param {object} response
				 */
				this.getLink = async function (response) {
					let pageText = response.responseText;
					if (pageText == void 0) {
						log.error("shareCode错误,重新从页面中获取");
						await that.getFileLink(true);
						return;
					}
					let sign = pageText.match(that.regexp.sign.match);
					let postData_p = "";
					let postData_sign = "";
					let fileName = pageText.match(that.regexp.fileName.match);
					let fileSize =
						pageText.match(that.regexp.fileSize.match) ||
						pageText.match(/<div class="n_filesize">大小:(.+?)<\/div>/i);
					let fileUploadTime =
						pageText.match(that.regexp.uploadTime.match) ||
						pageText.match(/<span class="n_file_infos">(.+?)<\/span>/i);
					if (fileName) {
						fileName = fileName[fileName.length - 1].trim();
					} else {
						fileName = "";
					}
					if (fileSize) {
						fileSize = fileSize[fileSize.length - 1].trim();
					} else {
						fileSize = "";
					}
					if (fileUploadTime) {
						fileUploadTime = fileUploadTime[fileUploadTime.length - 1].trim();
					} else {
						fileUploadTime;
					}
					if (sign) {
						postData_sign = sign[sign.length - 1];
						log.info(`获取Sign: ${postData_sign}`);
						if (utils.isNotNull(that.accessCode)) {
							log.info("传入参数=>有密码");
							postData_p = that.accessCode;
						} else {
							log.info("传入参数=>无密码");
						}
						let postResp = await httpx.post({
							url: that.router.default("ajaxm.php"),
							responseType: "json",
							headers: {
								"Content-Type":
									"application/x-www-form-urlencoded; charset=UTF-8",
								"User-Agent": utils.getRandomAndroidUA(),
								Referer: that.router.default(that.shareCode),
							},
							data: `action=downprocess&sign=${postData_sign}&p=${postData_p}`,
						});
						if (!postResp.status) {
							return;
						}
						let respData = postResp.data;
						log.info(respData);
						if (respData.readyState === 4) {
							let json_data = utils.toJSON(respData.responseText);
							let downloadUrl = `${json_data["dom"]}/file/${json_data["url"]}`;
							if (
								typeof json_data["url"] === "string" &&
								(json_data["url"].startsWith("http") ||
									json_data["url"].startsWith(json_data["dom"]))
							) {
								/* 有些情况下比如苹果的ipa文件的请求,json_data["url"]就是一个完整的链接 */
								downloadUrl = json_data["url"];
							}
							/* json_data["zt"]表示状态,一般为1 */
							let zt = json_data["zt"];
							/* json_data["inf"]一般是文件名,也可以看作是请求信息提示 */
							if ("密码不正确".indexOf(json_data["inf"]) != -1) {
								Qmsg.error("密码不正确!");
								NetDiskUI.newAccessCodeView(
									void 0,
									"lanzou",
									that.netDiskIndex,
									that.shareCode,
									(userInputAccessCode) => {
										that.init(
											that.netDiskIndex,
											that.shareCode,
											userInputAccessCode
										);
									}
								);
							} else {
								fileName = json_data["inf"] ? json_data["inf"] : fileName;
								downloadUrl = await NetDiskParse.getRedirectFinalUrl(
									downloadUrl,
									utils.getRandomAndroidUA()
								);
								log.info(downloadUrl);

								if (NetDiskFilterScheme.isForwardDownloadLink("lanzou")) {
									downloadUrl = NetDiskFilterScheme.parseDataToSchemeUri(
										"lanzou",
										downloadUrl
									);
								}

								NetDiskUI.staticView.oneFile({
									title: "蓝奏云单文件直链",
									fileName: fileName,
									fileSize: fileSize,
									downloadUrl: downloadUrl,
									fileUploadTime: fileUploadTime,
								});
							}
						} else {
							Qmsg.error("请求失败,请重试");
						}
					} else {
						let loadDownHost = pageText.match(that.regexp.loadDownHost.match);
						let loadDown = pageText.match(that.regexp.loadDown.match);
						let appleDown = pageText.match(that.regexp.appleDown.match);
						if (utils.isNull(loadDown)) {
							loadDown = pageText.match(/var[\s]*(cppat)[\s]*=[\s]*'(.+?)'/i);
						}
						if (utils.isNull(loadDownHost) && appleDown) {
							appleDown = appleDown[appleDown.length - 1];
							loadDownHost = [appleDown];
							loadDown = [""];
							log.success(["多文件-当前链接猜测为苹果的文件", appleDown]);
						}
						if (utils.isNull(loadDownHost)) {
							Qmsg.error("蓝奏云直链:获取sign的域名失败,请反馈开发者", {
								timeout: 3500,
							});
							return;
						}
						if (utils.isNull(loadDown)) {
							Qmsg.error("蓝奏云直链:获取sign失败,请反馈开发者", {
								timeout: 3500,
							});
							return;
						}
						let downloadUrl = `${loadDownHost[loadDownHost.length - 1]}${
							loadDown[loadDown.length - 1]
						}`;
						log.info([fileName, fileSize, downloadUrl]);
						downloadUrl = await NetDiskParse.getRedirectFinalUrl(
							downloadUrl,
							utils.getRandomAndroidUA()
						);
						log.info(downloadUrl);
						if (NetDiskFilterScheme.isForwardDownloadLink("lanzou")) {
							downloadUrl = NetDiskFilterScheme.parseDataToSchemeUri(
								"lanzou",
								downloadUrl
							);
						}

						NetDiskUI.staticView.oneFile({
							title: "蓝奏云单文件直链",
							fileName: fileName,
							fileSize: fileSize,
							downloadUrl: downloadUrl,
							fileUploadTime: fileUploadTime,
						});
					}
				};

				/**
				 * 通过iframe的链接来获取单文件直链
				 * @param {string} urlPathName url路径
				 * @param {{
				 * fileName:string,
				 * fileSize:string,
				 * fileUploadTime:string
				 * }} fileInfo 文件信息
				 */
				this.getLinkByIframe = async function (urlPathName, fileInfo) {
					log.info([urlPathName, fileInfo]);
					let iFrameUrl = that.router.default(urlPathName);
					let getResp = await httpx.get({
						url: iFrameUrl,
						headers: {
							Accept:
								"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
							"User-Agent": utils.getRandomPCUA(),
							Referer: that.router.default(that.shareCode),
						},
					});
					if (!getResp.status) {
						return;
					}
					let respData = getResp.data;
					log.info(respData);
					let pageText = respData.responseText;
					let aihidcms = pageText.match(/var[\s]*aihidcms[\s]*=[\s]*'(.*)';/i);
					let ciucjdsdc = pageText.match(
						/var[\s]*ciucjdsdc[\s]*=[\s]*'(.*)';/i
					);
					let ajaxdata = pageText.match(/var[\s]*ajaxdata[\s]*=[\s]*'(.+)';/i);
					let sign = pageText.match(/'sign':[\s]*'(.+)',/i);
					let ajaxUrl = pageText.match(/url[\s]*:[\s]*'(.+)'[\s]*,/);
					if (ajaxUrl) {
						ajaxUrl = ajaxUrl[ajaxUrl.length - 1];
					} else {
						Qmsg.error("提取ajaxm.php的具体参数失败,使用默认的ajaxm.php");
						ajaxUrl = "ajaxm.php";
					}
					if (!aihidcms) {
						Qmsg.error("ajaxm.php请求参数 websignkey 获取失败");
						return;
					} else {
						aihidcms = aihidcms[aihidcms.length - 1];
					}
					if (!ciucjdsdc) {
						Qmsg.error("ajaxm.php请求参数 websign 获取失败");
						return;
					} else {
						ciucjdsdc = ciucjdsdc[ciucjdsdc.length - 1];
					}
					if (!ajaxdata) {
						Qmsg.error("ajaxm.php请求参数 signs 获取失败");
						return;
					} else {
						ajaxdata = ajaxdata[ajaxdata.length - 1];
					}
					if (!sign) {
						Qmsg.error("ajaxm.php请求参数 sign 获取失败");
						return;
					} else {
						sign = sign[sign.length - 1];
					}
					let postData = `action=downprocess&signs=${ajaxdata}&sign=${sign}&websign=${ciucjdsdc}&ves=1&websignkey=${aihidcms}`;
					log.success("请求的路径参数:" + ajaxUrl);
					log.success("ajaxm.php的请求参数-> " + postData);
					let postResp = await httpx.post({
						url: that.router.default(ajaxUrl),
						headers: {
							Accept: "application/json, text/javascript, */*",
							"Content-Type": "application/x-www-form-urlencoded",
							Referer: that.router.default(that.shareCode),
							"User-Agent": utils.getRandomPCUA(),
						},
						data: postData,
					});
					if (!postResp.status) {
						return;
					}
					let postRespData = postResp.data;
					log.info(postRespData);
					let jsonData = utils.toJSON(postRespData.responseText);
					let downloadUrl = `${jsonData["dom"]}/file/${jsonData["url"]}`;
					let zt = jsonData["zt"];
					log.success(["直链", downloadUrl]);
					if ("密码不正确".indexOf(jsonData["inf"]) != -1) {
						Qmsg.error("密码不正确!");
						NetDiskUI.newAccessCodeView(
							void 0,
							"lanzou",
							that.netDiskIndex,
							that.shareCode,
							(userInputAccessCode) => {
								that.init(
									that.netDiskIndex,
									that.shareCode,
									userInputAccessCode
								);
							}
						);
					} else {
						fileInfo.fileName = utils.isNotNull(jsonData["inf"])
							? jsonData["inf"]
							: fileInfo.fileName;
						downloadUrl = await NetDiskParse.getRedirectFinalUrl(
							downloadUrl,
							utils.getRandomAndroidUA()
						);
						log.info(downloadUrl);
						return downloadUrl;
					}
				};
				/**
				 * 多文件获取
				 * @param {string} url 链接
				 */
				this.getMoreFile = async function (url) {
					if (url == void 0) {
						url = that.router.default(that.shareCode);
					}
					let getResp = await httpx.get({
						url: url,
						headers: {
							Accept: "*/*",
							"User-Agent": utils.getRandomAndroidUA(),
							Referer: url,
						},
					});
					if (!getResp.status) {
						return;
					}
					let respData = getResp.data;
					log.info(respData);
					if (respData.readyState !== 4) {
						Qmsg.error("请求失败,请重试");
						return;
					}
					let pageText = respData.responseText;
					let fid = pageText.match(/\'fid\':(.+?),/)[1].replaceAll("'", "");
					let uid = pageText.match(/\'uid\':(.+?),/)[1].replaceAll("'", "");
					let pgs = 1;
					let t_name = pageText.match(/\'t\':(.+?),/)[1];
					let t_rexp = new RegExp(t_name + "[\\s]*=[\\s]*('|\")(.+?)('|\");");
					let t = pageText.match(t_rexp)[2];
					let k_name = pageText.match(/\'k\':(.+?),/)[1];
					let k_rexp = new RegExp(k_name + "[\\s]*=[\\s]*('|\")(.+?)('|\");");
					let k = pageText.match(k_rexp)[2];
					let lx = that.shareCode.match(that.regexp.unicode.match) ? 1 : 2;
					let postData = `lx=${lx}&fid=${fid}&uid=${uid}&pg=${pgs}&rep=0&t=${t}&k=${k}&up=1&ls=1&pwd=${that.accessCode}`;
					log.info(`多文件请求参数:${postData}`);
					let postResp = await httpx.post({
						url: that.router.default("filemoreajax.php"),
						responseType: "json",
						headers: {
							"Content-Type":
								"application/x-www-form-urlencoded; charset=UTF-8",
							"User-Agent": utils.getRandomAndroidUA(),
							Referer: url,
						},
						data: postData,
					});
					if (!postResp.status) {
						return;
					}
					let postRespData = postResp.data;
					log.info(postRespData);
					let json_data = utils.toJSON(postRespData.responseText);
					let zt = json_data["zt"];
					let info = json_data["info"];
					if (zt === 4) {
						Qmsg.error(info);
					} else if (zt === 1) {
						let QmsgLoading = Qmsg.loading("获取文件夹成功,解析文件直链中...");
						/* 获取多文件的数组信息 */
						let folder = json_data["text"];
						/**
						 * 弹出内容
						 * @type {import("@whitesev/pops/dist/types/src/components/folder/indexType").PopsFolderDataConfig[]}
						 */
						let folderList = [];
						log.info(`本链接一共${folder.length}个文件`);
						for (let index = 0; index < folder.length; index++) {
							let folderInfo = folder[index];
							let fileShareCode = folderInfo["id"];
							let fileName = folderInfo["name_all"];
							let fileSize = folderInfo["size"];
							let fileType = folderInfo["icon"];
							let uploadTime = folderInfo["time"];
							folderList.push({
								fileName: fileName,
								fileSize: fileSize,
								fileType: fileType,
								createTime: uploadTime,
								latestTime: uploadTime,
								isFolder: false,
								index: 0,
								async clickEvent() {
									let folderDownloadInfo = await that.parseMoreFile(
										fileShareCode,
										fileName,
										fileSize,
										uploadTime
									);
									/* 成功获取下载信息 */
									if (folderDownloadInfo.success) {
										return {
											autoDownload: true,
											mode: "aBlank",
											url: folderDownloadInfo.downloadUrl,
										};
									} else {
										log.error(["获取下载信息失败:", folderDownloadInfo]);
										Qmsg.error(folderDownloadInfo.msg);
									}
								},
							});
						}
						QmsgLoading.close();
						NetDiskUI.staticView.moreFile("蓝奏云文件解析", folderList);
					} else if ("密码不正确".indexOf(info) !== -1) {
						Qmsg.error("密码不正确!");
						NetDiskUI.newAccessCodeView(
							void 0,
							"lanzou",
							that.netDiskIndex,
							that.shareCode,
							(userInputAccessCode) => {
								that.init(
									that.netDiskIndex,
									that.shareCode,
									userInputAccessCode
								);
							}
						);
					} else if ("没有了".indexOf(info) !== -1) {
						Qmsg.error("没有文件了");
					} else {
						Qmsg.error("未知错误");
					}
				};
				/**
				 * 文件解析并返回html-vip
				 * @param {string} paramShareCode 解析多文件获取的shareCode
				 * @param {string} fileName 文件名
				 * @param {string} fileSize 文件大小
				 * @param {string} fileUploadTime 文件上传时间
				 * @returns {Promise<{
				 * success :boolean,
				 * fileName: string,
				 * fileSize: string,
				 * fileUploadTime: string,
				 * downloadUrl: ?string,
				 * msg: string,
				 * }>}
				 */
				this.parseMoreFile = async function (
					paramShareCode,
					fileName,
					fileSize,
					fileUploadTime
				) {
					/* 根据获取到的json中多文件链接来获取单文件直链 */
					let getResp = await httpx.get({
						url: that.router.default(paramShareCode),
						headers: {
							Accept: "*/*",
							"User-Agent": utils.getRandomPCUA(),
							Referer: that.router.default(that.shareCode),
						},
					});
					log.info(getResp);
					if (!getResp.status) {
						return {
							success: false,
							fileName: fileName,
							fileSize: fileSize,
							fileUploadTime: fileUploadTime,
							msg: `解析失败,${getResp.msg}`,
							downloadUrl: void 0,
						};
					}
					let respData = getResp.data;
					let pageText = respData.responseText;
					let pageDOM = DOMUtils.parseHTML(pageText, true, true);
					let pageIframeElement =
						pageDOM.querySelector('iframe[class^="ifr"]') ||
						pageDOM.querySelector('iframe[class^="n_downlink"]');
					if (!pageIframeElement) {
						return {
							success: false,
							fileName: fileName,
							fileSize: fileSize,
							fileUploadTime: fileUploadTime,
							msg: `解析iframe链接失败`,
							downloadUrl: void 0,
						};
					}
					let iframeUrl = pageIframeElement.getAttribute("src");
					log.error(["该链接需要重新通过iframe地址访问获取信息", iframeUrl]);
					Qmsg.info("正在请求下载信息");
					let downloadUrl = await that.getLinkByIframe(iframeUrl, {
						fileName,
						fileSize,
						fileUploadTime,
					});
					if (downloadUrl) {
						if (NetDiskFilterScheme.isForwardDownloadLink("lanzou")) {
							downloadUrl = NetDiskFilterScheme.parseDataToSchemeUri(
								"lanzou",
								downloadUrl
							);
						}
						return {
							success: true,
							fileName: fileName,
							fileSize: fileSize,
							fileUploadTime: fileUploadTime,
							msg: "success",
							downloadUrl: downloadUrl,
						};
					} else {
						return {
							success: false,
							fileName: fileName,
							fileSize: fileSize,
							fileUploadTime: fileUploadTime,
							msg: `获取下载链接失败`,
							downloadUrl: void 0,
						};
					}
				};
				return this;
			},
			/**
			 * 蓝奏云优享
			 * @constructor
			 */
			lanzouyx: function () {
				let that = this;
				/** 所在规则的下标 */
				this.netDiskIndex = 0;
				/** 分享码 */
				this.shareCode = "";
				/** 分享码的id */
				this.shareCodeId = "";
				/** 提取码 */
				this.accessCode = "";
				/**
				 * 获取的uuid
				 * @type {?string}
				 */
				this.uuid = void 0;
				/**
				 * 获取的userId
				 * @type {?string}
				 **/
				this.userId = void 0;
				const LanZouUtils = {
					LanZouDiskApp: "lanZouY-disk-app",
					EncryptList: [
						"Y",
						"y",
						"0",
						"Z",
						"z",
						"N",
						"n",
						"M",
						"I",
						"6",
						"m",
						"W",
						"w",
						"1",
						"X",
						"x",
						"L",
						"l",
						"K",
						"7",
						"k",
						"i",
						"U",
						"u",
						"2",
						"V",
						"v",
						"J",
						"j",
						"8",
						"G",
						"g",
						"F",
						"S",
						"s",
						"3",
						"T",
						"t",
						"H",
						"h",
						"f",
						"E",
						"e",
						"D",
						"Q",
						"q",
						"4",
						"R",
						"r",
						"9",
						"d",
						"a",
						"C",
						"c",
						"B",
						"O",
						"o",
						"5",
						"P",
						"p",
						"b",
						"A",
					],
					decodeChar(e) {
						for (let t = 0; t < this.EncryptList.length; t++)
							if (e == this.EncryptList[t]) return t;
						return -1;
					},
					/**
					 * shareCode转id
					 * @param {string} shareCode
					 */
					idEncrypt(shareCode) {
						let t = 1,
							n = 0;
						if ("" != shareCode && shareCode.length > 4) {
							let r;
							shareCode = shareCode.substring(3, shareCode.length - 1);
							for (let index = 0; index < shareCode.length; index++)
								(r = shareCode.charAt(shareCode.length - index - 1)),
									(n += this.decodeChar(r) * t),
									(t *= 62);
						}
						return n;
					},
					encrypt(e) {
						const t = Cryptojs.enc.Utf8.parse(this.LanZouDiskApp),
							n = Cryptojs.enc.Utf8.parse(e),
							r = Cryptojs.AES.encrypt(n, t, {
								mode: Cryptojs.mode.ECB,
								padding: Cryptojs.pad.Pkcs7,
							});
						return r;
					},
					/**
					 * 用于时间戳转加密字符串
					 * @param {any} e
					 * @returns
					 */
					encryptHex(e) {
						const t = this.encrypt(e, this.LanZouDiskApp);
						return t.ciphertext.toString().toUpperCase();
					},
				};
				/**
				 * 入口
				 * @param {number} netDiskIndex
				 * @param {string} shareCode
				 * @param {string} accessCode
				 */
				this.init = async function (netDiskIndex, shareCode, accessCode) {
					log.info([netDiskIndex, shareCode, accessCode]);
					that.netDiskIndex = netDiskIndex;
					that.shareCode = shareCode;
					that.accessCode = accessCode;
					that.shareCodeId = that.getDecodeShareCodeId(shareCode);
					that.uuid = that.getEncodeUUID();
					let linkInfo = await this.recommendList(
						3,
						"Chrome",
						that.uuid,
						2,
						that.getEncodeTimeStamp(),
						that.shareCodeId,
						0,
						1,
						60
					);
					if (!linkInfo) {
						return;
					}
					if (!linkInfo["list"].length) {
						return;
					}
					if (linkInfo["list"][0]?.["map"]?.["userId"]) {
						that.userId = linkInfo["list"][0]?.["map"]?.["userId"];
					} else {
						Qmsg.error("解析获取【userId】为空");
						return;
					}
					if (linkInfo["list"][0]["folderIds"] == null) {
						/* 单文件 */
						log.success("该链接是 单文件");
						let fileInfo = linkInfo["list"][0]["fileList"][0];
						let folderInfoList = that.parseFolderInfo(
							linkInfo["list"][0]["fileList"],
							0
						);
						/* 获取文件下载信息 */
						let downloadInfo = await folderInfoList[0]["clickEvent"]();
						if (downloadInfo) {
							let downloadUrl = downloadInfo["url"];
							if (NetDiskFilterScheme.isForwardDownloadLink("lanzouyx")) {
								downloadUrl = NetDiskFilterScheme.parseDataToSchemeUri(
									"lanzouyx",
									downloadUrl
								);
							}
							NetDiskUI.staticView.oneFile({
								title: "蓝奏云优享单文件直链",
								fileName: fileInfo["fileName"],
								fileSize: fileInfo["fileSize"] * 1024,
								downloadUrl: downloadUrl,
								fileUploadTime: utils.formatToTimeStamp(fileInfo["updTime"]),
								fileLatestTime: utils.formatToTimeStamp(fileInfo["updTime"]),
							});
						}
					} else {
						/* 多文件 */
						log.success("该链接是 多文件");
						Qmsg.info("正在递归文件");
						let QmsgLoading = Qmsg.loading(`正在解析多文件中,请稍后...`);
						let folderInfoList = that.parseFolderInfo(
							linkInfo["list"][0]["fileList"],
							0
						);
						QmsgLoading.close();
						log.info("递归完毕");
						NetDiskUI.staticView.moreFile("蓝奏云优享解析", folderInfoList);
					}
				};
				/**
				 * 获取直链弹窗的文件夹信息
				 * @param {object} infoList
				 * @param {number} index
				 */
				this.parseFolderInfo = function (infoList, index) {
					let folderInfoList = [];
					let tempFolderInfoList = [];
					/**
					 * @type {import("@whitesev/pops/dist/types/src/components/folder/indexType").PopsFolderDataConfig[]}
					 */
					let tempFolderFileInfoList = [];
					infoList.forEach((item) => {
						if (item["fileType"] === 2) {
							/* 文件夹 */
							tempFolderInfoList.push({
								fileName: item["folderName"],
								fileSize: 0,
								fileType: "",
								createTime: new Date(item["updTime"]).getTime(),
								latestTime: new Date(item["updTime"]).getTime(),
								isFolder: true,
								index: index,
								async clickEvent() {
									let nowTime = Date.now();
									let timestamp = that.getEncodeTimeStamp(nowTime);
									let folderId = item["folderId"];
									let folderInfo = await that.getFolderInfo(
										3,
										"Chrome",
										that.uuid,
										2,
										timestamp,
										that.shareCodeId,
										folderId,
										1,
										60
									);
									if (folderInfo && folderInfo["list"]) {
										return that.parseFolderInfo(folderInfo["list"], index + 1);
									} else {
										return [];
									}
								},
							});
						} else {
							/* 文件 */
							tempFolderFileInfoList.push({
								fileName: item["fileName"],
								fileSize: item["fileSize"] * 1024,
								fileType: "",
								createTime: new Date(item["updTime"]).getTime(),
								latestTime: new Date(item["updTime"]).getTime(),
								isFolder: false,
								index: index,
								async clickEvent() {
									let fileId = item["fileId"];
									let userId = item["userId"] || that.userId;
									let uuid = that.uuid;
									if (utils.isNull(userId)) {
										Qmsg.error("获取【userId】为空");
										return;
									}
									if (utils.isNull(uuid)) {
										Qmsg.error("获取【uuid】为空");
										return;
									}
									let downloadUrl = await that.getDownloadFileUrl(
										...that.getDownloadFileParams(fileId, userId, uuid)
									);
									if (downloadUrl) {
										if (NetDiskFilterScheme.isForwardDownloadLink("lanzouyx")) {
											downloadUrl = NetDiskFilterScheme.parseDataToSchemeUri(
												"lanzouyx",
												downloadUrl
											);
										}
										return {
											url: downloadUrl,
											autoDownload: true,
											mode: "aBlank",
										};
									}
								},
							});
						}
					});
					tempFolderInfoList.sort((a, b) =>
						a["fileName"].localeCompare(b["fileName"])
					);
					tempFolderFileInfoList.sort((a, b) =>
						a["fileName"].localeCompare(b["fileName"])
					);
					folderInfoList = folderInfoList.concat(tempFolderInfoList);
					folderInfoList = folderInfoList.concat(tempFolderFileInfoList);
					return folderInfoList;
				};
				/**
				 * 获取列表信息
				 * @param {number} devType
				 * @param {string} devModel
				 * @param {string} uuid
				 * @param {number} extra
				 * @param {string} timestamp
				 * @param {number|string} shareId
				 * @param {number} type
				 * @param {number} offset
				 * @param {number} limit
				 * @returns
				 */
				this.recommendList = async function (
					devType = 3,
					devModel = "Chrome",
					uuid = "",
					extra = 2,
					timestamp = "",
					shareId = "",
					type = 0,
					offset = 1,
					limit = 60
				) {
					let postResp = await httpx.post(
						`https://api.ilanzou.com/unproved/recommend/list?devType=${devType}&devModel=${devModel}&uuid=${uuid}&extra=${extra}&timestamp=${timestamp}&shareId=${shareId}&type=${type}&offset=${offset}&limit=${limit}`,
						{
							headers: {
								Accept: "application/json, text/plain, */*",
								Origin: "https://www.ilanzou.com",
								Referer: "https://www.ilanzou.com/",
								"Sec-Fetch-Site": "same-site",
								Host: "api.ilanzou.com",
								"User-Agent": utils.getRandomPCUA(),
							},
							responseType: "json",
						}
					);
					if (!postResp.status) {
						return;
					}
					let data = utils.toJSON(postResp.data.responseText);
					log.success(["获取链接信息:", data]);
					if (data["code"] !== 200) {
						Qmsg.error("请求链接信息失败");
						return;
					}
					if (!data["list"].length) {
						Qmsg.error("获取链接信息为空");
						return;
					}
					return data;
				};
				/**
				 * 获取文件夹信息
				 * @param {number} devType
				 * @param {string} devModel
				 * @param {string} uuid
				 * @param {number} extra
				 * @param {string} timestamp
				 * @param {number|string} shareId
				 * @param {number|string} folderId
				 * @param {number} offset
				 * @param {number} limit
				 */
				this.getFolderInfo = async function (
					devType = 6,
					devModel = "Chrome",
					uuid = "",
					extra = 2,
					timestamp = "",
					shareId = "",
					folderId = "",
					offset = 1,
					limit = 60
				) {
					let postResp = await httpx.post(
						`https://api.ilanzou.com/unproved/share/list?devType=${devType}&devModel=${devModel}&uuid=${uuid}&extra=${extra}&timestamp=${timestamp}&shareId=${shareId}&folderId=${folderId}&offset=${offset}&limit=${limit}`,
						{
							headers: {
								Accept: "application/json, text/plain, */*",
								Origin: "https://www.ilanzou.com",
								Referer: "https://www.ilanzou.com/",
								"Sec-Fetch-Site": "same-site",
								Host: "api.ilanzou.com",
								"User-Agent": utils.getRandomPCUA(),
							},
						}
					);
					if (!postResp.status) {
						return;
					}
					let data = utils.toJSON(postResp.data.responseText);
					log.success(["获取文件列表信息:", data]);
					if (data["code"] === 200) {
						return data;
					} else {
						Qmsg.error(data["msg"]);
					}
				};
				/**
				 * 获取下载链接
				 */
				this.getDownloadFileUrl = async function (
					downloadId = "",
					enable = 1,
					devType = 6,
					uuid = "",
					timestamp = "",
					auth = ""
				) {
					let getResp = await httpx.options(
						`https://api.ilanzou.com/unproved/file/redirect?downloadId=${downloadId}&enable=${enable}&devType=${devType}&uuid=${uuid}&timestamp=${timestamp}&auth=${auth}`
					);
					if (!getResp.status) {
						return;
					}
					log.success(getResp);
					if (getResp.data.responseText) {
						let errorData = utils.toJSON(getResp.data.responseText);
						log.error(errorData);
						Qmsg.error(errorData["msg"]);
						return;
					}
					return getResp.data.finalUrl;
				};
				/**
				 * 获取加密的uuid
				 * @param {number} e
				 * @returns
				 */
				this.getEncodeUUID = function (e = 21) {
					let r = (e = 21) =>
						crypto
							.getRandomValues(new Uint8Array(e))
							.reduce(
								(e, t) => (
									(t &= 63),
									(e +=
										t < 36
											? t.toString(36)
											: t < 62
											? (t - 26).toString(36).toUpperCase()
											: t > 62
											? "-"
											: "_"),
									e
								),
								""
							);
					return r(e);
				};
				/**
				 * 获取shareCode转换后的id
				 */
				this.getDecodeShareCodeId = function (shareCode) {
					return LanZouUtils.idEncrypt(shareCode);
				};
				/**
				 * 获取加密后的timestamp
				 * @param {number} time
				 */
				this.getEncodeTimeStamp = function (time = Date.now()) {
					return LanZouUtils.encryptHex(time);
				};
				/**
				 * 获取下载文件的参数
				 * @param {string} fileId 文件id
				 * @param {string} userId 用户id
				 * @param {?string} uuid 用户登录生成的uuid
				 */
				this.getDownloadFileParams = function (fileId, userId = "", uuid) {
					let nowTime = Date.now();
					let downloadId = LanZouUtils.encryptHex(fileId + "|" + userId),
						enable = 1,
						devType = 6,
						timestamp = that.getEncodeTimeStamp(nowTime),
						auth = LanZouUtils.encryptHex(fileId + "|" + nowTime);
					return [downloadId, enable, devType, uuid, timestamp, auth];
				};
				/**
				 * 前往登录
				 */
				this.gotoLogin = function () {
					NetDiskPops.confirm(
						{
							title: {
								position: "center",
								text: "蓝奏云优享",
							},
							content: {
								text: "必须先在【蓝奏云优享】进行登录,然后登录成功后刷新获取必备的下载参数【uuid】和【userId】。",
								html: false,
							},
							btn: {
								reverse: true,
								position: "end",
								ok: {
									text: "前往",
									enable: true,
									callback() {
										window.open("https://www.ilanzou.com", "_blank");
									},
								},
							},
						},
						NetDiskUI.popsStyle.tianYiYunLoginTip
					);
				};
				return this;
			},
			/**
			 * 天翼云
			 * + 开发文档:https://id.dlife.cn/html/api_detail_696.html
			 * @constructor
			 * @returns {object}
			 */
			tianyiyun: function () {
				let that = this;
				/**
				 * 所在规则的下标
				 */
				this.netDiskIndex = 0;
				/**
				 * 分享码
				 */
				this.shareCode = "";
				/**
				 * 提取码
				 */
				this.accessCode = "";
				let shareId = void 0;
				/* 猜测1是有密码,2是无密码 */
				let shareMode = 1;
				this.code = {
					ShareNotFoundFlatDir: "抱歉,该文件的分享平铺目录未找到",
					ShareNotFound: "抱歉,您访问的页面地址有误,或者该页面不存在。",
					ShareAuditNotPass: "抱歉,该内容审核不通过",
					FileNotFound: "抱歉,文件不存在",
					ShareExpiredError: "抱歉,您访问的页面地址有误,或者该页面不存在",
					ShareAuditWaiting: "抱歉,该链接处于审核中",
					ShareInfoNotFound: "抱歉,您访问的页面地址有误,或者该页面不存在",
					FileTooLarge: "抱歉,文件太大,不支持下载",
					InvalidSessionKey:
						"天翼云PC端Cookie未生成,是否前去登录?<br />&nbsp;&nbsp;&nbsp;&nbsp;(注意,需要当前浏览器的UA切换成PC且在登录后要等待进入个人云空间后生成Cookie,不是手机端浏览的个人云空间,那样生成的Cookie无法使用)",
				};
				/**
				 *
				 * @param {number} netDiskIndex
				 * @param {string} shareCode
				 * @param {string} accessCode
				 * @returns
				 */
				this.init = async function (netDiskIndex, shareCode, accessCode) {
					log.info([netDiskIndex, shareCode, accessCode]);
					that.netDiskIndex = netDiskIndex;
					that.shareCode = shareCode;
					that.accessCode = accessCode;

					let shareInfoData = await that.getShareInfoByCodeV2(shareCode);
					if (!shareInfoData) {
						return;
					}

					log.info(["解析的JSON信息", shareInfoData]);
					if (
						shareInfoData["needAccessCode"] &&
						utils.isNull(that.accessCode)
					) {
						Qmsg.error("密码不正确!");
						NetDiskUI.newAccessCodeView(
							void 0,
							"tianyiyun",
							that.netDiskIndex,
							that.shareCode,
							(userInputAccessCode) => {
								that.init(
									that.netDiskIndex,
									that.shareCode,
									userInputAccessCode
								);
							}
						);
						return;
					}
					if ("shareId" in shareInfoData) {
						shareId = shareInfoData["shareId"];
					} else {
						shareId = await that.getShareId(shareCode, accessCode);
					}
					if ("shareMode" in shareInfoData) {
						shareMode = shareInfoData["shareMode"];
					}
					if (shareId == void 0) {
						return;
					}
					if (shareInfoData.isFolder) {
						/* 多文件 */
						Qmsg.info("正在递归文件");
						let QmsgLoading = Qmsg.loading(`正在解析多文件中,请稍后...`);
						let fileId = shareInfoData["fileId"];
						let folderInfo = await that.listShareDir(
							shareCode,
							accessCode,
							void 0,
							void 0,
							fileId,
							fileId,
							void 0,
							shareId,
							void 0,
							void 0,
							void 0,
							void 0
						);
						if (!folderInfo) {
							QmsgLoading.close();
							return;
						}
						let folderInfoList = that.getFolderInfo(
							shareCode,
							accessCode,
							folderInfo,
							0
						);
						QmsgLoading.close();
						log.info("递归完毕");
						NetDiskUI.staticView.moreFile("天翼云文件解析", folderInfoList);
						return;
					} else {
						/* 单文件 */
						let downloadUrl = await that.getDownloadUrl(
							that.shareCode,
							that.accessCode,
							shareInfoData.fileId,
							shareId
						);
						if (downloadUrl) {
							if (NetDiskFilterScheme.isForwardDownloadLink("tianyiyun")) {
								downloadUrl = NetDiskFilterScheme.parseDataToSchemeUri(
									"tianyiyun",
									downloadUrl
								);
							}
							NetDiskUI.staticView.oneFile({
								title: "天翼云单文件直链",
								fileName: shareInfoData.fileName,
								fileSize: utils.formatByteToSize(shareInfoData.fileSize),
								downloadUrl: downloadUrl,
								fileUploadTime: shareInfoData.fileCreateDate,
								fileLatestTime: shareInfoData.fileLastOpTime,
							});
						}
					}
				};
				/**
				 * 获取当前登录用户的信息
				 * @returns {Promise<?{
				 * encryptAccount: string,
				 * icon: string,
				 * nickname: string,
				 * res_code: string,
				 * res_message: string,
				 * sessionKey: string,
				 * userAccount: string
				 * }>}
				 */
				this.getUserBriefInfo = async function (shareCode) {
					let getResp = await httpx.get(
						"https://cloud.189.cn/api/portal/v2/getUserBriefInfo.action",
						{
							headers: {
								Accept: "application/json;charset=UTF-8",
								Referer: "https://cloud.189.cn/web/share?code=" + shareCode,
								"User-Agent": utils.getRandomPCUA(),
							},
							onerror() {},
						}
					);
					log.info(getResp);
					if (!getResp.status) {
						let errorResultJSON = utils.toJSON(getResp.data.responseText);
						if (errorResultJSON["res_code"] in that.code) {
							Qmsg.error(that.code[errorResultJSON["res_code"]]);
						} else {
							Qmsg.error("请求异常");
						}
						return;
					}
					let data = utils.toJSON(getResp.data.responseText);
					if (data["res_code"] === 0) {
						return data;
					}
				};
				/**
				 * 获取分享信息
				 * @param {string} shareCode
				 * @returns
				 */
				this.getShareInfoByCodeV2 = async function (shareCode) {
					let postResp = await httpx.post({
						url: "https://cloud.189.cn/api/open/share/getShareInfoByCodeV2.action",
						data: `shareCode=${shareCode}`,
						headers: {
							Accept: "application/json;charset=UTF-8",
							"Content-Type": "application/x-www-form-urlencoded",
							"User-Agent": utils.getRandomPCUA(),
							"Sign-Type": 1,
							Referer: "https://cloud.189.cn/web/share?code=" + shareCode,
							Origin: "https://cloud.189.cn",
						},
						onerror() {},
					});
					if (!postResp.status) {
						let errorData = utils.toJSON(postResp.data.responseText);
						log.error(["获取下载参数失败的JSON信息", errorData]);
						if (errorData["res_code"] in that.code) {
							Qmsg.error(that.code[errorData["res_code"]]);
						} else {
							Qmsg.error(errorData["res_message"]);
						}
						return;
					}
					let postData = postResp.data;
					log.info(postData);
					let data = utils.toJSON(postData.responseText);
					if (data["res_code"] == 0) {
						return data;
					} else {
						if (that.code.hasOwnProperty(data["res_code"])) {
							Qmsg.error(that.code[data["res_code"]]);
						} else {
							Qmsg.error("获取FileId失败");
						}
					}
				};
				/**
				 * 获取shareId
				 * @returns {Promise<?number>}
				 */
				this.getShareId = async function (shareCode, accessCode) {
					let getResp = await httpx.get({
						url: `https://cloud.189.cn/api/open/share/checkAccessCode.action?shareCode=${shareCode}&accessCode=${accessCode}`,
						headers: {
							Accept: "application/json;charset=UTF-8",
							"Cache-Control": "no-cache",
							"User-Agent": utils.getRandomPCUA(),
							"Sign-Type": 1,
							Referer: `https://cloud.189.cn/web/share?code=${shareCode}`,
						},
						responseType: "json",
					});
					if (!getResp.status) {
						return;
					}
					let respData = getResp.data;
					log.info(respData);
					let data = utils.toJSON(respData.responseText);
					if (data["res_code"] === 0 && "shareId" in data) {
						return data["shareId"];
					} else {
						Qmsg.error("获取shareId失败");
						log.info(data);
					}
				};
				/**
				 * 获取随机noCache
				 * @returns {string}
				 */
				this.getNoCacheValue = function () {
					let result = "";
					for (let index = 0; index < 17; index++) {
						result += utils.getRandomValue(1, 9);
					}
					return "0." + result;
				};
				/**
				 * 获取下载链接
				 * @param {string} shareCode
				 * @param {string} accessCode
				 * @param {number} fileId
				 * @param {number} shareId
				 * @returns {Promise}
				 */
				this.getDownloadUrl = async function (
					shareCode,
					accessCode,
					fileId,
					shareId
				) {
					let getResp = await httpx.get({
						url: `https://cloud.189.cn/api/open/file/getFileDownloadUrl.action?fileId=${fileId}&dt=1&shareId=${shareId}`,
						headers: {
							Accept: "application/json;charset=UTF-8",
							"Cache-Control": "no-cache",
							"User-Agent": utils.getRandomPCUA(),
							Referer: `https://cloud.189.cn/web/share?code=${shareCode}`,
							"Sign-Type": 1,
						},
						responseType: "json",
						onerror() {},
					});
					log.info(getResp);
					if (!getResp.status) {
						let errorResultJSON = utils.toJSON(getResp.data.responseText);
						if (errorResultJSON["errorCode"] === "InvalidSessionKey") {
							that.gotoLogin(that.code["InvalidSessionKey"]);
						} else if (errorResultJSON["res_code"] in that.code) {
							Qmsg.error(that.code[errorResultJSON["res_code"]]);
						} else {
							Qmsg.error("请求异常");
						}
						return;
					}
					let respData = getResp.data;
					let data = utils.toJSON(respData.responseText);
					log.info(data);
					if (data["res_code"] === 0) {
						return data["fileDownloadUrl"];
					} else if (
						"InvalidSessionKey" === data["res_code"] ||
						"InvalidSessionKey" === data["errorCode"]
					) {
						that.gotoLogin(that.code["InvalidSessionKey"]);
					} else if (that.code.hasOwnProperty(data["res_code"])) {
						Qmsg.error(that.code[data["res_code"]]);
					} else {
						Qmsg.error("请求失败");
						log.error(respData);
					}
				};

				/**
				 * 天翼云登录弹窗
				 * @param {string} text 弹窗的显示的内容
				 */
				this.gotoLogin = function (text = "") {
					NetDiskPops.confirm(
						{
							title: {
								position: "center",
								text: "天翼云",
							},
							content: {
								text: text,
								html: false,
							},
							btn: {
								reverse: true,
								position: "end",
								ok: {
									text: "前往",
									enable: true,
									callback() {
										window.open(
											"https://cloud.189.cn/api/portal/loginUrl.action?redirectURL=https://cloud.189.cn/web/main",
											"_blank"
										);
									},
								},
							},
						},
						NetDiskUI.popsStyle.tianYiYunLoginTip
					);
				};
				/**
				 * 解析文件夹信息
				 */
				this.listShareDir = async function (
					shareCode,
					accessCode,
					pageNum = 1,
					pageSize = 60,
					fileId,
					shareDirFileId,
					isFolder = true,
					shareId,
					iconOption = 5,
					orderBy = "lastOpTime",
					descending = true
				) {
					/* Sessionkey: Sessionkey */
					let getResp = await httpx.get(
						`https://cloud.189.cn/api/open/share/listShareDir.action?pageNum=${pageNum}&pageSize=${pageSize}&fileId=${fileId}&shareDirFileId=${shareDirFileId}&isFolder=${isFolder}&shareId=${shareId}&shareMode=${shareMode}&iconOption=${iconOption}&orderBy=${orderBy}&descending=${descending}&accessCode=${accessCode}`,
						{
							headers: {
								Accept: "application/json;charset=UTF-8",
								Referer: `https://cloud.189.cn/web/share?code=${shareCode}`,
								"Sign-Type": 1,
								"User-Agent": utils.getRandomPCUA(),
							},
							responseType: "json",
							onerror() {},
						}
					);
					if (!getResp.status) {
						let errorData = utils.toJSON(getResp.data.responseText);
						log.error(["解析文件夹信息失败", errorData]);
						if (errorData["res_code"] in that.code) {
							Qmsg.error(that.code[errorData["res_code"]]);
						} else if ("res_message" in errorData) {
							Qmsg.error(errorData["res_message"]);
						} else {
							Qmsg.error("解析文件夹信息失败");
						}
						return;
					}
					let getData = getResp.data;
					log.info(getData);
					let data = utils.toJSON(getData.responseText);
					if (data["res_code"] == 0) {
						return data["fileListAO"];
					} else {
						if (that.code.hasOwnProperty(data["res_code"])) {
							Qmsg.error(that.code[data["res_code"]]);
						} else {
							Qmsg.error("获取FileId失败");
						}
					}
				};
				/**
				 * 获取直链弹窗的文件夹信息
				 */
				this.getFolderInfo = function (
					shareCode,
					accessCode,
					dirInfo,
					index = 0
				) {
					/**
					 * @type {import("@whitesev/pops/dist/types/src/components/folder/indexType").PopsFolderDataConfig[]}
					 */
					let folderInfoList = [];
					let tempFolderInfoList = [];
					let tempFolderFileInfoList = [];
					/* 文件夹 */
					dirInfo["folderList"].forEach((folderInfo) => {
						folderInfoList.push({
							fileName: folderInfo["name"],
							fileSize: 0,
							fileType: "",
							createTime: utils.formatToTimeStamp(folderInfo["createDate"]),
							latestTime: utils.formatToTimeStamp(folderInfo["lastOpTime"]),
							isFolder: true,
							index: index,
							async clickEvent() {
								let _folderInfo_ = await that.listShareDir(
									shareCode,
									accessCode,
									1,
									100,
									folderInfo["id"],
									folderInfo["id"],
									void 0,
									shareId,
									void 0,
									void 0,
									void 0,
									void 0
								);
								if (!_folderInfo_) {
									return [];
								}
								return that.getFolderInfo(
									shareCode,
									accessCode,
									_folderInfo_,
									index + 1
								);
							},
						});
					});
					/* 文件 */
					dirInfo["fileList"].forEach((fileInfo) => {
						folderInfoList.push({
							fileName: fileInfo["name"],
							fileSize: fileInfo["size"],
							fileType: "",
							createTime: utils.formatToTimeStamp(fileInfo["createDate"]),
							latestTime: utils.formatToTimeStamp(fileInfo["lastOpTime"]),
							isFolder: false,
							index: index,
							async clickEvent() {
								let downloadUrl = await that.getDownloadUrl(
									shareCode,
									accessCode,
									fileInfo["id"],
									shareId
								);
								if (downloadUrl) {
									if (NetDiskFilterScheme.isForwardDownloadLink("tianyiyun")) {
										downloadUrl = NetDiskFilterScheme.parseDataToSchemeUri(
											"tianyiyun",
											downloadUrl
										);
									}

									return {
										autoDownload: true,
										mode: "aBlank",
										url: downloadUrl,
									};
								}
							},
						});
					});
					tempFolderInfoList.sort((a, b) =>
						a["fileName"].localeCompare(b["fileName"])
					);
					tempFolderFileInfoList.sort((a, b) =>
						a["fileName"].localeCompare(b["fileName"])
					);
					folderInfoList = folderInfoList.concat(tempFolderInfoList);
					folderInfoList = folderInfoList.concat(tempFolderFileInfoList);
					log.info(["getFolderInfo", folderInfoList]);
					return folderInfoList;
				};
				return this;
			},
			/**
			 * 文叔叔
			 * @constructor
			 * @returns {object}
			 */
			wenshushu: function () {
				let that = this;
				/**
				 * 所在规则的下标
				 */
				this.netDiskIndex = 0;
				/**
				 * 分享码
				 */
				this.shareCode = "";
				/**
				 * 提取码
				 */
				this.accessCode = "";
				/**
				 * 用于header头x-token
				 * @type {string}
				 */
				let token = void 0;
				this.code = {
					1004: "no token",
					1008: "您没有权限访问",
					1013: "糟糕,此任务已过期销毁,下次要记得续期",
					1066: "对方设置的下载 / 预览次数已用完",
					1088: "糟糕,您访问的页面不存在",
				};
				this.init = async function (netDiskIndex, shareCode, accessCode) {
					log.info([netDiskIndex, shareCode, accessCode]);
					that.netDiskIndex = netDiskIndex;
					that.shareCode = shareCode;
					that.accessCode = accessCode;
					Qmsg.info("正在请求直链中...");
					let token = await this.getWssToken();
					if (!token) {
						return;
					}
					let pidInfo = await this.getPid();
					if (!pidInfo) {
						return;
					}
					await this.getFileNList(pidInfo.bid, pidInfo.pid);
				};
				/**
				 * 获取token
				 * wss:xxxxxx
				 * @returns {Promise<string>}
				 */
				this.getWssToken = async function () {
					let postResp = await httpx.post({
						url: "https://www.wenshushu.cn/ap/login/anonymous",
						responseType: "json",
						dataType: "json",
						data: JSON.stringify({
							dev_info: "{}",
						}),
						headers: {
							Accept: "application/json, text/plain, */*",
							"User-Agent": utils.getRandomAndroidUA(),
							Referer: "https://www.wenshushu.cn/f/" + that.shareCode,
						},
					});
					log.success(postResp);
					if (!postResp.status) {
						return;
					}
					let data = utils.toJSON(postResp.data.responseText);
					if (data["code"] === 0) {
						token = data["data"]["token"];
						return data["data"]["token"];
					} else if (data["code"] in that.code) {
						Qmsg.error(that.code[data["code"]]);
					} else {
						Qmsg.error("获取wss失败");
					}
				};
				/**
				 * 获取pid
				 * @returns {Promise<{bid:string,pid:string}> }
				 */
				this.getPid = async function () {
					let postResp = await httpx.post({
						url: "https://www.wenshushu.cn/ap/task/mgrtask",
						dataType: "json",
						responseType: "json",
						data: JSON.stringify({
							tid: that.shareCode,
							password: "",
							ufileid: "",
						}),
						headers: {
							Accept: "application/json, text/plain, */*",
							"User-Agent": utils.getRandomAndroidUA(),
							Referer: "https://www.wenshushu.cn/f/" + that.shareCode,
							"x-token": token,
						},
					});
					log.success(postResp);
					if (!postResp.status) {
						return;
					}
					let respData = postResp.data;
					let data = utils.toJSON(respData.responseText);
					if (data["code"] === 0) {
						return {
							bid: data["data"]["boxid"],
							pid: data["data"]["ufileid"],
						};
					} else if (data["code"] in that.code) {
						Qmsg.error(that.code[data["code"]]);
					} else {
						Qmsg.error("获取pid失败");
					}
				};
				/**
				 * 获取文件列表信息
				 * @param {string} bid
				 * @param {string} pid
				 * @returns
				 */
				this.getFileNList = async function (bid, pid) {
					let postResp = await httpx.post({
						url: "https://www.wenshushu.cn/ap/ufile/nlist",
						dataType: "json",
						responseType: "json",
						data: JSON.stringify({
							start: 0,
							sort: {
								name: "asc",
							},
							bid: bid,
							pid: pid,
							options: {
								uploader: "true",
							},
							size: 50,
						}),
						headers: {
							Accept: "application/json, text/plain, */*",
							"User-Agent": utils.getRandomAndroidUA(),
							Referer: "https://www.wenshushu.cn/f/" + that.shareCode,
							"x-token": token,
						},
					});
					log.success(postResp);
					if (!postResp.status) {
						return;
					}
					let respData = postResp.data;
					let jsonData = utils.toJSON(respData.responseText);
					if (jsonData["code"] === 0) {
						if (jsonData["data"]["fileList"][0]["type"] === 2) {
							Qmsg.error("该链接为多层级文件嵌套,跳转");
							NetDiskParse.blank(
								NetDiskParse.getBlankUrl(
									"wenshushu",
									that.netDiskIndex,
									that.shareCode,
									that.accessCode
								),
								"wenshushu",
								that.netDiskIndex,
								that.shareCode,
								that.accessCode
							);
						} else {
							await that.getDownloadUrl(jsonData["data"]["fileList"][0]);
						}
					} else if (jsonData["code"] in that.code) {
						Qmsg.error(that.code[jsonData["code"]]);
					} else {
						Qmsg.error("获取文件信息失败");
					}
				};
				/**
				 * 获取下载链接
				 * @param {object} data
				 * @returns {Promise}
				 */
				this.getDownloadUrl = async function (data) {
					let file_name = data.fname;
					let file_size = utils.formatByteToSize(data.size);
					let postResp = await httpx.post({
						url: "https://www.wenshushu.cn/ap/dl/sign",
						dataType: "json",
						responseType: "json",
						data: JSON.stringify({
							ufileid: data.fid,
							consumeCode: 0,
						}),
						headers: {
							Accept: "application/json, text/plain, */*",
							"User-Agent": utils.getRandomAndroidUA(),
							Referer: "https://www.wenshushu.cn/f/" + that.shareCode,
							"x-token": token,
						},
					});
					if (!postResp.status) {
						return;
					}
					log.success(postResp);
					let respData = postResp.data;
					let jsonData = utils.toJSON(respData.responseText);
					if (jsonData["code"] == 0) {
						let downloadUrl = jsonData["data"]["url"];
						if (downloadUrl === "") {
							Qmsg.error("对方的分享流量不足");
						} else {
							if (NetDiskFilterScheme.isForwardDownloadLink("wenshushu")) {
								downloadUrl = NetDiskFilterScheme.parseDataToSchemeUri(
									"wenshushu",
									downloadUrl
								);
							}

							/* 文叔叔没有上传时间信息(暂时是这样的) */
							NetDiskUI.staticView.oneFile({
								title: "文叔叔单文件直链",
								fileName: file_name,
								fileSize: file_size,
								downloadUrl: downloadUrl,
							});
						}
					} else if (jsonData["data"] in that.code) {
						Qmsg.error(that.code[jsonData["data"]]);
					} else {
						Qmsg.error("获取下载链接失败");
					}
				};
				return this;
			},
			/**
			 * 123盘
			 * @constructor
			 * @returns {object}
			 */
			_123pan: function () {
				let that = this;
				/**
				 * 所在规则的下标
				 */
				this.netDiskIndex = 0;
				/**
				 * 分享码
				 */
				this.shareCode = "";
				/**
				 * 提取码
				 */
				this.accessCode = "";
				this.code = {
					5103: "分享码错误或者分享地址错误",
					5104: "分享已过期",
					"-1000": "获取出错",
					"-2000": "请求异常",
					"-3000": "请求意外中止",
					"-4000": "请求超时",
					104: "文件已失效",
				};
				this.init = async function (netDiskIndex, shareCode, accessCode) {
					log.info([netDiskIndex, shareCode, accessCode]);
					that.netDiskIndex = netDiskIndex;
					that.shareCode = shareCode;
					that.accessCode = accessCode;
					that.panelList = [];
					that.Authorization = GM_getValue("_123pan_User_Authorization");
					let checkLinkValidityStatus = await that.checkLinkValidity();
					if (!checkLinkValidityStatus) {
						return;
					}
					let infoLists = await that.getFiles();
					if (!infoLists) {
						return;
					}
					if (infoLists.length === 1 && infoLists[0]["Type"] == 0) {
						let fileInfo = infoLists[0];
						if (fileInfo["Status"] == 104) {
							Qmsg.error("文件已失效");
							return;
						}
						let downloadUrl = fileInfo["DownloadUrl"];
						let fileSize = "";
						if (downloadUrl === "") {
							let downloadInfo = await that.getFileDownloadInfo(
								fileInfo["Etag"],
								fileInfo["FileId"],
								fileInfo["S3KeyFlag"],
								that.shareCode,
								fileInfo["Size"]
							);
							if (downloadInfo && downloadInfo["code"] === 0) {
								downloadUrl = downloadInfo["data"]["DownloadURL"];
								if (NetDiskFilterScheme.isForwardDownloadLink("_123pan")) {
									downloadUrl = NetDiskFilterScheme.parseDataToSchemeUri(
										"_123pan",
										downloadUrl
									);
								}
								fileSize = utils.formatByteToSize(fileInfo["Size"]);
							} else if (downloadInfo && downloadInfo["code"] === 401) {
								downloadUrl = "javascript:;";
								fileSize = "请登录后下载";
							} else {
								downloadUrl = "javascript:;";
								fileSize = "获取下载链接失败";
							}
						} else {
							if (NetDiskFilterScheme.isForwardDownloadLink("_123pan")) {
								downloadUrl = NetDiskFilterScheme.parseDataToSchemeUri(
									"_123pan",
									downloadUrl
								);
							}

							fileSize = utils.formatByteToSize(fileInfo["Size"]);
						}
						let fileUploadTime = new Date(fileInfo["CreateAt"]).getTime();
						let fileLatestTime = new Date(fileInfo["UpdateAt"]).getTime();
						fileUploadTime = utils.formatTime(fileUploadTime);
						fileLatestTime = utils.formatTime(fileLatestTime);
						NetDiskUI.staticView.oneFile({
							title: "123盘单文件直链",
							fileName: fileInfo["FileName"],
							fileSize: fileSize,
							downloadUrl: downloadUrl,
							fileUploadTime: fileUploadTime,
							fileLatestTime: fileLatestTime,
						});
					} else {
						Qmsg.info("正在递归文件");
						let QmsgLoading = Qmsg.loading(`正在解析多文件中,请稍后...`);
						let folderInfoList = that.getFolderInfo(infoLists, 0);
						QmsgLoading.close();
						log.info("递归完毕");
						NetDiskUI.staticView.moreFile("123盘文件解析", folderInfoList);
					}
				};
				/**
				 * 校验链接有效性
				 * @returns {boolean}
				 */
				this.checkLinkValidity = async function () {
					Qmsg.info("正在校验链接有效性");
					let url = `https://www.123pan.com/s/${that.shareCode}`;

					let getResp = await httpx.get({
						url: url,
						headers: {
							"User-Agent": utils.getRandomPCUA(),
							Referer: "https://www.123pan.com",
						},
					});
					log.info(getResp);
					if (!getResp.status) {
						return false;
					}
					let respData = getResp.data;
					let g_initialPropsMatch = respData.responseText.match(
						/window.g_initialProps[\s]*=[\s]*\{(.+?)\};/s
					);
					if (g_initialPropsMatch) {
						log.info(g_initialPropsMatch);
						let g_initialProps = utils.toJSON(
							`{${g_initialPropsMatch[g_initialPropsMatch.length - 1]}}`
						);
						log.info(g_initialProps);
						if (g_initialProps.res.code !== 0) {
							Qmsg.error(g_initialProps.res.message);
							return false;
						}
						let HasPwd = g_initialProps.res.data.HasPwd;
						if (
							HasPwd &&
							(that.accessCode == void 0 || that.accessCode === "")
						) {
							/* 该链接需要密码但是没有获取到 */
							Qmsg.error("密码缺失!");
							NetDiskUI.newAccessCodeView(
								"密码缺失",
								"_123pan",
								that.netDiskIndex,
								that.shareCode,
								(userInputAccessCode) => {
									that.init(
										that.netDiskIndex,
										that.shareCode,
										userInputAccessCode
									);
								}
							);
						} else {
							/* 该链接不需要密码 || 该链接需要密码且已获取到 */
							return true;
						}
					} else {
						Qmsg.error("校验链接-获取初始化内容失败");
					}
				};
				/**
				 * 获取文件
				 * @param {number} parentFileId
				 * @returns {Promise<?{
				 * Category: number,
				 * ContentType: string,
				 * CreateAt: number,
				 * DownloadUrl: string,
				 * Etag: string,
				 * FileId: number,
				 * FileName: string,
				 * ParentFileId: number,
				 * PunishFlag: number,
				 * S3KeyFlag: number,
				 * Size: number,
				 * Status: number,
				 * StorageNode: string,
				 * Type: 0|1,
				 * UpdateAt: string,
				 * }[]>}
				 */
				this.getFiles = async function (parentFileId = 0) {
					let url = `https://www.123pan.com/b/api/share/get?limit=100&next=1&orderBy=share_id&orderDirection=desc&shareKey=${that.shareCode}&SharePwd=${that.accessCode}&ParentFileId=${parentFileId}&Page=1`;
					let getResp = await httpx.get({
						url: url,
						headers: {
							Accept: "*/*",
							"User-Agent": utils.getRandomPCUA(),
							Referer: `https://www.123pan.com/s/${that.shareCode}`,
						},
					});
					log.info(getResp);
					if (!getResp.status) {
						return;
					}
					let respData = getResp.data;
					let json_data = utils.toJSON(respData.responseText);
					if (json_data["code"] === 0) {
						let infoList = json_data["data"]["InfoList"];
						return infoList;
					} else if (json_data["code"] === 5103) {
						NetDiskUI.newAccessCodeView(
							void 0,
							"_123pan",
							that.netDiskIndex,
							that.shareCode,
							(userInputAccessCode) => {
								that.init(
									that.netDiskIndex,
									that.shareCode,
									userInputAccessCode
								);
							}
						);
					} else if (that.code[json_data["code"]]) {
						Qmsg.error(that.code[json_data["code"]]);
					} else if ("message" in json_data) {
						Qmsg.error(json_data["message"]);
					} else {
						Qmsg.error("123盘:未知的JSON格式");
					}
				};
				/**
				 * 递归算法使用的请求
				 * @param {string} parentFileId
				 * @returns {Promise<?{
				 * Category: number,
				 * ContentType: string,
				 * CreateAt: number,
				 * DownloadUrl: string,
				 * Etag: string,
				 * FileId: number,
				 * FileName: string,
				 * ParentFileId: number,
				 * PunishFlag: number,
				 * S3KeyFlag: number,
				 * Size: number,
				 * Status: number,
				 * StorageNode: string,
				 * Type: 0|1,
				 * UpdateAt: string,
				 * }[]>}
				 */
				this.getFilesByRec = async function (parentFileId) {
					let getResp = await httpx.get({
						url: `https://www.123pan.com/b/api/share/get?limit=100&next=1&orderBy=share_id&orderDirection=desc&shareKey=${that.shareCode}&SharePwd=${that.accessCode}&ParentFileId=${parentFileId}&Page=1`,
						headers: {
							Accept: "*/*",
							"User-Agent": utils.getRandomAndroidUA(),
							Referer: `https://www.123pan.com/s/${that.shareCode}`,
						},
					});
					if (!getResp.status) {
						return;
					}
					let respData = getResp.data;
					log.info(respData);
					let jsonData = utils.toJSON(respData.responseText);
					if (jsonData["code"] == 0) {
						return jsonData["data"]["InfoList"];
					}
				};
				/**
				 * 获取文件夹信息
				 * @param {{
				 * Category: number,
				 * ContentType: string,
				 * CreateAt: number,
				 * DownloadUrl: string,
				 * Etag: string,
				 * FileId: number,
				 * FileName: string,
				 * ParentFileId: number,
				 * PunishFlag: number,
				 * S3KeyFlag: number,
				 * Size: number,
				 * Status: number,
				 * StorageNode: string,
				 * Type: 0|1,
				 * UpdateAt: string,
				 * }[]} infoList
				 * @returns {Promise<{
				 * fileName: string,
				 * fileSize: string|number,
				 * fileType: ?string,
				 * createTime: ?string,
				 * latestTime: ?string,
				 * isFolder: boolean,
				 * index: ?number,
				 * clickCallBack: ?(event:Event,_config_: object)=>{}
				 * }[]>}
				 */
				this.getFolderInfo = function (infoList, index) {
					let folderInfoList = [];
					let tempFolderInfoList = [];
					/**
					 * @type {PopsFolderDataConfig[]}
					 */
					let tempFolderFileInfoList = [];
					infoList.forEach((item) => {
						if (item.Type) {
							/* 文件夹 */
							tempFolderInfoList.push({
								fileName: item.FileName,
								fileSize: 0,
								fileType: "",
								createTime: new Date(item.CreateAt).getTime(),
								latestTime: new Date(item.UpdateAt).getTime(),
								isFolder: true,
								index: index,
								async clickEvent() {
									let resultFileInfoList = await that.getFilesByRec(
										item["FileId"]
									);
									if (resultFileInfoList) {
										return that.getFolderInfo(resultFileInfoList, index + 1);
									} else {
										return [];
									}
								},
							});
						} else {
							/* 文件 */
							tempFolderFileInfoList.push({
								fileName: item.FileName,
								fileSize: item.Size,
								fileType: "",
								createTime: new Date(item.CreateAt).getTime(),
								latestTime: new Date(item.UpdateAt).getTime(),
								isFolder: false,
								index: index,
								async clickEvent() {
									if (item.Status == 104) {
										Qmsg.error("文件已失效");
									} else if (!Boolean(item.DownloadUrl)) {
										let downloadInfo = await that.getFileDownloadInfo(
											item["Etag"],
											item["FileId"],
											item["S3KeyFlag"],
											that.shareCode,
											item["Size"]
										);
										if (downloadInfo && downloadInfo["code"] === 0) {
											return {
												url: downloadInfo["data"]["DownloadURL"],
												autoDownload: true,
												mode: "aBlank",
											};
										} else if (downloadInfo && downloadInfo["code"] === 401) {
											Qmsg.error("请登录后下载");
										} else {
											Qmsg.error("获取下载链接失败");
										}
									} else {
										let downloadUrl = item.DownloadUrl;
										if (NetDiskFilterScheme.isForwardDownloadLink("_123pan")) {
											downloadUrl = NetDiskFilterScheme.parseDataToSchemeUri(
												"_123pan",
												downloadUrl
											);
										}
										return {
											url: downloadUrl,
											autoDownload: true,
											mode: "aBlank",
										};
									}
								},
							});
						}
					});
					tempFolderInfoList.sort((a, b) =>
						a["fileName"].localeCompare(b["fileName"])
					);
					tempFolderFileInfoList.sort((a, b) =>
						a["fileName"].localeCompare(b["fileName"])
					);
					folderInfoList = folderInfoList.concat(tempFolderInfoList);
					folderInfoList = folderInfoList.concat(tempFolderFileInfoList);
					return folderInfoList;
				};
				/**
				 * 获取单文件下载链接
				 * 123云盘新增了下载验证
				 * @param {string} Etag
				 * @param {string} FileID
				 * @param {string} S3keyFlag
				 * @param {string} ShareKey
				 * @param {string} Size
				 * @returns
				 */
				this.getFileDownloadInfo = async function (
					Etag,
					FileID,
					S3keyFlag,
					ShareKey,
					Size
				) {
					let authK_V = that.getFileDownloadAuth();
					let headers = {
						"App-Version": "3",
						Platform: "web",
						"Content-Type": "application/json;charset=UTF-8",
						Host: "www.123pan.com",
						Accept: "*/*",
						"User-Agent": utils.getRandomPCUA(),
						Referer: "https://www.123pan.com/s/" + ShareKey,
						Origin: "https://www.123pan.com",
					};
					if (that.Authorization) {
						headers["Authorization"] = "Bearer " + that.Authorization;
					}
					log.success("获取下载链接加密参数:" + authK_V);
					let postResp = await httpx.post({
						url: `https://www.123pan.com/a/api/share/download/info?${authK_V[0]}=${authK_V[1]}`,
						data: JSON.stringify({
							Etag: Etag,
							FileID: FileID,
							S3keyFlag: S3keyFlag,
							ShareKey: ShareKey,
							Size: Size,
						}),
						responseType: "json",
						headers: headers,
					});
					if (!postResp.status) {
						return;
					}
					let postData = postResp.data;
					let jsonData = utils.toJSON(postData.responseText);
					log.info(jsonData);
					if (jsonData["code"] == 0) {
						jsonData["data"]["DownloadURL"] = await that.decodeDownloadUrl(
							jsonData["data"]["DownloadURL"]
						);
						return jsonData;
					} else {
						return {
							code: jsonData["code"],
						};
					}
				};
				/**
				 * 获取单文件下载链接的加密参数
				 * 感谢:https://github.com/qaiu/netdisk-fast-download/
				 */
				this.getFileDownloadAuth = function () {
					function encry_time(param) {
						var param_time,
							param_other =
								arguments["length"] > 0x2 && void 0x0 !== arguments[0x2]
									? arguments[0x2]
									: 0x8;
						if (0x0 === arguments["length"]) return void 0;
						"object" === typeof param
							? (param_time = param)
							: (0xa === ("" + param)["length"] &&
									(param = 0x3e8 * parseInt(param)),
							  (param_time = new Date(param)));
						var param_timezoneoffset =
								param + 0xea60 * new Date(param)["getTimezoneOffset"](),
							param_time_n = param_timezoneoffset + 0x36ee80 * param_other;
						return (
							(param_time = new Date(param_time_n)),
							{
								y: param_time["getFullYear"](),
								m:
									param_time["getMonth"]() + 0x1 < 0xa
										? "0" + (param_time["getMonth"]() + 0x1)
										: param_time["getMonth"]() + 0x1,
								d:
									param_time["getDate"]() < 0xa
										? "0" + param_time["getDate"]()
										: param_time["getDate"](),
								h:
									param_time["getHours"]() < 0xa
										? "0" + param_time["getHours"]()
										: param_time["getHours"](),
								f:
									param_time["getMinutes"]() < 0xa
										? "0" + param_time["getMinutes"]()
										: param_time["getMinutes"](),
							}
						);
					}

					function encry_join(param) {
						for (
							var a =
									arguments["length"] > 0x1 && void 0x0 !== arguments[0x1]
										? arguments[0x1]
										: 0xa,
								funcRun = function () {
									for (var b, c = [], d = 0x0; d < 0x100; d++) {
										b = d;
										for (var index = 0x0; index < 0x8; index++)
											b = 0x1 & b ? 0xedb88320 ^ (b >>> 0x1) : b >>> 0x1;
										c[d] = b;
									}
									return c;
								},
								_funcRun_ = funcRun(),
								_param = param,
								_param_1 = -0x1,
								_param_0 = 0x0;
							_param_0 < _param["length"];
							_param_0++
						)
							_param_1 =
								(_param_1 >>> 0x8) ^
								_funcRun_[0xff & (_param_1 ^ _param.charCodeAt(_param_0))];
						return (_param_1 = (-0x1 ^ _param_1) >>> 0x0), _param_1.toString(a);
					}

					function getSign(urlPath) {
						var param_web = "web";
						var param_type = 3;
						var param_time = Math.round(
							(new Date().getTime() +
								0x3c * new Date().getTimezoneOffset() * 0x3e8 +
								28800000) /
								0x3e8
						).toString();
						var key = "a,d,e,f,g,h,l,m,y,i,j,n,o,p,k,q,r,s,t,u,b,c,v,w,s,z";
						var randomRoundNum = Math["round"](0x989680 * Math["random"]());

						var number_split;
						var time_a;
						var time_y;
						var time_m;
						var time_d;
						var time_h;
						var time_f;
						var time_array;
						var time_push;
						for (var number_item in ((number_split = key.split(",")),
						(time_a = encry_time(param_time)),
						(time_y = time_a["y"]),
						(time_m = time_a["m"]),
						(time_d = time_a["d"]),
						(time_h = time_a["h"]),
						(time_f = time_a["f"]),
						(time_array = [time_y, time_m, time_d, time_h, time_f].join("")),
						(time_push = []),
						time_array))
							time_push["push"](number_split[Number(time_array[number_item])]);
						var param_no;
						var param_join_s;
						return (
							(param_no = encry_join(time_push["join"](""))),
							(param_join_s = encry_join(
								""
									["concat"](param_time, "|")
									["concat"](randomRoundNum, "|")
									["concat"](urlPath, "|")
									["concat"](param_web, "|")
									["concat"](param_type, "|")
									["concat"](param_no)
							)),
							[
								param_no,
								""
									["concat"](param_time, "-")
									["concat"](randomRoundNum, "-")
									["concat"](param_join_s),
							]
						);
					}
					return getSign("/a/api/share/download/info");
				};
				/**
				 * 将直链的param参数解析成真正的直链
				 * @param {string} url
				 */
				this.decodeDownloadUrl = async function (url) {
					if (url === "") {
						return "";
					}
					let decodeURL = new URL(url);
					let params = decodeURL.search.replace(/^\?params=/gi, "");
					params = params.split("&")[0];
					try {
						let newDecodeUrl = decodeURI(atob(params));
						log.info("正在获取重定向直链");
						Qmsg.info("正在获取重定向直链");
						let getResp = await httpx.get({
							url: newDecodeUrl,
							responseType: "json",
							headers: {
								"User-Agent": utils.getRandomAndroidUA(),
								Referer: "https://www.123pan.com/s/" + that.shareCode,
								Origin: "https://www.123pan.com",
							},
							onerror: function () {},
						});
						log.info(getResp);
						if (!getResp.status && getResp.data.status !== 210) {
							/* 很奇怪,123盘返回的状态码是210 */
							// 这里还会有另一种情况,请求失败时,getResp.data内是数组[response],status不存在!!
							// 先转为URL对象看看auto_redirect是否存在,存在就设置1自动重定向
							let parseUrl = new URL(newDecodeUrl);
							if (parseUrl.searchParams.has("auto_redirect")) {
								parseUrl.searchParams.set("auto_redirect", "1");
								return parseUrl.toString();
							}
							return newDecodeUrl;
						}
						let respData = getResp.data;
						let resultJSON = utils.toJSON(respData.responseText);
						let newURL = new URL(resultJSON.data.redirect_url);
						newURL.searchParams.set("auto_redirect", "1");
						log.success(resultJSON);
						return newURL.toString();
					} catch (error) {
						log.error(error);
						return url;
					}
				};
				return this;
			},
			/**
			 * 坚果云
			 * @constructor
			 * @returns {object}
			 */
			jianguoyun: function () {
				let that = this;
				/**
				 * 所在规则的下标
				 */
				this.netDiskIndex = 0;
				/**
				 * 分享码
				 */
				this.shareCode = "";
				/**
				 * 提取码
				 */
				this.accessCode = "";
				this.errorCode = {
					UnAuthorized: "请先登录坚果云账号",
				};
				this.init = async function (netDiskIndex, shareCode, accessCode) {
					log.info([netDiskIndex, shareCode, accessCode]);
					that.netDiskIndex = netDiskIndex;
					that.shareCode = shareCode;
					that.accessCode = accessCode;
					let downloadParams = await that.getRequestDownloadParams();
					if (!downloadParams) {
						return;
					}
					if (downloadParams["isdir"]) {
						/* 是文件夹 */
						let Qmsg_loading = Qmsg.loading("正在遍历多文件信息...");
						let folderInfo = await that.getFolderInfo(downloadParams["hash"]);
						if (!folderInfo) {
							Qmsg_loading.close();
							return;
						}
						let newFolderInfoList = that.parseMoreFile(
							folderInfo,
							downloadParams["hash"],
							downloadParams["name"]
						);
						Qmsg_loading.close();

						/* 坚果云盘没有上传时间信息(暂时是这样的) */
						NetDiskUI.staticView.moreFile("坚果云文件解析", newFolderInfoList);
					} else {
						/* 是文件 */
						let fileSize = utils.formatByteToSize(downloadParams["size"]);
						let downloadUrl = await that.getFileLink(
							downloadParams.hash,
							downloadParams.name
						);
						if (!downloadUrl) {
							return;
						}
						if (NetDiskFilterScheme.isForwardDownloadLink("jianguoyun")) {
							downloadUrl = NetDiskFilterScheme.parseDataToSchemeUri(
								"jianguoyun",
								downloadUrl
							);
						}

						log.info(downloadUrl);
						/* 坚果云盘没有上传时间信息(暂时是这样的) */
						NetDiskUI.staticView.oneFile({
							title: "坚果云盘单文件直链",
							fileName: downloadParams["name"],
							fileSize: fileSize,
							downloadUrl: downloadUrl,
						});
					}
				};
				/**
				 * 解析多文件信息
				 * @param {{
				 * mtime: number,
				 * relPath: string,
				 * size: number,
				 * tblUri: ?string,
				 * type: "file"|string,
				 * }[]} folderInfo
				 * @param {string} hash 文件hash值
				 * @param {string} fileName 文件名
				 * @returns {{
				 * fileName: string,
				 * fileSize: string|number,
				 * fileType: ?string,
				 * createTime: ?string,
				 * latestTime: ?string,
				 * isFolder: boolean,
				 * index: ?number,
				 * clickCallBack: ?(event:Event,_config_: object)=>{}
				 * }[]}
				 */
				this.parseMoreFile = function (folderInfo, hash = "", fileName = "") {
					log.info(["解析多文件信息", folderInfo]);
					/**
					 * @type {PopsFolderDataConfig[]}
					 */
					let folderInfoList = [];
					folderInfo.forEach((item) => {
						let fileName = item.relPath;
						if (fileName.startsWith("/")) {
							fileName = fileName.replace(/^\//, "");
						}
						folderInfoList.push({
							fileName: fileName,
							fileSize: item["size"],
							fileType: "",
							createTime: item.mtime,
							latestTime: item.mtime,
							isFolder: false,
							index: 0,
							async clickEvent() {
								Qmsg.info("正在获取下载链接...");
								let downloadUrl = await that.getDirLink(
									hash,
									fileName,
									item["relPath"]
								);
								if (!downloadUrl) {
									return;
								}
								Qmsg.success("获取成功!");
								if (NetDiskFilterScheme.isForwardDownloadLink("jianguoyun")) {
									downloadUrl = NetDiskFilterScheme.parseDataToSchemeUri(
										"jianguoyun",
										downloadUrl
									);
								}

								log.info(downloadUrl);
								return {
									autoDownload: true,
									mode: "aBlank",
									url: downloadUrl,
								};
							},
						});
					});
					return folderInfoList;
				};
				/**
				 * 获取下载链接所需要的hash值和name
				 */
				this.getRequestDownloadParams = async function () {
					log.info("获取hash值");
					Qmsg.info("正在获取请求信息");
					let pageInfoRegexp = /var[\s]*PageInfo[\s]*=[\s]*{([\s\S]+)};/i;
					let formData = new FormData();
					formData.append("pd", that.accessCode);
					let requestDetails = {
						url: `https://www.jianguoyun.com/p/${that.shareCode}`,
						data: that.accessCode === "" ? void 0 : `pd=${that.accessCode}`,
						responseType: "html",
						headers: {
							"Content-Type": "application/x-www-form-urlencoded",
							"User-Agent": utils.getRandomPCUA(),
							Referer: `https://www.jianguoyun.com/p/${that.shareCode}`,
						},
					};
					let requestResp = void 0;
					if (that.accessCode === "") {
						requestResp = await httpx.get(requestDetails);
					} else {
						requestResp = await httpx.post(requestDetails);
					}
					if (!requestResp.status) {
						return;
					}
					let respData = requestResp.data;
					log.info("请求信息");
					log.info(respData);
					let pageInfo = respData.responseText.match(pageInfoRegexp);
					if (pageInfo) {
						pageInfo = pageInfo[pageInfo.length - 1];
						pageInfo = `({${pageInfo}})`;
						pageInfo = eval(pageInfo);
						log.info(pageInfo);
						let fileName = pageInfo["name"];
						let fileSize = pageInfo["size"];
						let fileHash = pageInfo["hash"];
						let fileNeedsPassword = pageInfo["needsPassword"];
						let fileOwner = pageInfo["owner"];
						let isdir = pageInfo["isdir"];
						let fileErrorCode = pageInfo["errorCode"];
						fileName = decodeURIComponent(fileName);
						log.success("是否是文件夹 ===> " + isdir);
						log.success("hash ===> " + fileHash);
						log.success("name ===> " + fileName);
						log.success("size ===> " + fileSize);
						if (
							fileNeedsPassword &&
							(that.accessCode == void 0 || that.accessCode === "")
						) {
							/* 需要密码但没密码 */
							Qmsg.error("密码不正确!");
							NetDiskUI.newAccessCodeView(
								"密码缺失",
								"jianguoyun",
								that.netDiskIndex,
								that.shareCode,
								(userInputAccessCode) => {
									that.init(
										that.netDiskIndex,
										that.shareCode,
										userInputAccessCode
									);
								}
							);
							return;
						}
						if (fileErrorCode === "AuthenticationFailed") {
							Qmsg.error("密码错误");
							NetDiskUI.newAccessCodeView(
								void 0,
								"jianguoyun",
								that.netDiskIndex,
								that.shareCode,
								(userInputAccessCode) => {
									that.init(
										that.netDiskIndex,
										that.shareCode,
										userInputAccessCode
									);
								}
							);
							return;
						}
						if (fileHash === "" || fileHash == void 0) {
							log.error("hash为空,可能文件被撤销分享了");
							Qmsg.error(`文件分享已被撤销`);
							return;
						}
						if (fileSize == void 0 && isdir == false) {
							log.error("无size,可能文件被删除了");
							Qmsg.error(`“${fileName}”文件已被拥有者(“${fileOwner}”)删除`);
							return;
						} else {
							return {
								name: fileName,
								hash: fileHash,
								size: fileSize,
								needsPassword: fileNeedsPassword,
								owner: fileOwner,
								isdir: isdir,
							};
						}
					} else if (
						respData.responseText.match("对不起,找不到您指定的文件。")
					) {
						log.error("啊噢! (404) 对不起,找不到您指定的文件。");
						Qmsg.error("坚果云: 对不起,找不到您指定的文件。");
					} else if (
						respData.responseText.match("对不起,您的某些输入不正确。")
					) {
						log.error("可能该链接不需要访问码或者访问码有问题");
						NetDiskUI.newAccessCodeView(
							void 0,
							"jianguoyun",
							that.netDiskIndex,
							that.shareCode,
							(userInputAccessCode) => {
								that.init(
									that.netDiskIndex,
									that.shareCode,
									userInputAccessCode
								);
							}
						);
					} else {
						log.error("获取PageInfo失败");
						Qmsg.error("坚果云: 获取PageInfo失败");
					}
				};
				/**
				 * 获取下载链接
				 * @param {string} fileHash 文件hash值
				 * @param {string} fileName 文件名
				 * @returns {Promise}
				 */
				this.getFileLink = async function (fileHash = "", fileName = "") {
					fileName = encodeURIComponent(fileName);
					let getResp = await httpx.get({
						url: `https://www.jianguoyun.com/d/ajax/fileops/pubFileLink?k=${fileHash}&name=${fileName}&wm=false${
							that.accessCode === "" ? "" : "&pd=" + that.accessCode
						}&forwin=1&_=${new Date().getTime()}`,
						responseType: "json",
						headers: {
							"User-Agent": utils.getRandomPCUA(),
						},
						onerror: function () {},
					});
					if (!getResp.status) {
						if (utils.isNotNull(getResp.data?.responseText)) {
							let errorData = utils.toJSON(getResp.data.responseText);
							log.error(["坚果云", errorData]);
							if (errorData["errorCode"] === "UnAuthorized") {
								that.gotoLogin();
							} else {
								Qmsg.error(errorData["detailMsg"]);
							}
						} else {
							Qmsg.error("请求异常");
						}
						return;
					}
					let respData = getResp.data;
					log.info(["请求信息", respData]);
					let resultJSON = utils.toJSON(respData.responseText);
					log.info(["解析JSON", resultJSON]);
					if (resultJSON.hasOwnProperty("errorCode")) {
						Qmsg.error("坚果云: " + resultJSON["detailMsg"]);
						return;
					} else if (resultJSON.hasOwnProperty("url")) {
						return resultJSON["url"];
					} else {
						Qmsg.error("坚果云: 处理下载链接异常");
					}
				};
				/**
				 * 获取文件夹下的文件下载链接
				 * @param {string} fileHash
				 * @param {string} fileName
				 * @param {string} filePath
				 * @returns {Promise}
				 */
				this.getDirLink = async function (
					fileHash = "",
					fileName = "",
					filePath = "/"
				) {
					fileName = encodeURIComponent(fileName);
					let getResp = await httpx.get({
						url: `https://www.jianguoyun.com/d/ajax/dirops/pubDIRLink?k=${fileHash}&dn=${fileName}&p=${filePath}&forwin=1&_=${new Date().getTime()}`,
						responseType: "json",
						headers: {
							"User-Agent": utils.getRandomPCUA(),
						},
						onerror: function () {},
					});
					if (!getResp.status) {
						if (utils.isNotNull(getResp.data?.responseText)) {
							let errorData = utils.toJSON(getResp.data.responseText);
							log.error(["坚果云", errorData]);
							if (errorData["errorCode"] === "UnAuthorized") {
								that.gotoLogin();
							} else {
								Qmsg.error(errorData["detailMsg"]);
							}
						} else {
							Qmsg.error("请求异常");
						}
						return;
					}
					let respData = getResp.data;
					log.info(["请求信息", respData]);
					let resultJSON = utils.toJSON(respData.responseText);
					log.info(resultJSON);
					if (resultJSON.hasOwnProperty("errorCode")) {
						Qmsg.error("坚果云: " + resultJSON["detailMsg"]);
						return;
					} else if (resultJSON.hasOwnProperty("url")) {
						return resultJSON["url"];
					} else {
						Qmsg.error("坚果云: 处理下载链接异常");
					}
				};
				/**
				 * 获取文件夹信息
				 * @param {string} hash
				 * @returns
				 */
				this.getFolderInfo = async function (hash = "") {
					let getResp = await httpx.get({
						url: `https://www.jianguoyun.com/d/ajax/dirops/pubDIRBrowse?hash=${hash}&relPath=%2F&_=${new Date().getTime()}`,
						responseType: "json",
						headers: {
							"User-Agent": utils.getRandomPCUA(),
						},
					});
					if (!getResp.status) {
						return;
					}
					let respData = getResp.data;
					log.info(["请求信息", respData]);
					let resultJSON = utils.toJSON(respData.responseText);
					log.info(resultJSON);
					if ("objects" in resultJSON) {
						return resultJSON["objects"];
					} else {
						Qmsg.error("坚果云: 处理多文件信息异常");
					}
				};
				/**
				 * 前往登录
				 */
				this.gotoLogin = function () {
					NetDiskPops.confirm(
						{
							title: {
								text: "提示",
								position: "center",
							},
							content: {
								text: `解析失败,原因:当前尚未登录坚果云,是否前往登录?`,
							},
							btn: {
								reverse: true,
								position: "end",
								ok: {
									text: "前往",
									callback: function (_event_) {
										window.open(
											"https://www.jianguoyun.com/d/login#from=https%3A%2F%2Fwww.jianguoyun.com%2F",
											"_blank"
										);
									},
								},
							},
						},
						NetDiskUI.popsStyle.jianGuoYunLoginTip
					);
				};
				return this;
			},
			/**
			 * 奶牛快传
			 * 感谢:https://github.com/qaiu/netdisk-fast-download
			 * @constructor
			 * @returns {object}
			 */
			nainiu: function () {
				let that = this;
				/**
				 * 所在规则的下标
				 */
				this.netDiskIndex = 0;
				/**
				 * 分享码
				 */
				this.shareCode = "";
				/**
				 * 提取码
				 */
				this.accessCode = "";
				const OK_CODE = "0000";
				this.init = async function (netDiskIndex, shareCode, accessCode) {
					log.info([netDiskIndex, shareCode, accessCode]);
					that.netDiskIndex = netDiskIndex;
					that.shareCode = shareCode;
					that.accessCode = accessCode;
					that.panelList = [];
					that.panelContent = "";
					let checkLinkValidityInfo = await that.checkLinkValidity(
						that.shareCode,
						that.accessCode
					);
					if (!checkLinkValidityInfo) {
						return;
					}
					if (checkLinkValidityInfo.isFolder) {
						/* 多文件 */
						Qmsg.info("正在递归文件");
						let QmsgLoading = Qmsg.loading(`正在解析多文件中,请稍后...`);
						let firstFolderInfo = await that.getShareFolder(
							checkLinkValidityInfo["data"]["guid"]
						);
						if (!firstFolderInfo) {
							QmsgLoading.close();
							return;
						}
						let firstFileInfo = await that.getShareFiles(
							checkLinkValidityInfo["data"]["guid"]
						);
						if (!firstFileInfo) {
							QmsgLoading.close();
							return;
						}
						let folderInfoList = that.getFolderInfo(
							checkLinkValidityInfo["data"]["guid"],
							firstFolderInfo,
							firstFileInfo,
							0
						);
						QmsgLoading.close();
						log.info("递归完毕");
						NetDiskUI.staticView.moreFile("奶牛快传文件解析", folderInfoList);
					} else {
						/* 单文件 */
						let downloadUrl = void 0;
						if (checkLinkValidityInfo["zipDownload"]) {
							downloadUrl = await that.getZipFileDownloadUrl(
								that.shareCode,
								checkLinkValidityInfo["guid"],
								checkLinkValidityInfo["fileName"]
							);
						} else {
							downloadUrl = await that.getDownloadUrl(
								that.shareCode,
								checkLinkValidityInfo["guid"],
								checkLinkValidityInfo["id"]
							);
						}
						if (!downloadUrl) {
							return;
						}
						if (NetDiskFilterScheme.isForwardDownloadLink("nainiu")) {
							downloadUrl = NetDiskFilterScheme.parseDataToSchemeUri(
								"nainiu",
								downloadUrl
							);
						}

						NetDiskUI.staticView.oneFile({
							title: "奶牛快传单文件直链",
							fileName: checkLinkValidityInfo["fileName"],
							fileType: checkLinkValidityInfo["fileType"],
							fileSize: checkLinkValidityInfo["fileSize"],
							downloadUrl: downloadUrl,
							fileUploadTime: checkLinkValidityInfo["fileUploadTime"],
							fileLatestTime: checkLinkValidityInfo["fileLatestTime"],
							clickCallBack: (_fileDetails_) => {
								that.downloadFile(
									checkLinkValidityInfo["fileName"],
									downloadUrl
								);
							},
						});
					}
				};
				/**
				 * 校验链接有效性并解析获取信息
				 * @param {string} shareCode
				 * @param {string} accessCode
				 * @param {boolean|object}
				 */
				this.checkLinkValidity = async function (shareCode, accessCode) {
					let resultJSON = await that.getShareByUniqueUrl(shareCode);
					if (!resultJSON) {
						return false;
					}
					let code = resultJSON["code"];
					let message = resultJSON["message"];
					if (code !== OK_CODE) {
						Qmsg.error(message);
						return false;
					} else {
						let needPassword = resultJSON["data"]["needPassword"];
						let zipDownload = resultJSON["data"]["zipDownload"];
						if (needPassword && utils.isNull(accessCode)) {
							Qmsg.error("密码缺失!");
							NetDiskUI.newAccessCodeView(
								"密码缺失",
								"nainiu",
								that.netDiskIndex,
								that.shareCode,
								(userInputAccessCode) => {
									that.init(
										that.netDiskIndex,
										that.shareCode,
										userInputAccessCode
									);
								}
							);
							return false;
						} else if (zipDownload) {
							/* 压缩包下载 */
							Qmsg.success("该链接为zip单文件");
							return {
								zipDownload: zipDownload,
								guid: resultJSON["data"]["guid"],
								fileSize: utils.formatByteToSize(
									resultJSON["data"]["firstFolder"]["size"]
								),
								fileName: resultJSON["data"]["firstFolder"]["title"],
								fileUploadTime: utils.formatTime(
									resultJSON["data"]["firstFolder"]["created_at"]
								),
								fileLatestTime: utils.formatTime(
									resultJSON["data"]["firstFolder"]["updated_at"]
								),
							};
						} else if (resultJSON["data"]["firstFile"] == void 0) {
							/* 文件夹类型 */
							Qmsg.success("该链接为文件夹类型");
							return {
								isFolder: true,
								guid: resultJSON["data"]["guid"],
								firstFolder: resultJSON["data"]["firstFolder"],
								data: resultJSON["data"],
							};
						}
						return {
							zipDownload: zipDownload,
							guid: resultJSON["data"]["guid"],
							id: resultJSON["data"]["firstFile"]["id"],
							fileSize: utils.formatByteToSize(
								resultJSON["data"]["firstFile"]["file_info"]["size"]
							),
							fileName: resultJSON["data"]["firstFile"]["file_info"]["title"],
							fileType: resultJSON["data"]["firstFile"]["file_info"]["format"],
							fileUploadTime: utils.formatTime(
								resultJSON["data"]["firstFile"]["created_at"]
							),
							fileLatestTime: utils.formatTime(
								resultJSON["data"]["firstFile"]["updated_at"]
							),
						};
					}
				};
				/**
				 * 获取直链弹窗的文件夹信息
				 * @returns
				 */
				this.getFolderInfo = function (
					transferGuid,
					shareFolderInfoList,
					shareFileInfoList,
					index = 0
				) {
					let folderInfoList = [];
					let tempFolderInfoList = [];
					let tempFolderFileInfoList = [];
					/* 文件夹 */
					shareFolderInfoList.forEach((folderInfo) => {
						folderInfoList.push({
							fileName: folderInfo["title"],
							fileSize: 0,
							fileType: "",
							createTime: folderInfo["created_at"],
							latestTime: folderInfo["updated_at"],
							isFolder: true,
							index: index,
							async clickEvent() {
								if (
									!folderInfo["child_folder_count"] &&
									!folderInfo["content_count"]
								) {
									/* 里面没有文件夹和文件 */
									return [];
								}
								let childFolderInfo = await that.getShareFolder(
									transferGuid,
									folderInfo["id"]
								);
								if (!childFolderInfo) {
									return [];
								}
								let childFileInfo = await that.getShareFiles(
									transferGuid,
									folderInfo["id"]
								);
								if (!childFileInfo) {
									return [];
								}
								let folderInfoList = that.getFolderInfo(
									transferGuid,
									childFolderInfo,
									childFileInfo,
									index + 1
								);
								return folderInfoList;
							},
						});
					});
					/* 文件 */
					shareFileInfoList.forEach((fileInfo) => {
						let fileName = fileInfo["file_info"]["title"];
						let fileType = fileInfo["file_info"]["format"] ?? "";
						if (Boolean(fileType)) {
							fileName = fileName + "." + fileType;
						}
						folderInfoList.push({
							fileName: fileName,
							fileSize: fileInfo["file_info"]["size"],
							fileType: fileType,
							createTime: fileInfo["created_at"],
							latestTime: fileInfo["updated_at"],
							isFolder: false,
							index: index,
							async clickEvent() {
								let downloadUrl = await that.getDownloadUrl(
									that.shareCode,
									transferGuid,
									fileInfo["id"]
								);
								if (!downloadUrl) {
									return;
								}
								if (NetDiskFilterScheme.isForwardDownloadLink("nainiu")) {
									downloadUrl = NetDiskFilterScheme.parseDataToSchemeUri(
										"nainiu",
										downloadUrl
									);
								}

								that.downloadFile(fileName, downloadUrl);
							},
						});
					});
					tempFolderInfoList.sort((a, b) =>
						a["fileName"].localeCompare(b["fileName"])
					);
					tempFolderFileInfoList.sort((a, b) =>
						a["fileName"].localeCompare(b["fileName"])
					);
					folderInfoList = folderInfoList.concat(tempFolderInfoList);
					folderInfoList = folderInfoList.concat(tempFolderFileInfoList);
					log.info(["getFolderInfo", folderInfoList]);
					return folderInfoList;
				};
				/**
				 * 文件解析
				 * @param {string} shareCode
				 * @param {string} accessCode
				 */
				this.parseMoreFile = async function (shareCode, accessCode) {};
				/**
				 * 获取文件夹信息
				 * @param {string} transferGuid
				 * @param {number} folderId
				 * @param {number} page
				 * @param {number} size
				 * @returns {Promise<?object[]>}
				 */
				this.getShareFolder = async function (
					transferGuid,
					folderId = "",
					page = 0,
					size = 100
				) {
					let getResp = await httpx.get(
						`https://cowtransfer.com/core/api/transfer/share/folders?transferGuid=${transferGuid}&folderId=${folderId}&page=${page}&size=${size}`,
						{
							headers: {
								Accept: "application/json",
								"User-Agent": utils.getRandomPCUA(),
								Referer: "https://cowtransfer.com/",
							},
						}
					);
					log.success(getResp);
					if (!getResp.status) {
						return;
					}
					let data = utils.toJSON(getResp.data.responseText);
					if (data.code !== OK_CODE) {
						Qmsg.error(data["message"]);
						return;
					}
					let folders = data["data"]["folders"];
					if (!Array.isArray(folders)) {
						Qmsg.error("data.folders不是数组");
						return;
					}
					return folders;
				};
				/**
				 * 获取文件信息
				 * @param {string} transferGuid
				 * @param {number} folderId
				 * @param {number} page
				 * @param {number} size
				 * @param {boolean} subContent
				 * @returns {Promise<?object[]>}
				 */
				this.getShareFiles = async function (
					transferGuid,
					folderId = "",
					page = 0,
					size = 20,
					subContent = false
				) {
					let getResp = await httpx.get(
						`https://cowtransfer.com/core/api/transfer/share/files?transferGuid=${transferGuid}&folderId=${folderId}&page=${page}&size=${size}&subContent=${subContent}`,
						{
							headers: {
								Accept: "application/json",
								"User-Agent": utils.getRandomPCUA(),
								Referer: "https://cowtransfer.com/",
							},
						}
					);
					log.success(getResp);
					if (!getResp.status) {
						return;
					}
					let data = utils.toJSON(getResp.data.responseText);
					if (data.code !== OK_CODE) {
						Qmsg.error(data["message"]);
						return;
					}
					let files = data["data"]["files"];
					if (!Array.isArray(files)) {
						Qmsg.error("data.files不是数组");
						return;
					}
					return files;
				};
				/**
				 * 获取分享信息
				 * @param {string} shareCode
				 * @returns {?{
				 * code: string,
				 * message: string,
				 * data: {zipDownload: boolean,
				 * guid:string,
				 * fileSize: string,
				 * fileName: string,
				 * fileUploadTime: number,
				 * fileLatestTime: number,
				 * } | {
				 * zipDownload: boolean,
				 * guid:string,
				 * id: string,
				 * fileSize: string,
				 * fileType: string,
				 * fileName: string,
				 * fileUploadTime: number,
				 * fileLatestTime: number,
				 * }[]}
				 */
				this.getShareByUniqueUrl = async function (shareCode) {
					let url = `https://cowtransfer.com/core/api/transfer/share?uniqueUrl=${shareCode}`;
					let getResp = await httpx.get({
						url: url,
						headers: {
							"User-Agent": utils.getRandomPCUA(),
							Referer: "https://cowtransfer.com/s/" + shareCode,
						},
					});
					log.info(getResp);
					if (!getResp.status) {
						return;
					}
					let respData = getResp.data;
					let resultJSON = utils.toJSON(respData.responseText);
					log.info(["转换的JSON", resultJSON]);
					return resultJSON;
				};
				/**
				 * 获取下载链接
				 * @param {string} shareCode
				 * @param {string} guid
				 * @param {string} id
				 * @returns {?string}
				 */
				this.getDownloadUrl = async function (shareCode, guid = "", id = "") {
					let url = `https://cowtransfer.com/core/api/transfer/share/download?transferGuid=${guid}&fileId=${id}`;
					let getResp = await httpx.get({
						url: url,
						headers: {
							"User-Agent": utils.getRandomPCUA(),
							Referer: "https://cowtransfer.com/s/" + shareCode,
						},
					});
					log.info(getResp);
					if (!getResp.status) {
						return;
					}
					let respData = getResp.data;
					let resultJSON = utils.toJSON(respData.responseText);
					log.info(["转换的JSON", resultJSON]);
					if (resultJSON["code"] === OK_CODE) {
						return resultJSON["data"]["downloadUrl"];
					} else {
						Qmsg.error(`奶牛快传-获取直链:${resultJSON["message"]}`);
						return;
					}
				};
				/**
				 * 获取zip文件的下载链接
				 * @param {string} shareCode
				 * @param {string} guid
				 * @param {string} title 标题
				 * @returns {?string}
				 */
				this.getZipFileDownloadUrl = async function (
					shareCode,
					guid = "",
					title = ""
				) {
					let url = `https://cowtransfer.com/core/api/transfer/share/download?transferGuid=${guid}&title=${title}`;
					let getResp = await httpx.get({
						url: url,
						headers: {
							"User-Agent": utils.getRandomPCUA(),
							Referer: "https://cowtransfer.com/s/" + shareCode,
						},
					});
					log.info(getResp);
					if (!getResp.status) {
						return;
					}
					let respData = getResp.data;
					let resultJSON = utils.toJSON(respData.responseText);
					log.info(["转换的JSON", resultJSON]);
					if (resultJSON["code"] === OK_CODE) {
						return resultJSON["data"]["downloadUrl"];
					} else {
						Qmsg.error(`奶牛快传-获取直链:${resultJSON["message"]}`);
						return;
					}
				};
				/**
				 * 下载文件
				 * @param {string} fileName 文件名
				 * @param {string} fileDownloadUrl 下载地址
				 */
				this.downloadFile = async function (fileName, fileDownloadUrl) {
					log.info(["下载文件:", fileName, fileDownloadUrl]);
					Qmsg.info(`调用【GM_download】下载:${fileName}`);
					if (typeof GM_download === "undefined") {
						Qmsg.error("当前脚本环境缺失API 【GM_download】");
						return;
					}
					let abortDownload = void 0;
					let downloadingQmsg = Qmsg.loading("下载中...", {
						showClose: true,
						onClose() {
							if (typeof abortDownload === "function") {
								abortDownload();
							}
						},
					});
					let isDownloadEnd = false;
					let GM_download_Result = GM_download({
						url: fileDownloadUrl,
						name: fileName,
						headers: {
							Referer: "https://cowtransfer.com/s/" + that.shareCode,
						},
						onload() {
							downloadingQmsg.close();
							Qmsg.success(`下载 ${fileName} 已完成`);
						},
						onprogress(details) {
							if (
								typeof details === "object" &&
								"loaded" in details &&
								"total" in details &&
								!isDownloadEnd
							) {
								let progressNum = details.loaded / details.total;
								let formatProgressNum = (progressNum * 100).toFixed(2);
								downloadingQmsg.setText(`下载中...${formatProgressNum}%`);
								if (details.loaded === details.total) {
									isDownloadEnd = true;
								}
							}
						},
						onerror(error) {
							downloadingQmsg.close();
							log.error(["下载失败error👉", error]);
							if (typeof error === "object" && error["error"]) {
								Qmsg.error(
									`下载 ${fileName} 失败或已取消 原因:${error["error"]}`,
									{
										timeout: 6000,
									}
								);
							} else {
								Qmsg.error(`下载 ${fileName} 失败或已取消`);
							}
						},
						ontimeout() {
							downloadingQmsg.close();
							Qmsg.error(`下载 ${fileName} 请求超时`);
						},
					});
					if (
						typeof GM_download_Result === "object" &&
						"abort" in GM_download_Result
					) {
						abortDownload = GM_download_Result["abort"];
					}
				};
				return this;
			},
			/**
			 * UC网盘
			 * @constructor
			 * @returns {object}
			 */
			uc: function () {
				let that = this;
				/**
				 * 所在规则的下标
				 */
				this.netDiskIndex = 0;
				/**
				 * 分享码
				 */
				this.shareCode = "";
				/**
				 * 提取码
				 */
				this.accessCode = "";
				/**
				 * 入口
				 * @param {number} netDiskIndex 网盘名称索引下标
				 * @param {string} shareCode
				 * @param {string} accessCode
				 * @returns
				 */
				this.init = async function (netDiskIndex, shareCode, accessCode) {
					log.info([netDiskIndex, shareCode, accessCode]);
					that.netDiskIndex = netDiskIndex;
					that.shareCode = shareCode;
					that.accessCode = accessCode;
					Qmsg.info("检查是否已登录UC网盘");
					let loginStatus = await that.isLogin();
					if (!Boolean(loginStatus)) {
						that.gotoLogin(
							"检测到尚未登录UC网盘,是否前去登录?<br />&nbsp;&nbsp;&nbsp;&nbsp;(注意,需要当前浏览器的UA切换成PC才有登录选项)"
						);
						return;
					}
					let stoken = await that.getStoken(that.shareCode, that.accessCode);
					if (!stoken) {
						return;
					}
					let detail = await that.getDetail(
						that.shareCode,
						that.accessCode,
						stoken
					);
					if (!detail) {
						Qmsg.error("UC网盘:获取detail失败");
						return;
					}
					if (
						detail.length === 1 &&
						detail[0].dir == false &&
						detail[0].file_type === 1
					) {
						let oneFileDetail = detail[0];
						let oneFileDownloadDetail = await that.getDownload(
							that.shareCode,
							stoken,
							oneFileDetail.fid,
							oneFileDetail.share_fid_token
						);
						if (!oneFileDownloadDetail) {
							return;
						}
						if (!oneFileDownloadDetail[0].download_url) {
							Qmsg.error("获取download_url失败");
							return;
						}
						NetDiskUI.staticView.oneFile({
							title: "UC网盘单文件直链",
							fileName: oneFileDownloadDetail[0].file_name,
							fileSize: utils.formatByteToSize(oneFileDownloadDetail[0].size),
							downloadUrl: oneFileDownloadDetail[0].download_url,
							fileUploadTime: utils.formatTime(
								oneFileDownloadDetail[0].created_at
							),
							fileLatestTime: utils.formatTime(
								oneFileDownloadDetail[0].last_update_at
							),
							clickCallBack() {
								that.downloadFile(
									oneFileDownloadDetail[0].file_name,
									oneFileDownloadDetail[0].download_url
								);
							},
						});
					} else {
						Qmsg.info("正在递归文件");
						let QmsgLoading = Qmsg.loading(`正在解析多文件中,请稍后...`);
						let folderInfoList = that.getFolderInfo(detail, stoken, 0);
						QmsgLoading.close();
						log.info("递归完毕");
						NetDiskUI.staticView.moreFile("UC网盘文件解析", folderInfoList);
						return;
					}
				};
				/**
				 * 判断是否已登录UC网盘
				 * @returns {Promise<?(string|boolean)>}
				 */
				this.isLogin = async function () {
					let getResp = await httpx.get("https://drive.uc.cn/", {
						headers: {
							"User-Agent": utils.getRandomPCUA(),
						},
					});
					log.success(["判断是否已登录UC网盘", getResp]);
					if (!getResp.status) {
						return;
					}
					if (getResp.data.finalUrl === "https://drive.uc.cn/list") {
						return "已登录";
					} else {
						return false;
					}
				};
				/**
				 * 下载文件
				 * @param {string} fileName 文件名
				 * @param {string} downloadUrl 下载链接
				 * @return { {
				 * abort: Function
				 * } }
				 */
				this.downloadFile = function (fileName, downloadUrl) {
					log.info([`调用【GM_download】下载:`, arguments]);
					Qmsg.info(`调用【GM_download】下载:${fileName}`);
					if (typeof GM_download === "undefined") {
						Qmsg.error("当前脚本环境缺失API 【GM_download】");
						return;
					}
					let downloadingQmsg = Qmsg.loading("下载中...");
					let isDownloadEnd = false;
					return GM_download({
						url: downloadUrl,
						name: fileName,
						headers: {
							Referer: "https://drive.uc.cn/",
						},
						onload() {
							downloadingQmsg.close();
							Qmsg.success(`下载 ${fileName} 已完成`);
						},
						onprogress(details) {
							if (
								typeof details === "object" &&
								"loaded" in details &&
								"total" in details &&
								!isDownloadEnd
							) {
								let progressNum = details.loaded / details.total;
								let formatProgressNum = (progressNum * 100).toFixed(2);
								downloadingQmsg.setText(`下载中...${formatProgressNum}%`);
								if (details.loaded === details.total) {
									isDownloadEnd = true;
								}
							}
						},
						onerror(error) {
							downloadingQmsg.close();
							log.error(["下载失败error👉", error]);
							if (typeof error === "object" && error["error"]) {
								Qmsg.error(
									`下载 ${fileName} 失败或已取消 原因:${error["error"]}`,
									{
										timeout: 6000,
									}
								);
							} else {
								Qmsg.error(`下载 ${fileName} 失败或已取消`);
							}
						},
						ontimeout() {
							downloadingQmsg.close();
							Qmsg.error(`下载 ${fileName} 请求超时`);
						},
					});
				};
				/**
				 * 前往登录
				 * @param {string} text 弹窗的显示的内容
				 */
				this.gotoLogin = function (text = "") {
					NetDiskPops.confirm(
						{
							title: {
								position: "center",
								text: "UC网盘",
							},
							content: {
								text: text,
								html: false,
							},
							btn: {
								reverse: true,
								position: "end",
								ok: {
									text: "前往",
									enable: true,
									callback() {
										window.open("https://drive.uc.cn", "_blank");
									},
								},
							},
						},
						NetDiskUI.popsStyle.tianYiYunLoginTip
					);
				};
				/**
				 * 获取stoken
				 * @param {string} pwd_id 分享码
				 * @param {string} passcode 访问码
				 * @returns {Promise<?string>}
				 */
				this.getStoken = async function (pwd_id, passcode) {
					let postResp = await httpx.post(
						"https://pc-api.uc.cn/1/clouddrive/share/sharepage/token?entry=ft&fr=pc&pr=UCBrowser",
						{
							data: JSON.stringify({
								share_for_transfer: true,
								passcode: passcode,
								pwd_id: pwd_id,
							}),
							headers: {
								Accept: "application/json, text/plain, */*",
								"Content-Type": "application/json;charset=UTF-8",
								"User-Agent": utils.getRandomPCUA(),
								Origin: "https://drive.uc.cn",
								Referer: "https://drive.uc.cn/",
							},
							onerror() {},
						}
					);
					if (!postResp.status) {
						let errorData = utils.toJSON(postResp.data.responseText);
						log.error(["获取stoken失败JSON信息", errorData]);
						if ("message" in errorData) {
							Qmsg.error(errorData["message"]);
						} else {
							Qmsg.error("请求异常,获取stoken失败");
						}
						return;
					}
					let data = utils.toJSON(postResp.data.responseText);
					log.info(["获取stoken:", data]);
					if (data["code"] !== 0) {
						log.error(["获取stoken失败", data]);
						Qmsg.error("获取stoken失败");
						return;
					}
					return data["data"]["stoken"];
				};

				/**
				 * 获取stoken
				 * @param {string} pwd_id 分享码
				 * @param {string} passcode 访问码
				 * @param {string} stoken 获取的stoken
				 * @param {string} [pdir_fid=0] 父fid,默认为0,如果为文件夹,那么它的fid就是这个值
				 * @param {number} [force=0]
				 * @param {number} [_page=1]
				 * @param {number} [_size=50]
				 * @param {number} [_fetch_banner=0]
				 * @param {number} [_fetch_share=0]
				 * @param {number} [_fetch_total=1]
				 * @returns {Promise<?{
				 * backup_sign: number,
				 * backup_source: boolean,
				 * ban: boolean,
				 * category: number,
				 * created_at: number,
				 * creator_ucid_or_default: string,
				 * cur_version_or_default: number,
				 * dir: boolean,
				 * duration: number,
				 * event_extra: {
				 *    recent_created_at: number
				 * },
				 * extra: string,
				 * fid: string,
				 * file: boolean,
				 * file_name: string,
				 * file_name_hl_end: number,
				 * file_name_hl_start: number,
				 * file_source: string,
				 * file_struct: {
				 *    fir_source: string,
				 *    platform_source: string,
				 *    sec_source: string,
				 *    thi_source: string,
				 *    upload_dm: string,
				 *    upload_mi: string,
				 * },
				 * file_type: number,
				 * format_type: string,
				 * include_items:  number,
				 * l_created_at:  number,
				 * l_updated_at:  number,
				 * last_update_at:  number,
				 * like:  number,
				 * name_space:  number,
				 * offline_source: boolean,
				 * operated_at:  number,
				 * owner_drive_type_or_default:  number,
				 * owner_ucid: string,
				 * pdir_fid: string,
				 * raw_name_space:  number,
				 * risk_type:  number,
				 * save_as_source: boolean,
				 * share_fid_token: string,
				 * size:  number,
				 * status:  number,
				 * tags: string,
				 * updated_at:  number,
				 * _extra: {},
				 * }[]>}
				 */
				this.getDetail = async function (
					pwd_id,
					passcode,
					stoken,
					pdir_fid = 0,
					force = 0,
					_page = 1,
					_size = 50,
					_fetch_banner = 0,
					_fetch_share = 0,
					_fetch_total = 1
				) {
					let getResp = await httpx.get(
						`https://pc-api.uc.cn/1/clouddrive/transfer_share/detail?pr=UCBrowser&fr=h5&pwd_id=${pwd_id}&__t=${new Date().getTime()}&passcode=${passcode}&stoken=${encodeURIComponent(
							stoken
						)}&pdir_fid=${pdir_fid}&force=${force}&_page=${_page}&_size=${_size}&_fetch_banner=${_fetch_banner}&_fetch_share=${_fetch_share}&_fetch_total=${_fetch_total}&_sort=${encodeURIComponent(
							"file_type:asc,file_name:asc"
						)}`,
						{
							headers: {
								Accept: "application/json, text/plain, */*",
								"User-Agent": utils.getRandomPCUA(),
								Origin: "https://drive.uc.cn",
								Referer: "https://drive.uc.cn/",
							},
						}
					);
					if (!getResp.status) {
						return;
					}
					let data = utils.toJSON(getResp.data.responseText);
					log.info(["获取detail:", data]);
					if (data["code"] !== 0) {
						log.error(["获取detail失败", data]);
						Qmsg.error("获取detail失败");
						return;
					}
					let metadata = data["metadata"];
					if (
						metadata &&
						metadata["_total"] &&
						metadata["_total"] > metadata["_size"]
					) {
						// 文件的总数量超过默认的值
						return await this.getDetail(
							pwd_id,
							passcode,
							stoken,
							pdir_fid,
							force,
							_page,
							metadata["_total"],
							_fetch_banner,
							_fetch_share,
							_fetch_total
						);
					}
					return data["data"]["list"];
				};

				/**
				 * 获取下载信息
				 * @param {string} pwd_id 分享码
				 * @param {string} stoken 获取的stoken
				 * @param {string} fids 通过获取到的detail获取到的fid
				 * @param {string} share_fid_token 通过获取到的detail获取到的share_fid_token
				 * @returns {Promise< ?{
				 * backup_sign: number,
				 * backup_source: boolean,
				 * ban: boolean,
				 * big_thumbnail: string,
				 * category: number,
				 * created_at: number,
				 * creator_ucid_or_default: string,
				 * cur_version_or_default: number,
				 * dir: boolean,
				 * download_url: string,
				 * duration: number,
				 * event_extra: {
				 *    recent_created_at: number
				 * },
				 * extra: string,
				 * fid: string,
				 * file: boolean,
				 * file_name: string,
				 * file_name_hl_end: number,
				 * file_name_hl_start: number,
				 * file_source: string,
				 * file_type: number,
				 * format_type: string,
				 * l_created_at: number,
				 * l_updated_at: number,
				 * last_update_at: number,
				 * like: number,
				 * md5: string,
				 * name_space: number,
				 * obj_category: string,
				 * offline_source: boolean,
				 * operated_at: number,
				 * owner_drive_type_or_default: number,
				 * owner_ucid: string,
				 * pdir_fid: string,
				 * preview_url: string,
				 * range_size: number,
				 * raw_name_space: number,
				 * risk_type: number,
				 * save_as_source: boolean,
				 * share_fid_token: string,
				 * size: number,
				 * status: number,
				 * thumbnail: string,
				 * updated_at: number,
				 * video_height: number,
				 * video_max_resolution: string,
				 * video_width: number,
				 * _extra: {},
				 * } []>}
				 */
				this.getDownload = async function (
					pwd_id,
					stoken,
					fid,
					share_fid_token
				) {
					let postResp = await httpx.post(
						"https://pc-api.uc.cn/1/clouddrive/file/download?entry=ft&fr=pc&pr=UCBrowser",
						{
							data: JSON.stringify({
								fids: [fid],
								pwd_id: pwd_id,
								stoken: stoken,
								fids_token: [share_fid_token],
							}),
							headers: {
								Accept: "application/json, text/plain, */*",
								"Content-Type": "application/json;charset=UTF-8",
								"User-Agent": utils.getRandomPCUA(),
								Origin: "https://drive.uc.cn",
								Referer: "https://drive.uc.cn/",
							},
						}
					);
					if (!postResp.status) {
						return;
					}
					let data = utils.toJSON(postResp.data.responseText);
					log.info(["获取download:", data]);
					if (data["code"] !== 0) {
						log.error(["获取download失败", data]);
						Qmsg.error("获取download失败");
						return;
					}
					if (data["data"].length === 0) {
						log.error(["获取download detail失败", data]);
						Qmsg.error("获取download detail失败失败");
						return;
					}
					return data["data"];
				};

				/**
				 * 获取文件夹信息
				 * @param {{
				 * backup_sign: number,
				 * backup_source: boolean,
				 * ban: boolean,
				 * category: number,
				 * created_at: number,
				 * creator_ucid_or_default: string,
				 * cur_version_or_default: number,
				 * dir: boolean,
				 * duration: number,
				 * event_extra: {
				 *    recent_created_at: number
				 * },
				 * extra: string,
				 * fid: string,
				 * file: boolean,
				 * file_name: string,
				 * file_name_hl_end: number,
				 * file_name_hl_start: number,
				 * file_source: string,
				 * file_struct: {
				 *    fir_source: string,
				 *    platform_source: string,
				 *    sec_source: string,
				 *    thi_source: string,
				 *    upload_dm: string,
				 *    upload_mi: string,
				 * },
				 * file_type: number,
				 * format_type: string,
				 * include_items:  number,
				 * l_created_at:  number,
				 * l_updated_at:  number,
				 * last_update_at:  number,
				 * like:  number,
				 * name_space:  number,
				 * offline_source: boolean,
				 * operated_at:  number,
				 * owner_drive_type_or_default:  number,
				 * owner_ucid: string,
				 * pdir_fid: string,
				 * raw_name_space:  number,
				 * risk_type:  number,
				 * save_as_source: boolean,
				 * share_fid_token: string,
				 * size:  number,
				 * status:  number,
				 * tags: string,
				 * updated_at:  number,
				 * _extra: {},
				 * }[]} infoList
				 * @return {Promise<{
				 * fileName: string,
				 * fileSize: string|number,
				 * fileType: ?string,
				 * createTime: ?string,
				 * latestTime: ?string,
				 * isFolder: boolean,
				 * index: ?number,
				 * clickCallBack: ?(event:Event,_config_: object)=>{}
				 * }[]>}
				 */
				this.getFolderInfo = function (infoList, stoken, index = 0) {
					let folderInfoList = [];
					let tempFolderInfoList = [];
					/**
					 * @type {PopsFolderDataConfig[]}
					 */
					let tempFolderFileInfoList = [];
					infoList.forEach((item) => {
						if (item.dir == false && item.file_type === 1) {
							/* 文件 */
							tempFolderFileInfoList.push({
								fileName: item.file_name,
								fileSize: item.size,
								fileType: "",
								createTime: item.created_at,
								latestTime: item.updated_at,
								isFolder: false,
								index: index,
								async clickEvent() {
									let fileDownloadUrl = await that.getDownload(
										that.shareCode,
										stoken,
										item.fid,
										item.share_fid_token
									);
									if (fileDownloadUrl) {
										if (fileDownloadUrl.length) {
											fileDownloadUrl = fileDownloadUrl[0].download_url;
										} else {
											fileDownloadUrl = "";
										}
									} else {
										fileDownloadUrl = "";
									}
									if (item.ban) {
										Qmsg.error("文件已被禁止下载");
									} else {
										let schemeDownloadUrl = fileDownloadUrl;
										if (NetDiskFilterScheme.isForwardDownloadLink("uc")) {
											schemeDownloadUrl =
												NetDiskFilterScheme.parseDataToSchemeUri(
													"uc",
													schemeDownloadUrl
												);
										}
										/* 如果已被scheme过滤,那么不进行GM_download下载 */
										if (schemeDownloadUrl === fileDownloadUrl) {
											that.downloadFile(item.file_name, fileDownloadUrl);
										} else {
											return {
												autoDownload: true,
												mode: "aBlank",
												url: fileDownloadUrl,
											};
										}
									}
								},
							});
						} else {
							/* 文件夹 */
							tempFolderInfoList.push({
								fileName: item.file_name,
								fileSize: item.size,
								fileType: "",
								createTime: item.created_at,
								latestTime: item.updated_at,
								isFolder: true,
								index: index,
								async clickEvent() {
									if (item.include_items === 0) {
										/* 里面没有文件 */
										log.success("里面没有文件");
										return [];
									}
									let newDetail = await that.getDetail(
										that.shareCode,
										that.accessCode,
										stoken,
										item.fid
									);
									if (newDetail) {
										return that.getFolderInfo(newDetail, stoken, index + 1);
									} else {
										return [];
									}
								},
							});
						}
					});

					tempFolderInfoList.sort((a, b) =>
						a["fileName"].localeCompare(b["fileName"])
					);
					tempFolderFileInfoList.sort((a, b) =>
						a["fileName"].localeCompare(b["fileName"])
					);
					folderInfoList = folderInfoList.concat(tempFolderInfoList);
					folderInfoList = folderInfoList.concat(tempFolderFileInfoList);
					log.info(["getFilesInfoByRec", folderInfoList]);
					return folderInfoList;
				};
				return this;
			},
			/**
			 * 阿里云盘
			 * @constructor
			 * @returns {object}
			 */
			aliyun: function () {
				let that = this;
				/**
				 * 所在规则的下标
				 */
				this.netDiskIndex = 0;
				/**
				 * 分享码
				 */
				this.shareCode = "";
				/**
				 * 提取码
				 */
				this.accessCode = "";
				this.X_Share_Token_Data = {
					expire_time: "2000-01-01T00:00:00.000Z",
					expires_in: 7200,
					share_token: "",
				};
				/**
				 * header请求头 X-Device-Id
				 */
				this.X_Device_Id = null;
				/**
				 * header请求头 X-Canary
				 */
				this.X_Canary = "client=web,app=share,version=v2.3.1";
				/**
				 * 入口
				 * @param {number} netDiskIndex 网盘名称索引下标
				 * @param {string} shareCode
				 * @param {string} accessCode
				 * @returns
				 */
				this.init = async function (netDiskIndex, shareCode, accessCode) {
					log.info([netDiskIndex, shareCode, accessCode]);
					that.netDiskIndex = netDiskIndex;
					that.shareCode = shareCode;
					that.accessCode = accessCode;
					that.X_Device_Id = that.get_X_Device_Id();
					log.info("生成X_Device_Id:" + that.X_Device_Id);
					if (
						globalThis.location.hostname !== "www.aliyundrive.com" &&
						globalThis.location.hostname !== "www.alipan.com"
					) {
						let url = NetDiskParse.getBlankUrl(
							"aliyun",
							that.netDiskIndex,
							that.shareCode,
							that.accessCode
						);
						let $QmsgErrorTip = Qmsg.error(
							`请在阿里云盘页面解析,<a href="${url}">点我前往</a>`,
							{
								html: true,
								timeout: 10000,
							}
						);
						DOMUtils.on(
							$QmsgErrorTip.$Qmsg.querySelector("a[href]"),
							"click",
							void 0,
							(event) => {
								utils.preventEvent(event);
								NetDiskParse.blank(
									url,
									"aliyun",
									that.netDiskIndex,
									that.shareCode,
									that.accessCode
								);
							}
						);
						return;
					}
					let detail = await this.list_by_share(shareCode, "root");
					if (!detail) {
						return;
					}
					Qmsg.info("正在解析链接");
					let QmsgLoading = Qmsg.loading(`正在解析多文件中,请稍后...`);
					let folderInfoList = that.getFolderInfo(detail, 0);
					QmsgLoading.close();
					log.info("解析完毕");
					NetDiskUI.staticView.moreFile("阿里云盘文件解析", folderInfoList);
				};
				/**
				 * 弹窗使用-获取文件夹信息
				 * @param {{
				 * category?: string,
				 * domain_id?: string,
				 * file_extension?: string,
				 * mime_extension?: string,
				 * mime_type?: string,
				 * punish_flag: number,
				 * created_at: string,
				 * domain_id: string,
				 * drive_id: string,
				 * file_id: string,
				 * name: string,
				 * parent_file_id:string,
				 * share_id: string,
				 * type: string,
				 * updated_at: string,
				 * }[]} infoList
				 * @return {Promise<{
				 * fileName: string,
				 * fileSize: string|number,
				 * fileType: ?string,
				 * createTime: ?string,
				 * latestTime: ?string,
				 * isFolder: boolean,
				 * index: ?number,
				 * clickCallBack: ?(event:Event,_config_: object)=>{}
				 * }[]>}
				 */
				this.getFolderInfo = function (infoList, index = 0) {
					let folderInfoList = [];
					let tempFolderInfoList = [];
					/**
					 * @type {PopsFolderDataConfig[]}
					 */
					let tempFolderFileInfoList = [];
					infoList.forEach((item) => {
						if (item.type !== "folder") {
							/* 文件 */
							tempFolderFileInfoList.push({
								fileName: item.name,
								fileSize: item.size,
								fileType: item.file_extension,
								createTime: new Date(item.created_at).getTime(),
								latestTime: new Date(item.updated_at).getTime(),
								isFolder: false,
								index: index,
								async clickEvent() {
									let fileDownloadUrl = await that.get_share_link_download_url(
										item.share_id,
										item.file_id
									);
									if (!fileDownloadUrl) {
										return;
									}
									let schemeDownloadUrl = fileDownloadUrl;
									if (NetDiskFilterScheme.isForwardDownloadLink("aliyun")) {
										schemeDownloadUrl =
											NetDiskFilterScheme.parseDataToSchemeUri(
												"aliyun",
												schemeDownloadUrl
											);
									}
									return {
										autoDownload: true,
										mode: "aBlank",
										url: schemeDownloadUrl,
									};
								},
							});
						} else {
							/* 文件夹 */
							tempFolderInfoList.push({
								fileName: item.name,
								fileSize: 0,
								fileType: "",
								createTime: item.created_at,
								latestTime: item.updated_at,
								isFolder: true,
								index: index,
								async clickEvent() {
									let newDetail = await that.list_by_share(
										item.share_id,
										item.file_id
									);
									if (newDetail) {
										return that.getFolderInfo(newDetail, index + 1);
									} else {
										return [];
									}
								},
							});
						}
					});

					tempFolderInfoList.sort((a, b) =>
						a["fileName"].localeCompare(b["fileName"])
					);
					tempFolderFileInfoList.sort((a, b) =>
						a["fileName"].localeCompare(b["fileName"])
					);
					folderInfoList = folderInfoList.concat(tempFolderInfoList);
					folderInfoList = folderInfoList.concat(tempFolderFileInfoList);
					log.info(["getFilesInfoByRec", folderInfoList]);
					return folderInfoList;
				};
				/**
				 * 列出文件列表
				 * @param {string} share_id
				 * @param {string} parent_file_id 父项,根是root
				 * @param {"name"} order_by 根据xxx排序
				 * @param {"ASC"|"DESC"} order_direction 排序规则(升序/降序)
				 * @returns {Promise<{
				 * category?: string,
				 * domain_id?: string,
				 * file_extension?: string,
				 * mime_extension?: string,
				 * mime_type?: string,
				 * punish_flag: number,
				 * created_at: string,
				 * domain_id: string,
				 * drive_id: string,
				 * file_id: string,
				 * name: string,
				 * parent_file_id:string,
				 * share_id: string,
				 * type: string,
				 * updated_at: string,
				 * }[]>}
				 */
				this.list_by_share = async function (
					share_id,
					parent_file_id,
					order_by = "name",
					order_direction = "DESC"
				) {
					let postResp = await httpx.post(
						"https://api.aliyundrive.com/adrive/v2/file/list_by_share",
						{
							data: JSON.stringify({
								share_id: share_id,
								parent_file_id: parent_file_id,
								limit: 20,
								image_thumbnail_process: "image/resize,w_256/format,jpeg",
								image_url_process:
									"image/resize,w_1920/format,jpeg/interlace,1",
								video_thumbnail_process:
									"video/snapshot,t_1000,f_jpg,ar_auto,w_256",
								order_by: order_by,
								order_direction: order_direction,
							}),
							headers: {
								Accept: "application/json, text/plain, */*",
								"Content-Type": "application/json",
								Origin: "https://www.aliyundrive.com",
								Referer: "https://www.aliyundrive.com/",
								"X-Canary": that.X_Canary,
								"X-Device-Id": that.X_Device_Id,
								"X-Share-Token": await that.get_X_Share_Token(
									that.shareCode,
									that.accessCode
								),
								"User-Agent": utils.getRandomPCUA(),
							},
							onerror() {},
						}
					);
					if (!postResp.status) {
						that.handle_request_error(postResp);
						return;
					}
					let data = utils.toJSON(postResp.data.responseText);
					log.info(["列出文件列表:", data]);
					return data["items"];
				};
				/**
				 * 获取文件的下载链接
				 * @returns {Promise<string>}
				 */
				this.get_share_link_download_url = async function (share_id, file_id) {
					let postResp = await httpx.post(
						"https://api.aliyundrive.com/v2/file/get_share_link_download_url",
						{
							data: JSON.stringify({
								expire_sec: 600,
								file_id: file_id,
								share_id: share_id,
							}),
							headers: {
								Accept: "application/json, text/plain, */*",
								"Content-Type": "application/json",
								Origin: "https://www.aliyundrive.com",
								Referer: "https://www.aliyundrive.com/",
								"Content-Type": "application/json;charset=UTF-8",
								Authorization: "Bearer " + that.getAuthorization(),
								"X-Share-Token": await that.get_X_Share_Token(
									that.shareCode,
									that.accessCode
								),
								"User-Agent": utils.getRandomPCUA(),
							},
							onerror() {},
						}
					);
					if (!postResp.status) {
						that.handle_request_error(postResp);
						return;
					}
					let data = utils.toJSON(postResp.data.responseText);
					log.info(["获取文件的下载链接:", data]);
					return data["download_url"];
				};
				/**
				 * 处理请求的错误
				 * @param {HttpxAsyncResult} postResp
				 */
				this.handle_request_error = function (postResp) {
					log.error(postResp);
					let errData = utils.toJSON(postResp.data.responseText);
					Qmsg.error(errData["message"]);
				};
				/**
				 * 获取用户鉴权值
				 * 来源:localStorage => token.access_token
				 */
				this.getAuthorization = function () {
					let token = unsafeWindow.localStorage.getItem("token");
					if (utils.isNotNull(token)) {
						token = utils.toJSON(token);
						let access_token = token["access_token"];
						log.success(["获取阿里云盘的access_token:", access_token]);
						return access_token;
					} else {
						log.error("获取access_token失败,请先登录账号!");
						Qmsg.error("获取access_token失败,请先登录账号!");
					}
				};
				/**
				 * 获取header请求头 X-Device-Id
				 */
				this.get_X_Device_Id = function () {
					for (
						var alipan_device_id_pattern =
								/^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i,
							alipan_s = [],
							alipan_l = 0;
						alipan_l < 256;
						++alipan_l
					)
						alipan_s.push((alipan_l + 256).toString(16).substr(1));
					function alipan_o() {
						return crypto.getRandomValues(new Uint8Array(16));
					}
					var alipan_c = function (args_e) {
							var second_arg =
									arguments.length > 1 && void 0 !== arguments[1]
										? arguments[1]
										: 0,
								devices_id_string = (
									alipan_s[args_e[second_arg + 0]] +
									alipan_s[args_e[second_arg + 1]] +
									alipan_s[args_e[second_arg + 2]] +
									alipan_s[args_e[second_arg + 3]] +
									"-" +
									alipan_s[args_e[second_arg + 4]] +
									alipan_s[args_e[second_arg + 5]] +
									"-" +
									alipan_s[args_e[second_arg + 6]] +
									alipan_s[args_e[second_arg + 7]] +
									"-" +
									alipan_s[args_e[second_arg + 8]] +
									alipan_s[args_e[second_arg + 9]] +
									"-" +
									alipan_s[args_e[second_arg + 10]] +
									alipan_s[args_e[second_arg + 11]] +
									alipan_s[args_e[second_arg + 12]] +
									alipan_s[args_e[second_arg + 13]] +
									alipan_s[args_e[second_arg + 14]] +
									alipan_s[args_e[second_arg + 15]]
								).toLowerCase();
							if (
								!(function (e) {
									return (
										"string" == typeof e && alipan_device_id_pattern.test(e)
									);
								})(devices_id_string)
							)
								throw TypeError("Stringified UUID is invalid");
							return devices_id_string;
						},
						alipan_u = function (args_e, args_t, args_n) {
							var randomValue =
								(args_e = args_e || {}).random || (args_e.rng || alipan_o)();
							if (
								((randomValue[6] = (15 & randomValue[6]) | 64),
								(randomValue[8] = (63 & randomValue[8]) | 128),
								args_t)
							) {
								args_n = args_n || 0;
								for (var i = 0; i < 16; ++i)
									args_t[args_n + i] = randomValue[i];
								return args_t;
							}
							return alipan_c(randomValue);
						};
					return alipan_u();
				};
				/**
				 * 获取header请求头 X-Share-Token
				 * 来源:localStorage => shareToken.share_token
				 */
				this.get_X_Share_Token = async function (share_id, share_pwd) {
					if (new Date() < new Date(that.X_Share_Token_Data.expire_time)) {
						return that.X_Share_Token_Data.share_token;
					}
					let postResp = await httpx.post(
						"https://api.aliyundrive.com/v2/share_link/get_share_token",
						{
							data: JSON.stringify({
								share_id: share_id,
								share_pwd: share_pwd,
							}),
							headers: {
								Accept: "application/json, text/plain, */*",
								"Content-Type": "application/json",
								Origin: "https://www.aliyundrive.com",
								Referer: "https://www.aliyundrive.com/",
								"X-Canary": that.X_Canary,
								"X-Device-Id": that.X_Device_Id,
								"User-Agent": utils.getRandomPCUA(),
							},
							onerror() {},
						}
					);
					if (!postResp.status) {
						that.handle_request_error(postResp);
						return;
					}
					let data = utils.toJSON(postResp.data.responseText);
					that.X_Share_Token_Data = data;
					log.info(["获取share_token:", that.X_Share_Token_Data]);
					return that.X_Share_Token_Data["share_token"];
				};
				return this;
			},
		},
		/**
		 * 网盘链接解析
		 * @param {string} netDiskName 网盘名称
		 * @param {number} netDiskIndex 网盘名称索引下标
		 * @param {string} shareCode
		 * @param {string} accessCode
		 */
		async parse(netDiskName, netDiskIndex, shareCode, accessCode) {
			Qmsg.info("正在获取直链");
			if (this.netDisk[netDiskName]) {
				let parseObj = new NetDiskParse.netDisk[netDiskName]();
				await parseObj.init(netDiskIndex, shareCode, accessCode);
			} else {
				log.error(`${netDiskName} 不存在解析`);
				Qmsg.error("该链接不存在解析功能");
			}
		},
		/**
		 * 复制到剪贴板
		 * @param {string} netDiskName
		 * @param {number} netDiskIndex
		 * @param {string} shareCode
		 * @param {string} accessCode
		 * @param {string} toastText 提示的文字
		 */
		copyText(
			netDiskName,
			netDiskIndex,
			shareCode,
			accessCode,
			toastText = "已复制"
		) {
			utils.setClip(
				NetDiskParse.getCopyUrlInfo(
					netDiskName,
					netDiskIndex,
					shareCode,
					accessCode
				)
			);
			Qmsg.success(toastText);
		},
		/**
		 * 新标签页打开
		 * @param {string} url 跳转的网址
		 * @param {string} netDiskName
		 * @param {number|string} netDiskIndex
		 * @param {string} shareCode
		 * @param {string} accessCode
		 */
		blank(url, netDiskName, netDiskIndex, shareCode, accessCode) {
			log.success(["新标签页打开", [...arguments]]);
			if (NetDiskAutoFillAccessCode.$data.enable) {
				NetDiskAutoFillAccessCode.setValue({
					url: url,
					netDiskName: netDiskName,
					netDiskIndex: netDiskIndex,
					shareCode: shareCode,
					accessCode: accessCode,
				});
			}
			if (NetDiskFilterScheme.isForwardBlankLink(netDiskName)) {
				url = NetDiskFilterScheme.parseDataToSchemeUri(netDiskName, url);
			}
			/* 百度网盘会拒绝referrer不安全访问 */
			document
				.querySelector("meta[name='referrer']")
				?.setAttribute("content", "no-referrer");
			if (
				utils.isNotNull(accessCode) &&
				GM_getValue(`${netDiskName}-open-blank-with-copy-accesscode`)
			) {
				/* 等待复制完毕再跳转 */
				utils.setClip(accessCode).then(() => {
					window.open(url, "_blank");
				});
			} else {
				window.open(url, "_blank");
			}
		},
		/**
		 * 将链接转为Scheme格式并打开
		 * @param {string} netDiskName 网盘名称
		 * @param {number} netDiskIndex 网盘名称索引下标
		 * @param {string} shareCode
		 * @param {string} accessCode
		 */
		openScheme(netDiskName, netDiskIndex, shareCode, accessCode) {
			let url = NetDiskParse.getBlankUrl(
				netDiskName,
				netDiskIndex,
				shareCode,
				accessCode
			);
			url = NetDiskFilterScheme.parseDataToSchemeUri(netDiskName, url);
			window.open(url, "_blank");
		},
		/**
		 * 获取重定向后的直链
		 * @param {string} url
		 * @param {string} userAgent 用户代理字符串
		 * @returns {Promise}
		 */
		async getRedirectFinalUrl(url, userAgent) {
			if (!GM_getValue("getTheDirectLinkAfterRedirection", true)) {
				return url;
			}
			Qmsg.success("获取重定向后的直链");
			log.info("开始获取重定向后的直链");
			let headResp = await httpx.head({
				url: url,
				headers: {
					"User-Agent": userAgent,
					Referer: window.location.origin,
				},
			});
			if (headResp.status) {
				return headResp.data.finalUrl;
			} else {
				return url;
			}
		},
		/**
		 * 获取用于跳转的url
		 * @param {string} netDiskName
		 * @param {number} netDiskIndex
		 * @param {?string} shareCode
		 * @param {?string} accessCode
		 * @returns {string}
		 */
		getBlankUrl(netDiskName, netDiskIndex, shareCode, accessCode) {
			/**
			 * @type {NetDiskRegularOption}
			 */
			let regularOption = NetDisk.regular[netDiskName][netDiskIndex];
			let blankUrl = regularOption.blank;
			if (shareCode) {
				blankUrl = NetDisk.replaceParam(blankUrl, {
					shareCode: shareCode,
				});
			}
			if (accessCode && accessCode !== "") {
				blankUrl = NetDisk.replaceParam(blankUrl, {
					accessCode: accessCode,
				});
			} else {
				blankUrl = blankUrl.replace(NetDisk.noAccessCodeRegExp, "");
			}
			/**
			 * 当前字典
			 */
			let currentDict = NetDisk.linkDict.get(netDiskName).get(shareCode);
			if (regularOption.paramMatch) {
				let paramMatchArray = currentDict.matchText.match(
					regularOption.paramMatch
				);
				let replaceParamData = {};
				for (let index = 0; index < paramMatchArray.length; index++) {
					replaceParamData[`$${index}`] = paramMatchArray[index];
				}
				blankUrl = NetDisk.replaceParam(blankUrl, replaceParamData);
			}
			return blankUrl;
		},
		/**
		 * 获取用于复制到剪贴板的网盘信息
		 * @param {string} netDiskName
		 * @param {number} netDiskIndex
		 * @param {?string} shareCode
		 * @param {?string} accessCode
		 * @returns {string}
		 */
		getCopyUrlInfo(netDiskName, netDiskIndex, shareCode, accessCode) {
			/**
			 * @type {NetDiskRegularOption}
			 */
			let regularOption = NetDisk.regular[netDiskName][netDiskIndex];
			let copyUrl = regularOption["copyUrl"];
			if (shareCode) {
				copyUrl = NetDisk.replaceParam(copyUrl, {
					shareCode: shareCode,
				});
			}
			if (accessCode && accessCode !== "") {
				copyUrl = NetDisk.replaceParam(copyUrl, {
					accessCode: accessCode,
				});
			} else {
				copyUrl = copyUrl.replace(NetDisk.noAccessCodeRegExp, "");
			}
			/**
			 * 当前字典
			 */
			let currentDict = NetDisk.linkDict.get(netDiskName).get(shareCode);
			if (regularOption.paramMatch) {
				let paramMatchArray = currentDict.matchText.match(
					regularOption.paramMatch
				);
				let replaceParamData = {};
				for (let index = 0; index < paramMatchArray.length; index++) {
					replaceParamData[`$${index}`] = paramMatchArray[index];
				}
				copyUrl = NetDisk.replaceParam(copyUrl, replaceParamData);
			}
			return copyUrl;
		},
	};

	/** 网盘-直链鉴权获取处理 */
	const NetDiskAuthorization = {
		/**
		 * 运行于ready
		 */
		init() {
			Object.keys(NetDiskAuthorization.netDisk).forEach((keyName) => {
				this.netDisk[keyName]();
			});
		},
		netDisk: {
			/**
			 * 123网盘,一般用于>100MB的文件直链获取
			 */
			_123pan() {
				if (window.location.hostname !== "www.123pan.com") {
					return;
				}
				/* 没在设置中开启直链获取就不获取鉴权信息 */
				if (!GM_getValue("_123pan-static-enable")) {
					return;
				}
				let authorToken = unsafeWindow.localStorage.getItem("authorToken");
				if (utils.isNull(authorToken)) {
					return;
				}
				/* 去除左右的引号 */
				authorToken = authorToken.replace(/^\"/, "").replace(/\"$/, "");
				log.success("获取123网盘已登录用户的authorToken值👇");
				log.success(authorToken);
				GM_setValue("_123pan_User_Authorization", authorToken);
			},
			/**
			 * 蓝奏优选
			 */
			lanzouyx() {
				/* 目前uuid可生成,userId可以通过请求获取到,暂不需要获取本地存储的 */
				return;
				if (window.location.hostname !== "www.ilanzou.com") {
					return;
				}
				/* 没在设置中开启直链获取就不获取鉴权信息 */
				if (!GM_getValue("lanzouyx-static-enable")) {
					return;
				}
				const uuid = unsafeWindow.localStorage.getItem("uuid");
				let diskVueX = unsafeWindow.localStorage.getItem("disk-vuex");
				let diskPCVueX = unsafeWindow.localStorage.getItem("disk-pc-vuex");
				if (utils.isNotNull(uuid)) {
					log.success(["获取蓝奏云优享生成的uuid:", uuid]);
					GM_setValue("lanzouyx-uuid", uuid);
				}
				if (utils.isNotNull(diskVueX)) {
					diskVueX = utils.toJSON(diskVueX);
					let userId = diskVueX?.["admin"]?.["account"]?.["info"]?.["userId"];
					if (userId != null) {
						log.success(["获取蓝奏云优享已登录用户的userId:", userId]);
						GM_setValue("lanzouyx-userId", userId);
					}
				}
				if (utils.isNotNull(diskPCVueX)) {
					diskPCVueX = utils.toJSON(diskPCVueX);
					let userId = diskVueX?.["common"]?.["accountInfo"]?.["userId"];
					if (userId != null) {
						log.success(["获取蓝奏云优享已登录用户的userId:", userId]);
						GM_setValue("lanzouyx-userId", userId);
					}
				}
			},
		},
	};

	/** 网盘-直链进行Scheme过滤 */
	const NetDiskFilterScheme = {
		protocol: "jumpwsv",
		pathname: "go",
		/**
		 * 处理链接
		 * @param {string} name 规则名
		 * @param {string} intentData 需要处理的数据
		 * @returns {string}
		 */
		parseDataToSchemeUri(name, intentData) {
			/** 是否启用 */
			let isEnable = GM_getValue(name + "-forward-scheme-enable", false);
			if (!isEnable) {
				return intentData;
			}
			/** 转发的scheme */
			let schemeUri = GM_getValue(name + "-static-scheme-uri");
			if (utils.isNull(schemeUri)) {
				schemeUri = this.getSchemeUri(this.getIDMSchemeUriOption(intentData));
			}
			if (schemeUri.startsWith(this.protocol)) {
				intentData = intentData.replace(/&/g, "{-and-}");
				intentData = intentData.replace(/#/g, "{-number-}");
			}
			schemeUri = NetDisk.replaceParam(schemeUri, {
				intentData: intentData,
			});
			return schemeUri;
		},
		isForwardDownloadLink(key) {
			return GM_getValue(`${key}-forward-download-link-enable`, false);
		},
		isForwardBlankLink(key) {
			return GM_getValue(`${key}-forward-blank-link-enable`, false);
		},
		getSchemeUri(option) {
			return `${this.protocol}://${this.pathname}?package=${option["package"]}&activity=${option["activity"]}&intentAction=${option["intentAction"]}&intentData=${option["intentData"]}&intentExtra=${option["intentExtra"]}`;
		},
		getIDMSchemeUriOption(intentData = "") {
			return {
				package: "idm.internet.download.manager.plus",
				activity: "idm.internet.download.manager.UrlHandlerDownloader",
				intentAction: "android.intent.action.VIEW",
				intentData: intentData,
				intentExtra: "",
			};
		},
	};

	/** 网盘-自动填入访问码 */
	const NetDiskAutoFillAccessCode = {
		key: "tempNetDiskInfo",
		$data: {
			/**
			 * 当前的网盘数据
			 * @type {?NetDiskAutoFillAccessCodeOption}
			 */
			netDiskInfo: null,
			/**
			 * @type {boolean} 自动输入访问码是否开启
			 */
			enable: Boolean(GM_getValue("autoFillAccessCode")),
		},
		/**
		 * 初始化
		 */
		init() {
			this.$data.netDiskInfo = this.getValue();
			if (!this.$data.netDiskInfo) {
				return;
			}
			if (!this.$data.enable) {
				return;
			}
			/* 访问码为空的话就不填 */
			if (utils.isNull(this.$data.netDiskInfo.accessCode)) {
				return;
			}
			/* 百度如果shareCode第一位是1的话,新版本会在href中去除这个1 */
			if (
				this.$data.netDiskInfo.netDiskName === "baidu" &&
				this.$data.netDiskInfo.shareCode.startsWith("1")
			) {
				if (
					!window.location.href.includes(
						this.$data.netDiskInfo.shareCode.slice(
							1,
							this.$data.netDiskInfo.shareCode.length
						)
					)
				) {
					return;
				}
			} else if (
				!window.location.href.includes(this.$data.netDiskInfo.shareCode)
			) {
				return;
			}
			if (
				this.$data.netDiskInfo.netDiskName in NetDiskAutoFillAccessCode.netDisk
			) {
				NetDiskAutoFillAccessCode.netDisk[this.$data.netDiskInfo.netDiskName](
					this.$data.netDiskInfo
				);
			}
		},
		netDisk: {
			/**
			 * 百度网盘
			 * @param {NetDiskAutoFillAccessCodeOption} netDiskInfo
			 */
			baidu(netDiskInfo) {
				if (
					window.location.hostname === "pan.baidu.com" &&
					window.location.pathname === "/share/init" &&
					window.location.search.startsWith("?surl=")
				) {
					log.success(["自动填写链接", netDiskInfo]);
					utils.waitNode("div.verify-form #accessCode").then((element) => {
						if (!utils.isVisible(element)) {
							log.error("输入框不可见,不输入密码");
							return;
						}
						Qmsg.success("自动填入访问码");
						element.value = netDiskInfo.accessCode;
						utils.dispatchEvent(element, "input");
						document.querySelector("div.verify-form #submitBtn")?.click();
					});
				}
				if (
					window.location.hostname === "pan.baidu.com" &&
					window.location.pathname === "/wap/init" &&
					window.location.search.startsWith("?surl=")
				) {
					log.success(["自动填写链接", netDiskInfo]);
					utils
						.waitNode(
							"div.extractWrap div.extract-content div.extractInputWrap.extract input[type=text]"
						)
						.then((inputElement) => {
							if (!utils.isVisible(inputElement)) {
								log.error("输入框不可见,不输入密码");
								return;
							}
							Qmsg.success("自动填入访问码");
							inputElement.value = netDiskInfo.accessCode;
							utils.dispatchEvent(inputElement, "input");
							document
								.querySelector(
									"div.extractWrap div.extract-content button.m-button"
								)
								?.click();
						});
				}
			},
			/**
			 * 蓝奏云
			 * @param {NetDiskAutoFillAccessCodeOption} netDiskInfo
			 */
			lanzou(netDiskInfo) {
				if (window.location.hostname.match(/lanzou[a-z]{1}.com/gi)) {
					log.success(["自动填写链接", netDiskInfo]);
					utils.waitNode("#pwd").then((element) => {
						if (!utils.isVisible(element)) {
							log.error("输入框不可见,不输入密码");
							return;
						}
						Qmsg.success("自动填入访问码");
						element.value = netDiskInfo.accessCode;
						utils.dispatchEvent(element, "input");
						(
							document.querySelector("#passwddiv div.passwddiv-input > div") ||
							element.nextElementSibling
						)?.click();
						document.querySelector("#sub")?.click();
					});
					utils.waitNode("#f_pwd").then((element) => {
						utils.mutationObserver(element, {
							config: {
								attributes: true,
								attributeFilter: ["style"],
							},
							callback: (mutations, observer) => {
								let inputElement = document.querySelector("#f_pwd #pwd");
								if (!utils.isVisible(inputElement)) {
									log.error("输入框不可见,不输入密码");
									return;
								}
								observer.disconnect();
								log.success("自动填入访问码并关闭观察者");
								Qmsg.success("自动填入访问码");
								inputElement.value = netDiskInfo.accessCode;
								utils.dispatchEvent(inputElement, "input");
								document.querySelector("#f_pwd #sub")?.click();
							},
						});
					});
				}
			},
			/**
			 * 天翼云
			 * @param {NetDiskAutoFillAccessCodeOption} netDiskInfo
			 */
			tianyiyun(netDiskInfo) {
				if (window.location.hostname === "cloud.189.cn") {
					/* 桌面端 */
					log.success(["自动填写链接", netDiskInfo]);
					/**
					 * 循环等待元素出现
					 * @param {HTMLElement} targetElement
					 * @param {Function} callback
					 */
					function loopWaitElementShow(targetElement, callback) {
						let loopCount = 0;
						let maxLoopCount = 30;
						let interval = setInterval(() => {
							loopCount++;
							if (loopCount > maxLoopCount) {
								log.error("结束循环检查,退出。");
								clearInterval(interval);
								return;
							}
							if (!utils.isVisible(targetElement)) {
								log.warn(`第 ${loopCount} 次:输入框不可见,不输入密码`);
								return;
							}
							callback();
							clearInterval(interval);
						}, 500);
					}

					utils.waitNode("input#code_txt").then((codeTxtElement) => {
						loopWaitElementShow(codeTxtElement, () => {
							Qmsg.success("自动填入访问码");
							let visitBtn = document.querySelector(".btn.btn-primary.visit");
							codeTxtElement.value = netDiskInfo.accessCode;
							codeTxtElement._value = netDiskInfo.accessCode;
							utils.dispatchEvent(codeTxtElement, "input");
							utils.dispatchEvent(visitBtn, "click");
						});
					});
				}
				if (window.location.hostname === "h5.cloud.189.cn") {
					/* 移动端 */
					log.success(["自动填写链接", netDiskInfo]);
					utils
						.waitNode("input.access-code-input")
						.then((accessInputElement) => {
							loopWaitElementShow(accessInputElement, () => {
								Qmsg.success("自动填入访问码");
								accessInputElement.value = netDiskInfo.accessCode;
								accessInputElement._value = netDiskInfo.accessCode;
								utils.dispatchEvent(accessInputElement, "input");
								utils.dispatchEvent(
									document.querySelector("div.button"),
									"click"
								);
							});
						});
				}
			},
			/**
			 * 中国移动云盘
			 * @param {NetDiskAutoFillAccessCodeOption} netDiskInfo
			 */
			hecaiyun(netDiskInfo) {
				if (window.location.hostname === "caiyun.139.com") {
					/* 桌面端 */
					log.success(["自动填写链接", netDiskInfo]);
					utils.waitNode("#token-input").then((element) => {
						if (!utils.isVisible(element)) {
							log.error("输入框不可见,不输入密码");
							return;
						}
						Qmsg.success("自动填入访问码");
						element.value = netDiskInfo.accessCode;
						utils.dispatchEvent(element, "input");
						document
							.querySelector("#homepage div.token div.token-form a")
							.click();
					});
					/* 移动端 */
					utils
						.waitNode("#app div.token-form input[type=text]")
						.then((element) => {
							if (!utils.isVisible(element)) {
								log.error("输入框不可见,不输入密码");
								return;
							}
							Qmsg.success("自动填入访问码");
							element.value = netDiskInfo.accessCode;
							utils.dispatchEvent(element, "input");
							document.querySelector("div.token-form a.btn-token").click();
						});
				}
			},
			/**
			 * 阿里云盘
			 * @param {NetDiskAutoFillAccessCodeOption} netDiskInfo
			 */
			aliyun(netDiskInfo) {
				if (
					window.location.hostname === "www.aliyundrive.com" ||
					window.location.hostname === "www.alipan.com"
				) {
					/* 桌面端 */
					log.success(["自动填写链接", netDiskInfo]);
					utils.waitNode("#root input.ant-input").then((element) => {
						if (!utils.isVisible(element)) {
							log.error("输入框不可见,不输入密码");
							return;
						}
						Qmsg.success("自动填入访问码");
						element.value = netDiskInfo.accessCode;
						utils.getReactObj(element).reactFiber.memoizedProps.onChange({
							currentTarget: element,
							target: element,
						});
						document.querySelector('#root button[type="submit"]').click();
					});

					/* ------------------------------------ */

					/* 移动端 */
					utils.waitNode("#root input[name=pwd]").then((element) => {
						if (!utils.isVisible(element)) {
							log.error("输入框不可见,不输入密码");
							return;
						}
						Qmsg.success("自动填入访问码");
						element.value = netDiskInfo.accessCode;
						utils.getReactObj(element).reactFiber.memoizedProps.onChange({
							currentTarget: element,
							target: element,
						});
						document.querySelector('#root button[type="submit"]').click();
					});
				}
			},
			/**
			 * 文叔叔
			 * 暂时没找到有密码的链接
			 * @param {NetDiskAutoFillAccessCodeOption} netDiskInfo
			 */
			wenshushu(netDiskInfo) {},
			/**
			 * 奶牛
			 * 暂时没找到有密码的链接
			 * @param {NetDiskAutoFillAccessCodeOption} netDiskInfo
			 */
			nainiu(netDiskInfo) {},
			/**
			 * 123云盘
			 * @param {NetDiskAutoFillAccessCodeOption} netDiskInfo
			 */
			_123pan(netDiskInfo) {
				if (window.location.hostname === "www.123pan.com") {
					/* 桌面端 */
					log.success(["自动填写链接", netDiskInfo]);
					utils
						.waitNode("#app .ca-fot input.ant-input[type=text]")
						.then((element) => {
							if (!utils.isVisible(element)) {
								log.error("输入框不可见,不输入密码");
								return;
							}
							Qmsg.success("自动填入访问码");
							utils.getReactObj(element).reactProps.onChange({
								target: {
									value: netDiskInfo.accessCode,
								},
							});
							element.nextSibling.click();
						});

					/* ------------------------------------ */

					/* 移动端 */
					utils
						.waitNode("#app .appinput input.ant-input[type=text]")
						.then((element) => {
							if (!utils.isVisible(element)) {
								log.error("输入框不可见,不输入密码");
								return;
							}
							Qmsg.success("自动填入访问码");
							utils.getReactObj(element).reactProps.onChange({
								target: {
									value: netDiskInfo.accessCode,
								},
							});
							element.nextSibling.click();
						});
				}
			},
			/**
			 * 腾讯微云
			 * @param {NetDiskAutoFillAccessCodeOption} netDiskInfo
			 */
			weiyun(netDiskInfo) {
				if (window.location.hostname === "share.weiyun.com") {
					/* 桌面端 */
					log.success(["自动填写链接", netDiskInfo]);
					utils.waitNode("#app input.input-txt").then((element) => {
						if (!utils.isVisible(element)) {
							log.error("输入框不可见,不输入密码");
							return;
						}
						Qmsg.success("自动填入访问码");
						element.value = netDiskInfo.accessCode;
						utils.dispatchEvent(element, "input");
						utils.dispatchEvent(element, "change");
						setTimeout(() => {
							document.querySelector(".form-item button.btn-main").click();
						}, 500);
					});

					/* ------------------------------------ */

					/* 移动端 */
					utils.waitNode(".input-wrap input.pw-input").then((element) => {
						if (!utils.isVisible(element)) {
							log.error("输入框不可见,不输入密码");
							return;
						}
						Qmsg.success("自动填入访问码");
						element.value = netDiskInfo.accessCode;
						utils.dispatchEvent(element, "input");
						utils.dispatchEvent(element, "change");
						setTimeout(() => {
							document.querySelector(".pw-btn-wrap button.btn").click();
						}, 500);
					});
				}
			},
			/**
			 * 迅雷
			 * @param {NetDiskAutoFillAccessCodeOption} netDiskInfo
			 */
			xunlei(netDiskInfo) {
				if (window.location.hostname === "pan.xunlei.com") {
					/* 桌面端 */
					log.success(["自动填写链接", netDiskInfo]);
					utils
						.waitNode("#__layout div.pass-input-wrap input.td-input__inner")
						.then((element) => {
							if (!utils.isVisible(element)) {
								log.error("输入框不可见,不输入密码");
								return;
							}
							log.error("输入框不可见,不输入密码");
							element.value = netDiskInfo.accessCode;
							utils.dispatchEvent(element, "input");
							utils.dispatchEvent(element, "change");
							setTimeout(() => {
								document
									.querySelector(
										"#__layout div.pass-input-wrap button.td-button"
									)
									.click();
							}, 500);
						});

					/* ------------------------------------ */

					/* 移动端 */
					utils
						.waitNode("#__layout div.pass-wrapper input.td-input__inner")
						.then((element) => {
							if (!utils.isVisible(element)) {
								log.error("输入框不可见,不输入密码");
								return;
							}
							log.error("输入框不可见,不输入密码");
							element.value = netDiskInfo.accessCode;
							utils.dispatchEvent(element, "input");
							utils.dispatchEvent(element, "change");
							setTimeout(() => {
								document
									.querySelector("#__layout div.pass-wrapper button.td-button")
									.click();
							}, 500);
						});
				}
			},
			/**
			 * 115网盘
			 * @param {NetDiskAutoFillAccessCodeOption} netDiskInfo
			 */
			_115pan(netDiskInfo) {
				if (window.location.hostname === "115.com") {
					log.success(["自动填写链接", netDiskInfo]);
					utils.waitNode("input.text").then((element) => {
						if (!utils.isVisible(element)) {
							log.error("输入框不可见,不输入密码");
							return;
						}
						Qmsg.success("自动填入访问码");
						element.value = netDiskInfo.accessCode;
						utils.dispatchEvent(element, "input");
						document
							.querySelector("#js-share_code div.form-decode div.submit a")
							.click();
					});
				}
			},
			/**
			 * 城通网盘
			 * @param {NetDiskAutoFillAccessCodeOption} netDiskInfo
			 */
			chengtong(netDiskInfo) {
				log.success(["自动填写链接", netDiskInfo]);
				utils.waitNode("#passcode").then((element) => {
					if (!utils.isVisible(element)) {
						log.error("输入框不可见,不输入密码");
						return;
					}
					Qmsg.success("自动填入访问码");
					element.value = netDiskInfo.accessCode;
					utils.dispatchEvent(element, "input");
					document
						.querySelector("#main-content .form-group button.btn[type=button]")
						.click();
				});
			},
			/**
			 * 夸克网盘
			 * @param {NetDiskAutoFillAccessCodeOption} netDiskInfo
			 */
			kuake(netDiskInfo) {
				if (window.location.hostname === "pan.quark.cn") {
					log.success(["自动填写链接", netDiskInfo]);
					utils
						.waitNode("#ice-container input.ant-input[class*=ShareReceive]")
						.then((element) => {
							if (!utils.isVisible(element)) {
								log.error("输入框不可见,不输入密码");
								return;
							}
							Qmsg.success("自动填入访问码");
							(
								utils.getReactObj(element).reactProps ||
								utils.getReactObj(element).reactEventHandlers
							).onChange({
								target: {
									value: netDiskInfo.accessCode,
								},
							});
						});
				}
			},
			/**
			 * 坚果云
			 * 暂时没找到有密码的链接
			 * @param {NetDiskAutoFillAccessCodeOption} netDiskInfo
			 */
			jianguoyun(netDiskInfo) {},
			/**
			 * OneDrive
			 * 暂时没找到有密码的链接
			 * @param {NetDiskAutoFillAccessCodeOption} netDiskInfo
			 */
			onedrive(netDiskInfo) {},
		},
		/**
		 *
		 * @param {NetDiskAutoFillAccessCodeOption} value
		 */
		setValue(value) {
			GM_setValue(this.key, value);
		},
		getValue() {
			return GM_getValue(this.key);
		},
	};

	/** Woker */
	const NetDiskWorker = {
		/** 是否正在匹配中 */
		isHandleMatch: false,
		/** worker的Blob链接 */
		blobUrl: "",
		/** @type {Worker} */
		GM_matchWorker: void 0,
		/** 初始化Worker的Blob链接 */
		initWorkerBlobLink() {
			const handleMatch = `
			(() => {
				function ${NetDiskWorker.handleRegularMatch.toString()}

				function ${NetDiskWorker.uniqueArr}
				
				this.addEventListener(
				"message",
				function (event) {
					const data = event.data;
					let matchedList = [];
					${NetDiskWorker.handleRegularMatch.name}(data,(matchData)=>{
					matchedList.push(matchData);
					})
					matchedList = ${NetDiskWorker.uniqueArr.name}(matchedList);
					this.postMessage({
					options: data,
					msg: "Match End",
					data: matchedList,
					startTime: data.startTime,
					endTime: Date.now(),
					});
				},
				{
					capture: true,
				}
				);
			})();
      `;
			let blob = new Blob([handleMatch]);
			NetDiskWorker.blobUrl = window.URL.createObjectURL(blob);
			log.info(`Worker Blob Link ===> ${NetDiskWorker.blobUrl}`);
		},
		/**
		 * 处理规则匹配
		 * @param {NetDiskWorkerOptions} data 数据
		 * @param {( matchData: NetDiskWorkerMatchOption )=>void} callback 成功匹配到的回调
		 */
		handleRegularMatch(data, callback) {
			const NetDiskRegularNameList = Object.keys(data.regular);
			for (const netDiskName of NetDiskRegularNameList) {
				const netDiskRegular = data.regular[netDiskName];
				for (let index = 0; index < netDiskRegular.length; index++) {
					const netDiskRegularItem = netDiskRegular[index];
					if (
						netDiskRegularItem["enable"] != null &&
						!netDiskRegularItem["enable"]
					) {
						continue;
					}
					let regexpList = [];
					if (data.matchTextRange === "all") {
						regexpList.push(
							new RegExp(netDiskRegularItem["link_innerText"], "gi")
						);
						regexpList.push(
							new RegExp(netDiskRegularItem["link_innerHTML"], "gi")
						);
					} else if (data.matchTextRange === "innertext") {
						regexpList.push(
							new RegExp(netDiskRegularItem["link_innerText"], "gi")
						);
					} else if (data.matchTextRange === "innerhtml") {
						regexpList.push(
							new RegExp(netDiskRegularItem["link_innerHTML"], "gi")
						);
					} else {
						throw new TypeError("未知的匹配范围: " + data.matchTextRange);
					}
					for (const regexp of regexpList) {
						for (const text of data.textList) {
							let matchData = text.match(regexp);
							if (matchData && matchData.length) {
								callback({
									netDiskName: netDiskName,
									netDiskIndex: index,
									data: matchData,
								});
							}
						}
					}
				}
			}
		},
		/**
		 * 数组去重
		 */
		uniqueArr(arr) {
			return arr.filter((obj, index, selfArray) => {
				return (
					index ===
					selfArray.findIndex((item) => {
						return JSON.stringify(item) === JSON.stringify(obj);
					})
				);
			});
		},
		/**
		 * 初始化Worker对象
		 */
		initWorker() {
			try {
				NetDiskWorker.GM_matchWorker = new Worker(NetDiskWorker.blobUrl);
				NetDiskWorker.GM_matchWorker.onmessage = NetDiskWorker.onMessage;
				NetDiskWorker.GM_matchWorker.onerror = NetDiskWorker.onError;
			} catch (error) {
				log.error([
					"初始化Worker失败,可能页面使用了Content-Security-Policy策略,使用另类方法",
					error.message,
				]);
				NetDiskWorker.GM_matchWorker = {
					/**
					 *
					 * @param {NetDiskWorkerOptions} data
					 */
					postMessage(data) {
						return new Promise((resolve, reject) => {
							/** @type {NetDiskWorkerMatchOption[]} */
							let matchedList = [];
							try {
								NetDiskWorker.handleRegularMatch(data, (matchData) => {
									matchedList.push(matchData);
								});
							} catch (error) {
								NetDiskWorker.onError(error);
							} finally {
								matchedList = NetDiskWorker.uniqueArr(matchedList);
								NetDiskWorker.onMessage(
									new MessageEvent("message", {
										data: {
											options: data,
											msg: "Match End",
											data: matchedList,
											startTime: data.startTime,
											endTime: Date.now(),
										},
									})
								);
								resolve();
							}
						});
					},
				};
			}
		},
		/**
		 * 传递数据给worker内进行处理匹配
		 * @param { NetDiskWorkerOptions } message 数据
		 * @param { ?StructuredSerializeOptions } options 配置
		 */
		postMessage(message, options) {
			if (isDebug) {
				log.info(["Debug-传递数据给worker内进行处理匹配: ", message]);
			}
			NetDiskWorker.GM_matchWorker.postMessage(message, options);
		},
		/**
		 * Worker的onmessage
		 * @param {MessageEvent<NetDiskWorkerCallBackOptions>} event
		 */
		onMessage(event) {
			const data = event.data;
			if (isDebug) {
				log.info([
					`Debug-匹配结束,用时${Date.now() - data.startTime}ms: `,
					data,
				]);
			}
			if (data.data.length) {
				log.success(
					`成功匹配${data.data.length}个,用时${Date.now() - data.startTime}ms`
				);
			}
			if (event.data.options.from === "PasteText") {
				NetDiskUI.matchPasteText.matchEndCallBack(data);
			}
			NetDiskWorker.successCallBack(data);
		},
		/**
		 * Worker的onerror
		 * @param {ErrorEvent} error
		 */
		onError(error) {
			NetDiskWorker.errorCallBack(error);
		},
		/**
		 * worker处理文件匹配后的回调
		 * @param {NetDiskWorkerCallBackOptions} options
		 */
		successCallBack(options) {
			/* 匹配为空,释放锁 */
			if (!options.data.length) {
				NetDiskWorker.matchingEndCallBack();
				return;
			}
			/** @type {NetiDiskHandleObject[]} */
			const handleNetDiskList = [];
			for (const matchData of options.data) {
				/* 已匹配到的网盘,用于显示图标 */
				NetDisk.matchLink.add(matchData.netDiskName);
				/**
				 * 匹配到的可能很多,使用集合去重
				 * @type {Set<string>}
				 */
				let matchLinkSet = new Set();
				matchData.data.forEach((item) => {
					matchLinkSet.add(item);
				});

				matchLinkSet.forEach((item) => {
					let handleLink = NetDisk.handleLink(
						matchData.netDiskName,
						matchData.netDiskIndex,
						item
					);
					if (handleLink) {
						handleNetDiskList.push({
							shareCode: handleLink.shareCode,
							accessCode: handleLink.accessCode,
							netDiskName: matchData.netDiskName,
							netDiskIndex: matchData.netDiskIndex,
							matchText: item,
						});
					}
				});
			}
			/* 过滤掉重复的 */
			let filterHandleNetDiskList = handleNetDiskList.filter(
				(value, index, selfArray) => {
					let isFind =
						selfArray.findIndex((obj) => {
							/* 过滤掉同样配置的 */
							/* 或者是netDiskName、netDiskIndex相同,且shareCode前面存在重复的 */
							return (
								//JSON.stringify(obj) === JSON.stringify(value)
								obj.accessCode === value.accessCode &&
								obj.netDiskIndex === value.netDiskIndex &&
								obj.netDiskName === value.netDiskName &&
								obj.shareCode === value.shareCode
								//(obj.netDiskName === value.netDiskName &&
								//  obj.netDiskIndex === value.netDiskIndex &&
								//  obj.shareCode.startsWith(value.shareCode)) ||
								//value.shareCode.startsWith(obj.shareCode)
							);
						}) === index;
					return isFind;
				}
			);
			filterHandleNetDiskList.forEach((item) => {
				if (NetDisk.tempLinkDict.has(item.netDiskName)) {
					let currentTempDict = NetDisk.tempLinkDict.get(item.netDiskName);
					currentTempDict.set(item.shareCode, item);
				}
			});
			filterHandleNetDiskList.forEach((item) => {
				const { shareCode, accessCode, netDiskName, netDiskIndex, matchText } =
					item;
				const currentRegular = NetDisk.regular[netDiskName][netDiskIndex];
				if (
					currentRegular.shareCodeExcludeRegular &&
					Array.isArray(currentRegular.shareCodeExcludeRegular)
				) {
					/* 排除掉在目标规则已匹配到的shareCode */
					for (const excludeRegularName of currentRegular.shareCodeExcludeRegular) {
						let excludeDict = NetDisk.linkDict.get(excludeRegularName);
						let currentTempDict = NetDisk.tempLinkDict.get(excludeRegularName);
						if (
							excludeDict.startsWith(shareCode) ||
							currentTempDict.startsWith(shareCode)
						) {
							log.warn(
								`${netDiskName}:该分享码【${shareCode}】与已匹配到该分享码的规则【${excludeRegularName}】冲突`
							);
							return;
						}
					}
				}

				/** 当前存储的 */
				const currentDict = NetDisk.linkDict.get(netDiskName);
				NetDisk.hasMatchLink = true;
				if (currentDict.startsWith(shareCode)) {
					/* 存在该访问码 */
					/* 根据shareCode获取accessCode和netDiskIndex信息 */
					let shareCodeDict = currentDict.getStartsWith(shareCode);
					if (
						typeof shareCodeDict.isForceAccessCode === "boolean" &&
						shareCodeDict.isForceAccessCode
					) {
						/* 该访问码已被锁定,禁止修改 */
						return;
					}
					if (utils.isNotNull(shareCodeDict.accessCode)) {
						/* 已匹配到的访问码不为空,不设置新的 */
						return;
					}
					if (utils.isNull(accessCode)) {
						/* 访问码为空,不设置新的 */
						return;
					}

					currentDict.set(
						shareCode,
						NetDisk.getLinkDickObj(accessCode, netDiskIndex, false, matchText)
					);
					NetDiskUI.view.changeLinkView(
						netDiskName,
						netDiskIndex,
						shareCode,
						accessCode,
						matchText
					);
					log.info(
						`该匹配项无密码,设置密码 ${netDiskName} ${netDiskIndex}: ${shareCode}  ===> ${accessCode}`
					);
				} else {
					/* 不存在该访问码,添加新的进去 */
					currentDict.set(
						shareCode,
						NetDisk.getLinkDickObj(accessCode, netDiskIndex, false, matchText)
					);
					NetDiskUI.isMatchedNetDiskIconMap.add(netDiskName);
					NetDiskUI.view.addLinkView(
						netDiskName,
						netDiskIndex,
						shareCode,
						accessCode,
						matchText
					);
					log.success(
						`添加链接 ${netDiskName} ${netDiskIndex}: ${shareCode}  ===> ${accessCode}`
					);
				}
			});

			/* 清空临时的 */
			Object.keys(NetDisk.tempLinkDict.getItems()).forEach((keyName) => {
				NetDisk.tempLinkDict.get(keyName).clear();
			});
			if (NetDisk.hasMatchLink) {
				switch (NetDiskUIMenuData.netdiskBehaviorMode) {
					case "suspension_smallwindow".toLowerCase():
						if (
							GM_getValue(
								"current_suspension_smallwindow_mode",
								"suspension"
							) === "suspension"
						) {
							NetDiskUI.suspension.show();
						} else {
							NetDiskUI.view.show();
						}
						break;
					case "suspension_window".toLowerCase():
						NetDiskUI.suspension.show();
						break;
					case "smallwindow".toLowerCase():
						NetDiskUI.view.show();
						break;
					default:
						log.error([
							"未知的行为模式:" + NetDiskUIMenuData.netdiskBehaviorMode,
						]);
				}
			}
			NetDiskWorker.matchingEndCallBack();
		},
		/**
		 * Worker失败回调
		 * @param {object} error
		 */
		errorCallBack(error) {
			NetDiskWorker.matchingEndCallBack(true);
			log.error(["Worker Error", error]);
		},
		/**
		 * 匹配结束回调
		 * @param {boolean} isNow 是否立刻释放锁
		 */
		matchingEndCallBack(isNow) {
			if (isNow) {
				NetDiskWorker.isHandleMatch = false;
			} else {
				const delaytime =
					parseFloat(
						GM_getValue("delaytime", NetDiskData.defaultMatchIntervalTime)
					) * 1000;
				setTimeout(() => {
					NetDiskWorker.matchingEndCallBack(true);
				}, delaytime);
			}
		},
		/**
		 * 监听页面节点内容或节点文本的变动,从而进行匹配网盘链接
		 */
		monitorDOMChange() {
			NetDiskWorker.initWorkerBlobLink();
			NetDiskWorker.initWorker();
			/**
			 * 设置-判定为添加元素才进行匹配
			 * @type {boolean}
			 */
			const isAddedNodesToMatch = GM_getValue("isAddedNodesToMatch");
			/**
			 * 观察者的事件
			 * @param {?MutationRecord[]} mutations
			 */
			async function observeEvent(mutations) {
				if (NetDiskWorker.isHandleMatch) {
					/* 当前正在处理规则匹配字符串中 */
					return;
				}
				if (isAddedNodesToMatch && mutations && mutations.length) {
					// 设定为添加元素才匹配且观察器检测到改变的元素
					/** 判断是否存在添加的元素 */
					let hasAddNodes = false;
					for (const mutation of mutations) {
						if (
							mutation.addedNodes &&
							mutation.addedNodes instanceof NodeList
						) {
							if (mutation.addedNodes.length) {
								hasAddNodes = true;
								break;
							}
						}
					}
					if (!hasAddNodes) {
						return;
					}
				}
				NetDiskWorker.isHandleMatch = true;
				/** 开始时间 */
				const startTime = Date.now();
				/** 读取剪贴板内容 */
				let readClipboard = GM_getValue("readClipboard", false);
				if (readClipboard) {
					NetDisk.clipboardText = await NetDisk.getClipboardText();
				}
				if (typeof NetDisk.clipboardText !== "string") {
					NetDisk.clipboardText = "";
				}
				let matchTextRangeLowerCase = GM_getValue(
					"pageMatchRange",
					"all"
				).toLowerCase();
				/** @type {string[]} */
				let matchTextList = [];

				/* 剪贴板内容 */
				if (NetDisk.clipboardText.trim() !== "") {
					matchTextList.push(NetDisk.clipboardText);
				}
				/* 当前的网页链接 */
				if (NetDisk.allowMatchLocationHref) {
					let decodeUrl = window.location.href;
					try {
						decodeUrl = decodeURIComponent(decodeUrl);
					} catch (error) {}
					matchTextList.push(decodeUrl);
				}
				/* innerText和innerHTML */
				if (matchTextRangeLowerCase === "all") {
					let pageText = NetDisk.ignoreStrRemove(
						document.documentElement.innerText
					);
					let pageHTML = NetDisk.ignoreStrRemove(
						document.documentElement.innerHTML,
						true
					);
					matchTextList.push(pageText);
					matchTextList.push(pageHTML);
				} else if (matchTextRangeLowerCase === "innertext") {
					/* innerText */
					let pageText = NetDisk.ignoreStrRemove(
						document.documentElement.innerText
					);
					matchTextList.push(pageText);
				} else {
					/* innerHTML */
					let pageHTML = NetDisk.ignoreStrRemove(
						document.documentElement.innerHTML,
						true
					);
					matchTextList.push(pageHTML);
				}
				/* 发送消息 */
				NetDiskWorker.postMessage({
					textList: matchTextList,
					matchTextRange: matchTextRangeLowerCase,
					regular: NetDisk.regular,
					startTime: startTime,
					from: "DOMChange",
				});
			}
			utils.mutationObserver(document.documentElement, {
				callback: observeEvent,
				/* 主动触发一次,因为有的页面上没触发mutationObserver */
				immediate: true,
				config: {
					/* 子节点的变动(新增、删除或者更改) */
					childList: GM_getValue(
						"mutationObserver-childList",
						NetDiskData.default_mutationObserver_childList
					),
					/* 节点内容或节点文本的变动 */
					characterData: GM_getValue(
						"mutationObserver-characterData",
						NetDiskData.default_mutationObserver_characterData
					),
					/* 是否将观察器应用于该节点的所有后代节点 */
					subtree: GM_getValue(
						"mutationObserver-subtree",
						NetDiskData.default_mutationObserver_subtree
					),
				},
			});
		},
	};

	/** 网盘-引用/获取文件 */
	const NetDiskRequire = {
		requiredFileMap: new Map(),
		/**
		 * 网络加载文件
		 * @param {string} path
		 * @param {HttpxDetails} options
		 * @returns
		 */
		async file(path, options) {
			if (utils.isNull(path)) {
				log.error(["NetDiskRequire.file的参数path为空", path]);
				return false;
			}
			if (this.requiredFileMap.has(path)) {
				log.warn(["NetDiskRequire.file的参数path已引入过", path]);
				return true;
			}
			let getResp = await httpx.get(path, options);
			if (!getResp.status) {
				return false;
			}
			let jsText = getResp.data.responseText;
			this.requiredFileMap.set(path, jsText);
			log.info(["加载js文件", path]);
			unsafeWindow.eval(jsText);
			await utils.sleep(300);
		},
	};

	/** 网盘-自定义规则 */
	const NetDiskCustomRules = {
		key: "userRule",
		dataKey: "userRuleData",
		$data: {
			/**
			 * @type {UtilsDictionaryConstructor<string,NetDiskSettingMenuDetails>}
			 */
			settingViewDetails: new utils.Dictionary(),
		},
		init() {
			if (typeof GM_getValue(this.dataKey) !== "object") {
				GM_setValue(this.dataKey, {});
			}
			let userRule = this.parseRule(this.getRule());
			for (let ruleName in userRule) {
				if (ruleName in NetDisk.regular) {
					/* 如果规则已存在(已内置),自定义规则先放在前面匹配 */
					NetDisk.regular[ruleName] = [
						...userRule[ruleName],
						...NetDisk.regular[ruleName],
					];
				} else {
					NetDisk.regular[ruleName] = userRule[ruleName];
				}
			}
		},
		getCSS() {
			return `
      .pops[type-value=confirm] .pops-confirm-content{
        overflow: hidden;
      }
      /* textarea美化 */
      .pops.whitesevPopNetDiskCustomRules[type-value="confirm"] .pops-confirm-content textarea{
        width: 100%;
        height: 100%;
        border: none;
        outline: none;
        padding: 0;
        margin: 0;
        -webkit-appearance: none;
        -moz-appearance: none;
        appearance: none;
        background-image: none;
        background-color: transparent;

        display: inline-block;
        resize: vertical;
        padding: 5px 15px;
        line-height: 1.5;
        box-sizing: border-box;
        border: 1px solid #dcdfe6;
        transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
        appearance: none;
        resize: none;
      }
      /* 获得焦点 */
      .pops.whitesevPopNetDiskCustomRules[type-value="confirm"] .pops-confirm-content textarea:focus{
        outline: none;
        border-color: #3677f0;
      }
      /* 提示文字 */
      .pops.whitesevPopNetDiskCustomRules[type-value="confirm"] .pops-confirm-content textarea::placeholder {
        color: #c0c4cc;
      }
      /* 鼠标hover */
      .pops.whitesevPopNetDiskCustomRules[type-value="confirm"] .pops-confirm-content textarea:hover {
        border-color: #c0c4cc;
      }
      `;
		},
		/**
		 * 添加/编辑规则
		 * @param {boolean} isEdit
		 * @param {?string} ruleKey 当isEdit为true时,传入该值
		 */
		showUI(isEdit, ruleKey) {
			let titleText = "添加";
			if (isEdit) {
				titleText = "编辑";
			}
			titleText += "自定义规则";
			/** @type {HTMLTextAreaElement} */
			let $ruleInput = null;

			/**
			 * 保存按钮的回调
			 * @param {PopsBtnCallBackEvent} event
			 */
			function saveCallBack(event) {
				/**
				 * 检测regexp项是否符合规定
				 * @param {NetDiskUserCustomRuleRegexp} ruleRegExp
				 * @returns
				 */
				function checkRegExp(ruleRegExp) {
					if (typeof ruleRegExp["link_innerText"] !== "string") {
						Qmsg.error("regexp缺失的键名: link_innerText,类型: string");
						return;
					}
					if (typeof ruleRegExp["link_innerHTML"] !== "string") {
						Qmsg.error("regexp缺失的键名: link_innerHTML,类型: string");
						return;
					}
					if (typeof ruleRegExp["shareCode"] !== "string") {
						Qmsg.error("regexp缺失的键名: shareCode,类型: string");
						return;
					}
					if (typeof ruleRegExp["shareCodeNeedRemoveStr"] !== "string") {
						Qmsg.error(
							"regexp缺失的键名: shareCodeNeedRemoveStr,类型: string"
						);
						return;
					}
					if (typeof ruleRegExp["uiLinkShow"] !== "string") {
						Qmsg.error("regexp缺失的键名: uiLinkShow,类型: string");
						return;
					}
					if (typeof ruleRegExp["blank"] !== "string") {
						Qmsg.error("regexp缺失的键名: blank,类型: string");
						return;
					}
					if (typeof ruleRegExp["copyUrl"] !== "string") {
						Qmsg.error("regexp缺失的键名: copyUrl,类型: string");
						return;
					}
					if (
						typeof ruleRegExp["accessCode"] === "string" &&
						typeof ruleRegExp["checkAccessCode"] !== "string"
					) {
						Qmsg.error("regexp设置了accessCode但是没有设置checkAccessCode");
						return;
					}
					if (
						typeof ruleRegExp["accessCode"] !== "string" &&
						typeof ruleRegExp["checkAccessCode"] === "string"
					) {
						Qmsg.error("regexp设置了checkAccessCode但是没有设置accessCode");
						return;
					}
					return true;
				}
				/**
				 * 检测设置项是否符合规定
				 * @param {NetDiskUserCustomRuleSetting} ruleSetting
				 */
				function checkSetting(ruleSetting) {
					if (typeof ruleSetting["name"] !== "string") {
						Qmsg.error("setting缺失的键名: name,类型: string");
						return;
					}
					if (typeof ruleSetting["enable"] !== "boolean") {
						Qmsg.error("setting缺失的键名: enable,类型: boolean");
						return;
					}
					return true;
				}
				try {
					/**
					 * @type {NetDiskUserCustomRule}
					 */
					let ruleJSON = JSON.parse($ruleInput.value);
					if (typeof ruleJSON !== "object") {
						Qmsg.error("该规则不是object类型");
						return;
					}
					if (typeof ruleJSON["key"] !== "string") {
						Qmsg.error("缺失的键名: key,类型: string");
						return;
					}
					if (typeof ruleJSON["regexp"] !== "object") {
						Qmsg.error("缺失的键名: regexp,类型: object|Arrany");
						return;
					}
					if (typeof ruleJSON["setting"] !== "object") {
						Qmsg.error("缺失的键名: setting,类型: object");
						return;
					}
					if (Array.isArray(ruleJSON["regexp"])) {
						for (const regexpItem of ruleJSON["regexp"]) {
							if (!checkRegExp(regexpItem)) {
								return;
							}
						}
					} else {
						if (!checkRegExp(ruleJSON["regexp"])) {
							return;
						}
					}

					if (!checkSetting(ruleJSON["setting"])) {
						return;
					}
					if (isEdit) {
						NetDiskCustomRules.setRule(ruleKey, ruleJSON);
					} else {
						NetDiskCustomRules.addRule(ruleJSON);
					}
					Qmsg.success("保存成功");
					return ruleJSON;
				} catch (error) {
					log.error(error);
					Qmsg.error(error.message, {
						html: true,
						timeout: 3500,
					});
					return;
				}
			}
			/**
			 * 调试按钮的回调
			 * @param {PopsBtnCallBackEvent} event
			 */
			function debugCallBack(event) {
				let ruleJSON = saveCallBack(event);
				if (!ruleJSON) {
					return;
				}
				NetDiskCustomRules.showDebugUI(ruleJSON);
			}
			/**
			 * 格式化按钮的回调
			 * @param {PopsBtnCallBackEvent} event
			 */
			function formatCallBack(event) {
				try {
					let ruleJSON = JSON.parse($ruleInput.value);
					let ruleJSONString = NetDiskCustomRules.getFormatRule(ruleJSON);
					$ruleInput.value = ruleJSONString;
					Qmsg.success("格式化成功");
				} catch (error) {
					log.error(error);
					Qmsg.error(error.message, {
						html: true,
						timeout: 3500,
					});
				}
			}
			let dialog = NetDiskPops.confirm(
				{
					title: {
						text: titleText,
						position: "center",
					},
					content: {
						text: `<textarea class="netdisk-custom-rules" placeholder="请输入自定义规则"></textarea>`,
						html: true,
					},
					btn: {
						merge: true,
						mergeReverse: false,
						reverse: false,
						position: "space-between",
						ok: {
							text: "保存",
							callback: saveCallBack,
						},
						cancel: {
							text: "调试",
							callback: debugCallBack,
						},
						other: {
							enable: true,
							text: "格式化",
							type: "xiaomi-primary",
							callback: formatCallBack,
						},
					},
					class: "whitesevPopNetDiskCustomRules",
					style: this.getCSS(),
				},
				NetDiskUI.popsStyle.customRulesView
			);
			$ruleInput = dialog.$shadowRoot.querySelector("textarea");
			if (isEdit) {
				let rule = this.getRule(ruleKey);
				$ruleInput.value = this.getFormatRule(rule);
			} else {
				$ruleInput.value = this.getTemplateRule();
			}
		},
		/**
		 * 调试规则
		 * @param {NetDiskUserCustomRule} ruleJSON
		 */
		showDebugUI(ruleJSON) {
			if (utils.isNull(ruleJSON.regexp)) {
				Qmsg.error("请先配置regexp");
				return;
			}
			let that = this;
			let customRule = this.parseRule([ruleJSON]);
			let regexp = customRule[ruleJSON.key];
			let dialog = NetDiskPops.confirm(
				{
					title: {
						text: `调试规则 ${ruleJSON.key}`,
						position: "center",
					},
					content: {
						text: `
          <div class="custom-rule-container">
            <textarea class="custom-rule-match-text" placeholder="请输入需要测试匹配的字符串"></textarea>
            <div class="custom-rule-input-container">
              <select class="custom-rule-select-regexp"></select>
              <button class="custom-rule-run-match-button" type="primary" data-icon="" data-righticon="false">
                <span>执行</span>
              </button>
            </div>
          </div>
          <div class="custom-rule-match-log">
            <div>匹配日志↓</div>
            <div class="custom-rule-match-log-container"></div>
          </div>
          `,
						html: true,
					},
					btn: {
						ok: {
							enable: false,
						},
					},
					style: `
        .custom-rule-container{
          display: flex;
          align-items: center;
        }
        .custom-rule-select-regexp{
          width: 100%;
          height: 32px;
          line-height: 32px;
          border: 1px solid rgb(184, 184, 184, var(--pops-bd-opacity));
          border-radius: 5px;
          text-align: center;
          outline: 0;
          background: rgb(255, 255, 255, var(--pops-bg-opacity));
          box-shadow: none;
        }
        .custom-rule-input-container{
          display: flex;
          flex-wrap: wrap;
          justify-content: center;
          margin: 5px;
          width: 30%;
        }
        .custom-rule-select-regexp-item{

        }
        button.custom-rule-run-match-button{
          margin-top: 5px;
        }
        textarea.custom-rule-match-text{
          width: 100%;
          min-height: 70px;
          outline: none;
          margin: 0px;
          background-image: none;
          background-color: transparent;
          display: inline-block;
          resize: vertical;
          padding: 5px;
          line-height: 1.5;
          box-sizing: border-box;
          border: 1px solid rgb(220, 223, 230);
          appearance: none;
        }
        .custom-rule-match-log{

        }
        .custom-rule-match-log-container{
          padding: 5px;
          background: rgb(229, 229, 229);
        }
        .custom-rule-match-log-container p{
          margin: 2px 0px;
          border-bottom: 1px solid #000000;
        }
        .custom-rule-match-log-container p:last-child{
          border-bottom: 0px;
          margin-bottom: 0px;
        }
        .custom-rule-match-log-container p[data-tag]{
          
        }
        .custom-rule-match-log-container p[data-tag="info"]{

        }
        .custom-rule-match-log-container p[data-tag="success"]{
          color: green;
        }
        .custom-rule-match-log-container p[data-tag="warn"]{
          color: yellow;
        }
        .custom-rule-match-log-container p[data-tag="error"]{
          color: red;
        }
        `,
				},
				NetDiskUI.popsStyle.customRuleDebugView
			);
			/** @type {HTMLSelectElement} */
			let $select = dialog.$shadowRoot.querySelector(
				".custom-rule-select-regexp"
			);
			/** @type {HTMLTextAreaElement} */
			let $matchText = dialog.$shadowRoot.querySelector(
				".custom-rule-match-text"
			);
			/** @type {HTMLDivElement} */
			let $log = dialog.$shadowRoot.querySelector(
				".custom-rule-match-log-container"
			);
			/** @type {HTMLButtonElement} */
			let $button = dialog.$shadowRoot.querySelector(
				".custom-rule-run-match-button"
			);
			regexp.forEach((regExpItem, index) => {
				$select.appendChild(
					DOMUtils.createElement("option", {
						className: "custom-rule-select-regexp-item",
						innerText: "regexp下标:" + index,
						"data-value": regExpItem,
					})
				);
			});
			/**
			 * 设置日志输出
			 * @param {"info"|"error"|"success"|"warn"} tag 日志等级
			 * @param {...any[]} args
			 */
			function setLog(tag, ...args) {
				let text = "";
				args.forEach((item) => {
					if (text !== "") {
						text += "\n";
					}
					if (typeof item !== "string") {
						text += JSON.stringify(item, void 0, 4);
					} else {
						text += item;
					}
				});
				let logElement = DOMUtils.createElement(
					"p",
					{
						innerText: text,
					},
					{
						"data-tag": tag,
					}
				);
				DOMUtils.append($log, logElement);
			}
			/**
			 * 清空日志
			 */
			function clearLog() {
				$log.innerHTML = "";
			}
			/**
			 * 日志回调
			 * @param {NetDiskDebugLogData} logData
			 */
			function logCallBack(logData) {
				if (Array.isArray(logData.msg)) {
					setLog(logData.status ? "info" : "error", ...logData.msg);
				} else {
					setLog(logData.status ? "info" : "error", logData.msg);
				}
				if (!logData.status) {
					setLog("error", "执行完毕");
				}
			}
			function debugRunClickEvent() {
				if (utils.isNull($matchText.value)) {
					Qmsg.error("请先输入待匹配的字符串");
					return;
				}
				/* 清空日志 */
				clearLog();
				let netDiskName = ruleJSON.key;
				let netDiskIndex = $select.selectedIndex;
				let selectRegExp = $select.selectedOptions[netDiskIndex]["data-value"];
				log.info(["当前选中的规则: ", selectRegExp]);
				let testCustomRule = {};
				testCustomRule[ruleJSON.key] = [selectRegExp];
				/** @type {string[]} */
				let matchTextList = [];
				NetDiskWorker.handleRegularMatch(
					{
						regular: testCustomRule,
						textList: [$matchText.value],
						matchTextRange: "all",
					},
					(matchData) => {
						matchTextList.push(...matchData.data);
					}
				);
				if (!matchTextList.length) {
					setLog("error", "未成功匹配到数据");
					return;
				}
				matchTextList = NetDiskWorker.uniqueArr(matchTextList);
				setLog("info", "成功匹配到的数据 ==> ", matchTextList);
				matchTextList.forEach((matchText, index) => {
					setLog("success", "当前处理的字符串: " + matchText);
					setLog("success", "当前执行: 对shareCode进行处理获取");
					let shareCode = NetDiskDebug.handleShareCode(
						matchText,
						selectRegExp,
						logCallBack
					);
					if (utils.isNull(shareCode)) {
						return;
					}
					setLog("info", " ");
					setLog("info", `================分割线================`);
					setLog("info", " ");
					setLog("success", "当前执行: 对accessCode进行处理获取");
					let accessCode = NetDiskDebug.handleAccessCode(
						matchText,
						selectRegExp,
						logCallBack
					);
					setLog("info", " ");
					setLog("info", `================分割线================`);
					setLog("info", " ");
					setLog("success", "当前执行: 对uiLinkShow进行处理获取");
					let uiLinkShow = NetDiskDebug.handleLinkShow(
						matchText,
						selectRegExp,
						shareCode,
						accessCode,
						logCallBack
					);
					setLog("info", " ");
					setLog("info", `================分割线================`);
					setLog("info", " ");
					setLog("success", "当前执行: 对blank进行处理获取");
					let blankUrl = NetDiskDebug.handleBlank(
						matchText,
						selectRegExp,
						shareCode,
						accessCode,
						logCallBack
					);
					setLog("info", " ");
					setLog("info", `================分割线================`);
					setLog("info", " ");
					setLog("success", "当前执行: 对copyUrl进行处理获取");
					let copyUrl = NetDiskDebug.handleCopyUrl(
						matchText,
						selectRegExp,
						shareCode,
						accessCode,
						logCallBack
					);
					setLog("success", "执行完毕");
				});
			}
			DOMUtils.on($button, "click", void 0, debugRunClickEvent);
		},
		/**
		 * 上下文环境
		 * @param {NetDiskUserCustomRule} rule
		 */
		getBindContext(rule) {
			function setValue(key, value) {
				let localData = GM_getValue(NetDiskCustomRules.dataKey);
				let ruleData = localData[rule.key];
				ruleData[key] = value;
				GM_setValue(NetDiskCustomRules.dataKey, localData);
			}
			function getValue(key, defaultValue) {
				let localData = GM_getValue(NetDiskCustomRules.dataKey);
				let ruleData = localData[rule.key];
				return ruleData[key] ?? defaultValue;
			}
			function deleteValue(key) {
				let localData = GM_getValue(NetDiskCustomRules.dataKey);
				let ruleData = localData[rule.key];
				Reflect.deleteProperty(ruleData, key);
				GM_setValue(NetDiskCustomRules.dataKey, localData);
			}
			return {
				rule: rule,
				NetDiskRequire: NetDiskRequire,
				CryptoJS: Cryptojs,
				httpx: httpx,
				utils: utils,
				DOMUtils: DOMUtils,
				window: window,
				unsafeWindow: unsafeWindow,
				NetDiskCheckLinkValidity: NetDiskCheckLinkValidity,
				log: log,
				Qmsg: Qmsg,
				pops: pops,
				setValue: setValue,
				getValue: getValue,
				deleteValue: deleteValue,
			};
		},
		/**
		 * 把用户自定义规则进行转换成脚本规则
		 * @param {NetDiskUserCustomRule[]} localRule
		 * @returns {NetDiskRegular}
		 */
		parseRule(localRule) {
			/**
			 *
			 * @param {NetDiskUserCustomRuleRegexp} ruleRegExp
			 */
			function parseRegExp(ruleRegExp) {
				if (typeof ruleRegExp["shareCode"] === "string") {
					ruleRegExp["shareCode"] = new RegExp(ruleRegExp["shareCode"], "ig");
				}
				if (typeof ruleRegExp["shareCodeNeedRemoveStr"] === "string") {
					ruleRegExp["shareCodeNeedRemoveStr"] = new RegExp(
						ruleRegExp["shareCodeNeedRemoveStr"],
						"ig"
					);
				}
				if (typeof ruleRegExp["shareCodeNotMatch"] === "string") {
					ruleRegExp["shareCodeNotMatch"] = new RegExp(
						ruleRegExp["shareCodeNotMatch"],
						"ig"
					);
				}
				if (typeof ruleRegExp["checkAccessCode"] === "string") {
					ruleRegExp["checkAccessCode"] = new RegExp(
						ruleRegExp["checkAccessCode"],
						"ig"
					);
				}
				if (typeof ruleRegExp["accessCode"] === "string") {
					ruleRegExp["accessCode"] = new RegExp(ruleRegExp["accessCode"], "ig");
				}
				if (typeof ruleRegExp["acceesCodeNotMatch"] === "string") {
					ruleRegExp["acceesCodeNotMatch"] = new RegExp(
						ruleRegExp["acceesCodeNotMatch"],
						"ig"
					);
				}
				if (typeof ruleRegExp["paramMatch"] === "string") {
					ruleRegExp["paramMatch"] = new RegExp(ruleRegExp["paramMatch"], "i");
				}
				return ruleRegExp;
			}
			let userRule = {};
			for (const userRuleItem of localRule) {
				let userRegExp = userRuleItem.regexp;
				if (userRuleItem.setting) {
					/** 设置 @type {NetDiskSettingMenuDetails} */
					let viewDetails = {
						type: userRuleItem.setting.name,
						key: userRuleItem.key,
						isUserRule: true,
					};
					let userRegExpOther = {};
					/* 是否启用,设置默认值 */
					this.initDefaultValue(
						`${userRuleItem.key}-enable`,
						Boolean(userRuleItem.setting["enable"])
					);

					viewDetails["enable"] = GM_getValue(`${userRuleItem.key}-enable`);

					userRegExpOther["enable"] = GM_getValue(`${userRuleItem.key}-enable`);

					if (typeof userRuleItem.setting["isBlank"] === "boolean") {
						/* 新标签页打开 */
						viewDetails["isBlank"] = true;
						this.initDefaultValue(
							`${userRuleItem.key}-open-enable`,
							Boolean(userRuleItem.setting["isBlank"])
						);
					}
					if (
						typeof userRuleItem.setting["openBlankWithCopyAccessCode"] ===
						"boolean"
					) {
						/* 跳转时复制访问码 */
						viewDetails["openBlankWithCopyAccessCode"] = true;
						this.initDefaultValue(
							`${userRuleItem.key}-open-blank-with-copy-accesscode`,
							Boolean(userRuleItem.setting["openBlankWithCopyAccessCode"])
						);
					}
					if (typeof userRuleItem.setting["isForward"] === "boolean") {
						/* 直接进行scheme转发链接 */
						viewDetails["isForward"] = true;
						this.initDefaultValue(
							`${userRuleItem.key}-forward-scheme-enable`,
							Boolean(userRuleItem.setting["isForward"])
						);
					}
					if (typeof userRuleItem.setting["schemeUri"] === "boolean") {
						/* scheme转发的字符串格式 */
						viewDetails["schemeUri"] = true;
						this.initDefaultValue(`${userRuleItem.key}-static-scheme-uri`, "");
					}
					if (typeof userRuleItem.setting["checkLinkValidity"] === "boolean") {
						/* 用于验证链接有效性 */
						viewDetails["checkLinkValidity"] = true;
						this.initDefaultValue(
							`${userRuleItem.key}-check-link-valid`,
							Boolean(userRuleItem.setting["checkLinkValidity"])
						);
						userRegExpOther["checkLinkValidity"] = GM_getValue(
							`${userRuleItem.key}-check-link-valid`
						);
					}
					if (
						typeof userRuleItem.setting["innerTextAccessCodeBeforeMaxRange"] ===
						"number"
					) {
						/* text-提取码间隔前的字符长度 */
						viewDetails["innerTextAccessCodeBeforeMaxRange"] =
							userRuleItem.setting["innerTextAccessCodeBeforeMaxRange"];
						this.initDefaultValue(
							`${userRuleItem.key}_innerText_accessCode_before_max_range`,
							viewDetails["innerTextAccessCodeBeforeMaxRange"]
						);
						userRegExpOther["innerTextAccessCodeBeforeMaxRange"] =
							NetDiskLocalData.innerTextAccessCodeBeforeMaxRange(
								userRuleItem.key
							);
					}
					if (
						typeof userRuleItem.setting["innerTextAccessCodeAfterMaxRange"] ===
						"number"
					) {
						/* text-提取码间隔后的字符长度 */
						viewDetails["innerTextAccessCodeAfterMaxRange"] =
							userRuleItem.setting["innerTextAccessCodeAfterMaxRange"];
						this.initDefaultValue(
							`${userRuleItem.key}_innerText_accessCode_after_max_range`,
							viewDetails["innerTextAccessCodeAfterMaxRange"]
						);
						userRegExpOther["innerTextAccessCodeAfterMaxRange"] =
							NetDiskLocalData.innerTextAccessCodeAfterMaxRange(
								userRuleItem.key
							);
					}
					if (
						typeof userRuleItem.setting["innerHTMLAccessCodeBeforeMaxRange"] ===
						"number"
					) {
						/* html-提取码间隔前的字符长度 */
						viewDetails["innerHTMLAccessCodeBeforeMaxRange"] =
							userRuleItem.setting["innerHTMLAccessCodeBeforeMaxRange"];
						this.initDefaultValue(
							`${userRuleItem.key}_innerHTML_accessCode_before_max_range`,
							viewDetails["innerHTMLAccessCodeBeforeMaxRange"]
						);
						userRegExpOther["innerHTMLAccessCodeBeforeMaxRange"] =
							NetDiskLocalData.innerHTMLAccessCodeBeforeMaxRange(
								userRuleItem.key
							);
					}
					if (
						typeof userRuleItem.setting["innerHTMLAccessCodeAfterMaxRange"] ===
						"number"
					) {
						/* html-提取码间隔后的字符长度 */
						viewDetails["innerHTMLAccessCodeAfterMaxRange"] =
							userRuleItem.setting["innerHTMLAccessCodeAfterMaxRange"];
						this.initDefaultValue(
							`${userRuleItem.key}_innerHTML_accessCode_after_max_range`,
							viewDetails["innerHTMLAccessCodeAfterMaxRange"]
						);
						userRegExpOther["innerHTMLAccessCodeAfterMaxRange"] =
							NetDiskLocalData.innerHTMLAccessCodeAfterMaxRange(
								userRuleItem.key
							);
					}
					/**
					 *
					 * @param {NetDiskRegularOption} userRegexp
					 */
					function handleRegExp(userRegexp) {
						if ("enable" in userRegExpOther) {
							userRegexp["enable"] = userRegExpOther["enable"];
						}
						if ("checkLinkValidity" in userRegExpOther) {
							userRegexp["checkLinkValidity"] =
								userRegExpOther["checkLinkValidity"];
						}
						if ("innerTextAccessCodeBeforeMaxRange" in userRegExpOther) {
							userRegexp["link_innerText"] = NetDisk.replaceParam(
								userRuleItem.key,
								{
									innerTextAccessCodeBeforeMaxRange:
										userRegExpOther["innerTextAccessCodeBeforeMaxRange"],
								}
							);
						}
						if ("innerTextAccessCodeAfterMaxRange" in userRegExpOther) {
							userRegexp["link_innerText"] = NetDisk.replaceParam(
								userRuleItem.key,
								{
									innerTextAccessCodeAfterMaxRange:
										userRegExpOther["innerTextAccessCodeAfterMaxRange"],
								}
							);
						}
						if ("innerHTMLAccessCodeBeforeMaxRange" in userRegExpOther) {
							userRegexp["link_innerHTML"] = NetDisk.replaceParam(
								userRuleItem.key,
								{
									innerHTMLAccessCodeBeforeMaxRange:
										userRegExpOther["innerHTMLAccessCodeBeforeMaxRange"],
								}
							);
						}
						if ("innerHTMLAccessCodeAfterMaxRange" in userRegExpOther) {
							userRegexp["link_innerHTML"] = NetDisk.replaceParam(
								userRuleItem.key,
								{
									innerHTMLAccessCodeAfterMaxRange:
										userRegExpOther["innerHTMLAccessCodeAfterMaxRange"],
								}
							);
						}
						return userRegexp;
					}
					if (Array.isArray(userRegExp)) {
						userRegExp = userRegExp.map((userRegexpItem) =>
							handleRegExp(userRegexpItem)
						);
					} else {
						handleRegExp(userRegExp);
					}
					if (this.$data.settingViewDetails.has(userRuleItem.key)) {
						this.$data.settingViewDetails.delete(userRuleItem.key);
					}
					this.$data.settingViewDetails.set(userRuleItem.key, viewDetails);
				}
				if (typeof userRuleItem["icon"] === "string") {
					if (userRuleItem["icon"] in NetDiskUI.src.icon) {
						/* 判断icon的值是否是图标字典中的键,是的话让该规则配置它的图标 */
						NetDiskUI.src.icon[userRuleItem["key"]] =
							NetDiskUI.src.icon[userRuleItem["icon"]];
					} else {
						NetDiskUI.src.icon[userRuleItem["key"]] = userRuleItem["icon"];
					}
				}
				if (Array.isArray(userRegExp)) {
					userRegExp = userRegExp.map((userRegexpItem) => {
						return parseRegExp(userRegexpItem);
					});
				} else {
					parseRegExp(userRegExp);
				}
				if (userRule[userRuleItem.key]) {
					/* 已存在相同key规则,追加新的 */
					userRule[userRuleItem.key].push(userRegExp);
				} else {
					if (Array.isArray(userRegExp)) {
						userRule[userRuleItem.key] = userRegExp;
					} else {
						userRule[userRuleItem.key] = [userRegExp];
					}
				}
				const AsyncFunction = Object.getPrototypeOf(
					async function () {}
				).constructor;
				if (typeof userRuleItem.checkLinkValidityFunction === "string") {
					try {
						if (NetDiskCheckLinkValidity.netDisk[userRuleItem.key] == null) {
							NetDiskCheckLinkValidity.netDisk[userRuleItem.key] = {};
						}
						NetDiskCheckLinkValidity.netDisk[userRuleItem.key].init =
							new AsyncFunction(
								"netDiskIndex",
								"shareCode",
								"accessCode",
								userRuleItem.checkLinkValidityFunction
							).bind(this.getBindContext(userRuleItem));
					} catch (error) {
						log.error(error);
					}
				}
				if (typeof userRuleItem.AuthorizationFunction === "string") {
					try {
						NetDiskAuthorization.netDisk[userRuleItem.key] = new AsyncFunction(
							userRuleItem.AuthorizationFunction
						).bind(this.getBindContext(userRuleItem));
					} catch (error) {
						log.error(error);
					}
				}
				if (typeof userRuleItem.AutoFillAccessCodeFunction === "string") {
					try {
						NetDiskAutoFillAccessCode.netDisk[userRuleItem.key] =
							new AsyncFunction(
								"netDiskInfo",
								userRuleItem.AutoFillAccessCodeFunction
							).bind(this.getBindContext(userRuleItem));
					} catch (error) {
						log.error(error);
					}
				}
				if (typeof userRuleItem.parseFunction === "string") {
					try {
						NetDiskParse.netDisk[userRuleItem.key] = new Function(
							userRuleItem.parseFunction
						).bind(this.getBindContext(userRuleItem));
					} catch (error) {
						log.error(error);
					}
				}
			}
			return userRule;
		},
		/**
		 * 获取设置菜单配置
		 */
		getSettingViewDetails() {
			let viewDetailsList = [];
			this.$data.settingViewDetails.forEach((value) => {
				viewDetailsList.push(value);
			});
			return viewDetailsList;
		},
		/**
		 * 初始化默认值
		 */
		initDefaultValue(key, value) {
			if (GM_getValue(key) == null) {
				GM_setValue(key, value);
			}
		},
		/**
		 * 获取模板规则
		 * @returns
		 */
		getTemplateRule() {
			/**
			 * @type {NetDiskUserCustomRule}
			 */
			let templateRule = {
				key: "规则名",
				icon: "图标链接或base64图片",
				regexp: [
					{
						link_innerText: "",
						link_innerHTML: "",
						shareCode: "",
						shareCodeNeedRemoveStr: "",
						uiLinkShow: "",
						blank: "",
						copyUrl: "",
					},
				],
				setting: {
					name: "名字",
					enable: true,
					isBlank: true,
					openBlankWithCopyAccessCode: true,
				},
			};
			return this.getFormatRule(templateRule);
		},
		/**
		 * 添加规则
		 * @param {NetDiskUserCustomRule} userRule
		 */
		addRule(userRule) {
			let localRule = this.getRule();
			localRule.push(userRule);
			GM_setValue(NetDiskCustomRules.key, localRule);
		},
		/**
		 * 设置规则到本地
		 * @param {string} oldRuleKey 旧规则的键名
		 * @param {NetDiskUserCustomRule[]|NetDiskUserCustomRule} userRule
		 */
		setRule(oldRuleKey, userRule) {
			if (Array.isArray(userRule)) {
				GM_setValue(NetDiskCustomRules.key, userRule);
			} else {
				let localRule = this.getRule();
				let findRuleIndex = localRule.findIndex(
					(item) => item.key === oldRuleKey
				);
				if (findRuleIndex !== -1) {
					localRule[findRuleIndex] = null;
					localRule[findRuleIndex] = userRule;
				} else {
					log.error(["覆盖规则失败", userRule]);
					Qmsg.error("覆盖规则失败");
					return false;
				}
				this.setRule(oldRuleKey, localRule);
			}
		},
		/**
		 * 删除单条规则
		 * @param {string} ruleKey 规则的key名
		 */
		deleteRule(ruleKey) {
			let localRule = this.getRule();
			let findIndex = localRule.findIndex((rule) => rule.key === ruleKey);
			if (findIndex !== -1) {
				localRule.splice(findIndex, 1);
				this.setRule(ruleKey, localRule);
				return true;
			} else {
				return false;
			}
		},
		/**
		 * 清空规则
		 */
		clearRule() {
			GM_deleteValue(NetDiskCustomRules.key);
		},
		/**
		 * 获取规则
		 * @param {?string} key
		 * @returns {(NetDiskUserCustomRule|NetDiskUserCustomRule)[]}
		 */
		getRule(key) {
			if (typeof key === "string") {
				return GM_getValue(NetDiskCustomRules.key, []).find(
					(item) => item.key === key
				);
			}
			return GM_getValue(NetDiskCustomRules.key, []);
		},
		/**
		 * 获取格式化后的规则
		 * @param {?string} rule
		 */
		getFormatRule(rule) {
			return JSON.stringify(rule || this.getRule(), void 0, 4);
		},
	};

	/** 弹窗UI界面 */
	const NetDiskUI = {
		/** 元素对象实例 */
		Alias: {
			/**
			 * 链接弹窗的对象
			 * @type {PopsCallResult}
			 */
			uiLinkAlias: void 0,
			/**
			 * 历史匹配记录弹窗的对象
			 * @type {PopsCallResult}
			 */
			historyAlias: void 0,
			/**
			 * 设置弹窗的对象
			 */
			settingAlias: void 0,
		},
		/**
		 * 已匹配到的网盘图标字典
		 * @type {Set<string>}
		 */
		isMatchedNetDiskIconMap: new Set(),
		/**
		 * 高度和宽度大小
		 */
		size: parseInt(GM_getValue("size", 50)),
		/**
		 * 按钮透明度
		 */
		opacity: parseFloat(GM_getValue("opacity", 1)),
		/**
		 * 是否正在循环切换按钮背景
		 */
		isSwitchRandomBackground: false,
		/**
		 * 是否默认弹窗可以拖拽
		 */
		defaultPCDrag: false,
		/**
		 * 是否默认弹窗拖拽距离
		 */
		defaultPCDragLimit: true,
		/**
		 * 是否默认开启亚克力效果
		 */
		defaultPopsAcrylic: false,
		/**
		 * 点击弹窗遮罩层是否可以关闭弹窗
		 */
		defaultClickMaskToCloseDialog: false,
		/**
		 * 是否默认禁用弹窗弹出后背景可以滚动
		 */
		defaultForbiddenScroll: false,
		/**
		 * 默认弹窗动画
		 */
		defaultAnimation: "pops-anim-fadein-zoom",
		/**
		 * folder默认排序的属性名
		 */
		defaultSortName: "fileName",
		/**
		 * folder是否降序排序
		 */
		defaultSortDesc: false,
		/**
		 * 弹窗的配置
		 * 规定格式
		 * {
		 *  PC:{
		 *    width: "",
		 *    height: "",
		 *  },
		 *  Mobile: {
		 *    width: "",
		 *    height: "",
		 *  }
		 * }
		 */
		popsStyle: {
			/**
			 * 天翼云需要登录的提示
			 */
			tianYiYunLoginTip: {
				PC: {
					width: "30vw",
					height: "280px",
				},
				Mobile: {
					width: "80vw",
					height: "250px",
				},
			},
			/**
			 * 坚果云需要登录的提示
			 */
			jianGuoYunLoginTip: {
				PC: {
					width: "350px",
					height: "200px",
				},
				Mobile: {
					width: "350px",
					height: "200px",
				},
			},
			/**
			 * 设置
			 */
			settingView: {
				PC: {
					width: "800px",
					height: "600px",
				},
				Mobile: {
					width: "92vw",
					height: "80vh",
				},
			},
			/**
			 * 设置默认值的界面
			 */
			setDefaultValueView: {
				PC: {
					width: "350px",
					height: "200px",
				},
				Mobile: {
					width: "350px",
					height: "200px",
				},
			},
			/**
			 * (主)网盘链接界面
			 */
			mainView: {
				PC: {
					width: "500px",
					height: "100%",
				},
				Mobile: {
					width: "88vw",
					height: "50vh",
				},
			},
			/**
			 * (主)网盘链接界面-小窗
			 */
			mainViewSmallWindow: {
				PC: {
					width:
						GM_getValue(
							"netdisk-ui-small-window-width",
							NetDiskData.defaultSmallWindowWidth
						) + "px",
					height: "auto",
				},
				Mobile: {
					width:
						GM_getValue(
							"netdisk-ui-small-window-width",
							NetDiskData.defaultSmallWindowWidth
						) + "px",
					height: "auto",
				},
			},
			/**
			 * 单文件直链弹窗
			 */
			oneFileStaticView: {
				PC: {
					width: "550px",
					height: "350px",
				},
				Mobile: {
					width: "88vw",
					height: "300px",
				},
			},
			/**
			 * 多文件直链弹窗
			 */
			moreFileStaticView: {
				PC: {
					width: "700px",
					height: "600px",
				},
				Mobile: {
					width: "88vw",
					height: "500px",
				},
			},
			/**
			 * 新密码、错误密码输入弹窗
			 */
			inputNewAccessCodeView: {
				PC: {
					width: "400px",
					height: "200px",
				},
				Mobile: {
					width: "88vw",
					height: "160px",
				},
			},
			/**
			 * 历史存储记录弹窗
			 */
			historyMatchView: {
				PC: {
					width: "50vw",
					height: "65vh",
				},
				Mobile: {
					width: "88vw",
					height: "60vh",
				},
			},
			/**
			 * 自定义规则的弹窗
			 */
			customRulesView: {
				PC: {
					width: "50vw",
					height: "65vh",
				},
				Mobile: {
					width: "88vw",
					height: "60vh",
				},
			},
			/**
			 * 自定义规则的调试视图
			 */
			customRuleDebugView: {
				PC: {
					width: "55vw",
					height: "70vh",
				},
				Mobile: {
					width: "88vw",
					height: "70vh",
				},
			},
			/**
			 * 主动识别的弹窗
			 */
			matchPasteTextView: {
				PC: {
					width: "50vw",
					height: "65vh",
				},
				Mobile: {
					width: "88vw",
					height: "60vh",
				},
			},
			/**
			 * 访问码规则弹窗
			 */
			accessCodeRuleView: {
				PC: {
					width: "50vw",
					height: "65vh",
				},
				Mobile: {
					width: "88vw",
					height: "60vh",
				},
			},
			/**
			 * 访问码规则添加/修改/删除
			 */
			accessCodeRuleEditView: {
				PC: {
					width: "44vw",
					height: "50vh",
				},
				Mobile: {
					width: "70vw",
					height: "45vh",
				},
			},
		},
		src: {
			/**
			 * 图标RESOURCE_ICON
			 * 从图标库中引入并覆盖
			 */
			icon: {},
		},
		/**
		 * 初始化Qmsg的配置
		 */
		initQmsg() {
			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),
			});
		},
		/**
		 * 悬浮按钮  双击打开主界面,长按打开设置(不能移动,移动就不打开,只是移动按钮
		 */
		suspension: {
			/** @type {HTMLDivElement} */
			suspensionNode: null,
			/** 是否已显示 */
			isShow: false,
			/** 是否已设置事件 */
			isSetEvent: false,
			/** 是否正在切换背景 */
			isRandBg: false,
			/**
			 * 显示悬浮按钮
			 */
			show() {
				if (!this.isShow) {
					this.isShow = true;
					this.createUI();
					this.setSuspensionPosition();
				}
				if (!this.isSetEvent) {
					this.isSetEvent = true;
					this.setSuspensionEvent();
					this.setResizeEventListener();
				}
				this.backgroundSwitch();
				this.showSuspension();
			},
			showSuspension() {
				this.suspensionNode.style.display = "";
			},
			hideSuspension() {
				this.suspensionNode.style.display = "none";
			},
			/**
			 * 判断当前是否是顶部窗口
			 * @returns {boolean}
			 */
			isTopWindow() {
				return unsafeWindow.self.window === unsafeWindow.top.window;
			},
			/**
			 * 创建UI界面
			 */
			createUI() {
				if (NetDiskUI.size < 15) {
					/* 大小不能小于 15px */
					GM_setValue("size", 15);
					NetDiskUI.size = 15;
				}
				if (NetDiskUI.size > 250) {
					/* 大小不能大于 250px */
					GM_setValue("size", 250);
					NetDiskUI.size = 250;
				}
				if (NetDiskUI.opacity < 0.1) {
					/* 透明度不能小于 0.1 */
					GM_setValue("opacity", 0.1);
					NetDiskUI.opacity = 0.1;
				}
				if (NetDiskUI.opacity > 1.0) {
					/* 透明度不能大于 1.0 */
					GM_setValue("opacity", 1);
					NetDiskUI.opacity = 1;
				}
				let $shadowContainer = DOMUtils.createElement("div", {
					className: "whitesev-suspension-shadow-container",
				});
				let $shadowRoot = $shadowContainer.attachShadow({ mode: "open" });
				this.suspensionNode = DOMUtils.createElement(
					"div",
					{
						id: "whitesevSuspensionId",
						className: "whitesevSuspension",
						innerHTML: `
            <style type="text/css">

            ${this.getCSS()}

            </style>
            <div class="whitesevSuspensionMain">
              <div class="whitesevSuspensionFloor">
                <div class="netdisk"></div>
              </div>
            </div>
            `,
					},
					{
						style: `
            width: ${NetDiskUI.size}px;
            height: ${NetDiskUI.size}px;
            opacity: ${NetDiskUI.opacity}
          `,
					}
				);
				$shadowRoot.appendChild(this.suspensionNode);
				document.body.appendChild($shadowContainer);
			},
			/**
			 * 显示设置
			 */
			showSettingView() {
				if (NetDiskUI.Alias.settingAlias) {
					log.error("设置界面已存在");
					Qmsg.error("设置界面已存在");
					return;
				}
				const that = this;
				/**
				 *
				 * @param {string} text
				 * @param {string} key
				 * @param {boolean} defaultValue
				 * @param {(event:Event,enable:boolean)=>void} callback
				 * @param {string} description
				 * @returns
				 */
				function getSwtichDetail(
					text,
					key,
					defaultValue,
					callback,
					description
				) {
					defaultValue = Boolean(defaultValue);
					return {
						text: text,
						type: "switch",
						description: description,
						attributes: {
							"data-key": key,
							"data-default-value": defaultValue,
						},
						getValue() {
							return Boolean(GM_getValue(key, defaultValue));
						},
						callback(event, value) {
							GM_setValue(key, Boolean(value));
							if (typeof callback === "function") {
								callback(event, value);
							}
						},
					};
				}
				/**
				 *
				 * @param {string} text
				 * @param {string} description
				 * @param {string} key
				 * @param {number} defaultValue
				 * @param {number} min
				 * @param {number} max
				 * @param {?number} step
				 * @param {?(event: PointerEvent,value: number)=> void} callback
				 * @param {?(value: number)=> string|number} getToolTipContent
				 * @returns
				 */
				function getSliderDetail(
					text,
					description,
					key,
					defaultValue,
					min,
					max,
					step,
					callback,
					getToolTipContent
				) {
					return {
						text: text,
						type: "slider",
						description: description,
						attributes: {
							"data-key": key,
							"data-default-value": defaultValue,
						},
						getValue() {
							return GM_getValue(key, defaultValue);
						},
						callback(event, value) {
							GM_setValue(key, value);
							if (typeof callback === "function") {
								callback(event, value);
							}
						},
						getToolTipContent(value) {
							if (typeof getToolTipContent === "function") {
								return getToolTipContent(value);
							} else {
								return value;
							}
						},
						min: min,
						max: max,
						step: step,
					};
				}
				/**
				 *
				 * @param {string} text
				 * @param {string} description
				 * @param {string} key
				 * @param {any} defaultValue
				 * @param {{
				 * text:string,value:string
				 * }[]} data
				 * @param {(event:PointerEvent, isSelectedValue: any, isSelectedText:string)=>void} callback
				 */
				function getSelectDetail(
					text,
					description,
					key,
					defaultValue,
					data,
					callback
				) {
					return {
						text: text,
						type: "select",
						description: description,
						attributes: {
							"data-key": key,
							"data-default-value": defaultValue,
						},
						getValue() {
							return GM_getValue(key, defaultValue);
						},
						callback(event, isSelectedValue, isSelectedText) {
							GM_setValue(key, isSelectedValue);
							if (typeof callback === "function") {
								callback(event, isSelectedValue, isSelectedText);
							}
						},
						data: data,
					};
				}
				/**
				 * @type {PopsPanelContentConfig[]}
				 */
				let contentDetails = [
					{
						id: "netdisk-panel-config-all-setting",
						title: "总设置",
						isDefault: true,
						forms: [
							{
								type: "forms",
								text: "",
								forms: [
									{
										type: "deepMenu",
										text: "Toast",
										forms: [
											{
												type: "forms",
												text: "",
												className: "netdisk-panel-forms-toast",
												forms: [
													getSelectDetail(
														"位置",
														"Toast显示在九宫格的位置,默认: 中间",
														"qmsg-position",
														"top",
														[
															{
																value: "topleft",
																text: "左上角",
															},
															{
																value: "top",
																text: "顶部",
															},
															{
																value: "topright",
																text: "右上角",
															},
															{
																value: "left",
																text: "左边",
															},
															{
																value: "center",
																text: "中间",
															},
															{
																value: "right",
																text: "右边",
															},
															{
																value: "bottomleft",
																text: "左下角",
															},
															{
																value: "bottom",
																text: "底部",
															},
															{
																value: "bottomright",
																text: "右下角",
															},
														],
														NetDiskUI.initQmsg
													),
													getSelectDetail(
														"同时最多显示的数量",
														"默认: 3",
														"qmsg-maxnums",
														3,
														[
															{
																value: 1,
																text: "1",
															},
															{
																value: 2,
																text: "2",
															},
															{
																value: 3,
																text: "3",
															},
															{
																value: 4,
																text: "4",
															},
															{
																value: 5,
																text: "5",
															},
														],
														NetDiskUI.initQmsg
													),
													getSwtichDetail(
														"逆序弹出",
														"qmsg-showreverse",
														false,
														NetDiskUI.initQmsg,
														"默认是自上往下显示Toast,逆序则是自下往上显示Toast"
													),
												],
											},
										],
									},
									{
										type: "deepMenu",
										text: "弹窗",
										forms: [
											{
												className: "netdisk-panel-forms-pops",
												type: "forms",
												text: "",
												forms: [
													getSelectDetail(
														"动画",
														`显示/关闭的动画效果,默认: ${NetDiskUI.defaultAnimation}`,
														"popsAnimation",
														NetDiskUI.defaultAnimation,
														[
															{
																value: "",
																text: "无",
															},
															{
																value: "pops-anim-spread",
																text: "spread",
															},
															{
																value: "pops-anim-shake",
																text: "shake",
															},
															{
																value: "pops-anim-rolling-left",
																text: "rolling-left",
															},
															{
																value: "pops-anim-rolling-right",
																text: "rolling-right",
															},
															{
																value: "pops-anim-slide-top",
																text: "slide-top",
															},
															{
																value: "pops-anim-slide-bottom",
																text: "slide-bottom",
															},
															{
																value: "pops-anim-slide-left",
																text: "slide-left",
															},
															{
																value: "pops-anim-slide-right",
																text: "slide-right",
															},
															{
																value: "pops-anim-fadein",
																text: "fadein",
															},
															{
																value: "pops-anim-fadein-zoom",
																text: "fadein-zoom",
															},
															{
																value: "pops-anim-fadein-alert",
																text: "fadein-alert",
															},
															{
																value: "pops-anim-don",
																text: "don",
															},
															{
																value: "pops-anim-roll",
																text: "roll",
															},
															{
																value: "pops-anim-sandra",
																text: "sandra",
															},
															{
																value: "pops-anim-gather",
																text: "gather",
															},
														]
													),
													getSwtichDetail(
														"点击弹窗遮罩层关闭弹窗",
														"clickMaskToCloseDialog",
														NetDiskUI.defaultClickMaskToCloseDialog,
														void 0,
														"点击遮罩层触发关闭弹窗事件"
													),
													getSwtichDetail(
														"窗口拖拽",
														"pcDrag",
														NetDiskUI.defaultPCDrag,
														void 0,
														"长按标题栏可拖拽移动弹窗"
													),
													getSwtichDetail(
														"限制拖拽距离",
														"pcDragLimit",
														NetDiskUI.defaultPCDragLimit,
														void 0,
														"只能在浏览器的可视窗口内拖动"
													),
													getSwtichDetail(
														"亚克力效果",
														"popsAcrylic",
														NetDiskUI.defaultPopsAcrylic,
														void 0,
														""
													),
												],
											},
										],
									},
									{
										type: "deepMenu",
										text: "文件弹窗",
										forms: [
											{
												type: "forms",
												text: "",
												className: "netdisk-panel-forms-pops-folder",
												forms: [
													getSelectDetail(
														"排序名",
														"当前的规则",
														"pops-folder-sort-name",
														NetDiskUI.defaultSortName,
														[
															{
																value: "fileName",
																text: "文件名",
															},
															{
																value: "latestTime",
																text: "修改时间",
															},
															{
																value: "fileSize",
																text: "大小",
															},
														]
													),
													getSelectDetail(
														"排序规则",
														"当前的规则",
														"pops-folder-sort-is-desc",
														NetDiskUI.defaultSortDesc,
														[
															{
																value: false,
																text: "升序",
															},
															{
																value: true,
																text: "降序",
															},
														]
													),
												],
											},
										],
									},
									{
										type: "deepMenu",
										text: "小图标导航",
										forms: [
											{
												type: "forms",
												text: "",
												forms: [
													getSwtichDetail(
														"点击定位分享码",
														"pops-netdisk-icon-click-event-find-sharecode",
														true,
														NetDiskData.iconDefaultClickEventToFindShareCode,
														"自动滚动页面至包含分享码的元素"
													),
													getSwtichDetail(
														"选中分享码",
														"pops-netdisk-icon-click-event-find-sharecode-with-select",
														true,
														NetDiskData.iconDefaultClickEventToFindShareCodeWithSelect,
														"使用光标选中分享码/元素"
													),
													getSwtichDetail(
														"循环定位",
														"pops-netdisk-icon-click-event-loop-find-sharecode",
														true,
														NetDiskData.iconDefaultClickEventToFindShareCodeByLoop,
														"关闭则是每一个元素只定位一次"
													),
												],
											},
										],
									},
									{
										type: "deepMenu",
										text: "悬浮按钮",
										forms: [
											{
												type: "forms",
												text: "",
												forms: [
													getSliderDetail(
														"大小",
														"悬浮按钮的大小,默认: 50",
														"size",
														50,
														15,
														250,
														void 0,
														(event, value) => {
															NetDiskUI.size = parseInt(value);
															if (NetDiskUI.suspension.isShow) {
																DOMUtils.css(
																	NetDiskUI.suspension.suspensionNode,
																	{
																		width: NetDiskUI.size,
																		height: NetDiskUI.size,
																	}
																);
																NetDiskUI.suspension.setSuspensionPosition();
															}
														},
														(value) => {
															return `${value}px`;
														}
													),
													getSliderDetail(
														"透明度",
														"值越小越透明,默认: 1",
														"opacity",
														1,
														0.1,
														1,
														0.1,
														(event, value) => {
															NetDiskUI.opacity = parseFloat(value);
															if (NetDiskUI.suspension.isShow) {
																DOMUtils.css(
																	NetDiskUI.suspension.suspensionNode,
																	{
																		opacity: NetDiskUI.opacity,
																	}
																);
															}
														}
													),
													getSliderDetail(
														"背景轮播时间",
														"淡入/淡出的时间,默认: 1500",
														"randbg-time",
														1500,
														0,
														10000,
														100,
														void 0,
														(value) => {
															return `${value}ms`;
														}
													),
													getSliderDetail(
														"背景显示时间",
														"图标显示的持续时间,默认: 1200",
														"randbg-show-time",
														1200,
														0,
														10000,
														100,
														void 0,
														(value) => {
															return `${value}ms`;
														}
													),
													getSwtichDetail(
														"吸附边缘",
														"suspended-button-adsorption-edge",
														false,
														void 0,
														"移动悬浮按钮松开后自动吸附边缘"
													),
												],
											},
										],
									},
									{
										type: "deepMenu",
										text: "小窗模式",
										forms: [
											{
												type: "forms",
												text: "",
												className: "netdisk-panel-forms-small-window",
												forms: [
													getSliderDetail(
														"宽度",
														"设置小窗宽度(px),默认: 250",
														"netdisk-ui-small-window-width",
														NetDiskData.defaultSmallWindowWidth,
														NetDiskData.smallWindowMinWidth,
														NetDiskData.smallWindowMaxWidth,
														1,
														void 0,
														(value) => {
															return `${value}px`;
														}
													),
													getSliderDetail(
														"高度",
														"设置小窗最大高度(px),默认: 200",
														"netdisk-ui-small-window-max-height",
														NetDiskData.defaultSmallWindowMaxHeight,
														NetDiskData.smallWindowMinMaxHeight,
														NetDiskData.smallWindowMaxMaxHeight,
														1,
														void 0,
														(value) => {
															return `${value}px`;
														}
													),
												],
											},
										],
									},
									{
										type: "deepMenu",
										text: "历史匹配记录",
										forms: [
											{
												type: "forms",
												text: "",
												className: "netdisk-panel-history-match",
												forms: [
													getSelectDetail(
														"排序规则",
														"",
														"netdisk-history-match-ordering-rule",
														"按 更新时间 - 降序",
														[
															{
																value: "按 记录时间 - 升序",
																text: "按 记录时间 - 升序",
															},
															{
																value: "按 记录时间 - 降序",
																text: "按 记录时间 - 降序",
															},
															{
																value: "按 更新时间 - 升序",
																text: "按 更新时间 - 升序",
															},
															{
																value: "按 更新时间 - 降序",
																text: "按 更新时间 - 降序",
															},
														]
													),
													{
														text: "修复存储记录",
														type: "button",
														description:
															"如果【匹配记录】弹窗打不开,可能是存储的数据缺失某些字段,可尝试点击此处进行修复",
														buttonIconIsLoading: false,
														buttonType: "primary",
														buttonText() {
															return "修复";
														},
														callback(event) {
															try {
																const { count, repairCount } =
																	NetDiskUI.netDiskHistoryMatch.checkAndRepairLocalData();
																if (repairCount === 0) {
																	Qmsg.info(`不存在需要修复的数据`);
																} else {
																	Qmsg.success(
																		`共计: ${count} 条,修复${repairCount}条`
																	);
																}
															} catch (error) {
																Qmsg.error("修复异常:" + error.toString());
															}
														},
													},
													getSwtichDetail(
														"保存匹配记录",
														"saveMatchNetDisk",
														false,
														void 0,
														"将匹配到的链接信息进行本地存储,可点击【油猴菜单-⚙ 历史匹配记录】进行查看"
													),
												],
											},
										],
									},
									{
										type: "deepMenu",
										text: "匹配设置",
										forms: [
											{
												type: "forms",
												text: "文本匹配范围",
												forms: [
													getSelectDetail(
														"匹配类型",
														"匹配的文本类型",
														"pageMatchRange",
														"all",
														[
															{
																value: "all",
																text: "全部",
															},
															{
																value: "innerText",
																text: "普通文本",
															},
															{
																value: "innerHTML",
																text: "超文本",
															},
														]
													),
													getSwtichDetail(
														"匹配剪贴板",
														"readClipboard",
														false,
														void 0,
														"Api兼容性查看:<a href='https://caniuse.com/mdn-api_permissions_permission_clipboard-read' target='_blank'>读取剪贴板权限申请</a>、<a href='https://caniuse.com/mdn-api_clipboard_readtext' target='_blank'>直接读取剪贴板</a>"
													),
													getSwtichDetail(
														"匹配当前URL",
														"allowMatchLocationHref",
														false,
														void 0,
														"匹配window.location.href"
													),
												],
											},
											{
												type: "forms",
												text: "观察器",
												forms: [
													getSliderDetail(
														"匹配间隔",
														"匹配文本完毕后的延迟xxx秒允许下一次匹配",
														"delaytime",
														NetDiskData.defaultMatchIntervalTime,
														NetDiskData.matchIntervalMinTime,
														NetDiskData.matchIntervalMaxTime,
														0.1,
														void 0,
														(value) => {
															return `${value}s`;
														}
													),
													getSwtichDetail(
														"添加元素时进行匹配",
														"isAddedNodesToMatch",
														false,
														void 0,
														"当监听到页面添加元素时才进行匹配文本"
													),
													getSwtichDetail(
														"观察器:childList",
														"mutationObserver-childList",
														NetDiskData.default_mutationObserver_childList,
														void 0,
														"子节点的变动(新增、删除或者更改)"
													),
													getSwtichDetail(
														"观察器:characterData",
														"mutationObserver-characterData",
														NetDiskData.default_mutationObserver_characterData,
														void 0,
														"节点内容或节点文本的变动"
													),
													getSwtichDetail(
														"观察器:subtree",
														"mutationObserver-subtree",
														NetDiskData.default_mutationObserver_subtree,
														void 0,
														"是否将观察器应用于该节点的所有后代节点"
													),
												],
											},
										],
									},
									{
										type: "deepMenu",
										text: "功能",
										forms: [
											{
												type: "forms",
												text: "",
												className: "netdisk-panel-forms-function",
												forms: [
													getSelectDetail(
														"行为模式",
														"匹配到链接时触发的UI执行",
														"netdisk-behavior-mode",
														NetDiskData.defaultNetdiskBehaviorMode,
														[
															{
																text: "悬浮按钮+小窗",
																value: "suspension_smallwindow",
															},
															{
																text: "悬浮按钮+大窗",
																value: "suspension_window",
															},
															{
																text: "小窗",
																value: "smallwindow",
															},
														],
														void 0
													),
													getSwtichDetail(
														"自动输入访问码",
														"autoFillAccessCode",
														false,
														void 0,
														"通过主动点击链接跳转时,会自动输入网盘访问码"
													),
													getSwtichDetail(
														"获取重定向后的直链",
														"getTheDirectLinkAfterRedirection",
														false,
														void 0,
														"对获取的链接再进行一次重定向获取链接"
													),
												],
											},
										],
									},
									{
										type: "deepMenu",
										text: "分享码相关",
										forms: [
											{
												type: "forms",
												text: "",
												className: "netdisk-panel-forms-share-code",
												forms: [
													getSliderDetail(
														"相同系数",
														"例如分享码: aaaaaaaabb,它的相同系数是0.8,设置相同系数≥0.8时会被排除",
														"excludeIdenticalSharedCodesCoefficient",
														NetDiskData.defaultExcludeIdenticalSharedCodesCoefficient,
														NetDiskData.excludeIdenticalSharedCodesCoefficientMin,
														NetDiskData.excludeIdenticalSharedCodesCoefficientMax,
														0.01,
														void 0,
														(value) => {
															return value;
														}
													),
													getSwtichDetail(
														"排除分享码",
														"excludeIdenticalSharedCodes",
														false,
														void 0,
														"启用后会根据【相同系数】排除掉匹配到的分享码"
													),
												],
											},
										],
									},
								],
							},
						],
					},
				];

				let shortcutDetails = {
					type: "deepMenu",
					text: "快捷键",
					forms: [
						{
							className: "netdisk-panel-forms-shortcut-keys",
							text: "",
							type: "forms",
							forms: [],
						},
					],
				};
				let shortcurFormsDetailsList = [
					{
						text: "【打开】⚙ 设置",
						key: "netdisk-keyboard-open-setting",
					},
					{
						text: "【打开】⚙ 历史匹配记录",
						key: "netdisk-keyboard-open-history-matching-records",
					},
					{
						text: "【打开】⚙ 访问码规则",
						key: "netdisk-keyboard-open-accesscode-rule",
					},
					{
						text: "【打开】⚙ 用户自定义规则",
						key: "netdisk-keyboard-open-user-rule",
					},
					{
						text: "【打开】⚙ 主动识别文本",
						key: "netdisk-keyboard-open-proactively-recognize-text",
					},
				];
				shortcurFormsDetailsList.forEach((item) => {
					shortcutDetails.forms[0].forms.push({
						text: item.text,
						type: "button",
						attributes: {
							"data-key": item.key,
							"data-default-value": "暂无快捷键",
						},
						buttonIcon: "keyboard",
						buttonIconIsLoading: false,
						buttonType: "default",
						buttonText() {
							return NetDiskShortcut.getShowText(
								this.attributes["data-key"],
								this.attributes["data-default-value"]
							);
						},
						callback(event) {
							NetDiskShortcut.buttonClickCallBack(
								event,
								this.attributes["data-key"],
								this.attributes["data-default-value"]
							);
						},
					});
				});
				contentDetails[0].forms[0].forms.push(shortcutDetails);
				/**
				 * 追加网盘设置
				 */
				function addNetDiskSetting() {
					/**
					 * @type {NetDiskSettingMenuDetails[]}
					 */
					let netDiskDetailsList = [
						{
							type: "百度网盘",
							key: "baidu",
							enable: true,
							isBlank: true,
							openBlankWithCopyAccessCode: true,
							checkLinkValidity: true,
							isForward: true,
							isForwardBlankLink: true,
							schemeUri: true,
							innerTextAccessCodeBeforeMaxRange: 20,
							innerTextAccessCodeAfterMaxRange: 10,
							innerHTMLAccessCodeBeforeMaxRange: 100,
							innerHTMLAccessCodeAfterMaxRange: 15,
							ownFormList: [
								{
									text: "第三方解析站",
									type: "forms",
									forms: [
										{
											text: "启用解析站",
											type: "switch",
											description:
												"开源项目:<a href='https://github.com/yuantuo666/baiduwp-php' target='_blank'>https://github.com/yuantuo666/baiduwp-php</a>",
											attributes: {
												"data-key": "baidu-static-enable",
												"data-default-value": false,
											},
											getValue() {
												return Boolean(
													GM_getValue(
														this.attributes["data-key"],
														this.attributes["data-default-value"]
													)
												);
											},
											callback(event, value) {
												GM_setValue(
													this.attributes["data-key"],
													Boolean(value)
												);
											},
										},
										{
											text: "跳转时复制链接",
											type: "switch",
											description: "跳转至解析站时复制百度网盘链接",
											attributes: {
												"data-key": "baidu-baiduwp-php-copy-url",
												"data-default-value": false,
											},
											getValue() {
												return Boolean(
													GM_getValue(
														this.attributes["data-key"],
														this.attributes["data-default-value"]
													)
												);
											},
											callback(event, value) {
												GM_setValue(
													this.attributes["data-key"],
													Boolean(value)
												);
											},
										},
										{
											text: "网址",
											type: "input",
											description: "解析站的网址Url",
											attributes: {
												"data-key": "baidu-baiduwp-php-url",
												"data-default-value": "",
											},
											getValue() {
												return GM_getValue(
													this.attributes["data-key"],
													this.attributes["data-default-value"]
												);
											},
											callback(event, value) {
												GM_setValue(this.attributes["data-key"], value);
											},
											placeholder:
												"使用了baiduwp-php源码的网站,例如:https://www.example.com/",
										},
										{
											text: "表单参数",
											type: "input",
											description: "跳转时携带的参数",
											attributes: {
												"data-key": "baidu-baiduwp-php-post-form",
												"data-default-value": "",
											},
											getValue() {
												return GM_getValue(
													this.attributes["data-key"],
													this.attributes["data-default-value"]
												);
											},
											callback(event, value) {
												GM_setValue(this.attributes["data-key"], value);
											},
											placeholder:
												"POST表单,例如:surl={#shareCode#}&pwd={#accessCode#}&password=",
										},
									],
								},
							],
						},
						{
							type: "蓝奏云",
							key: "lanzou",
							enable: true,
							parseMoreFile: true,
							isBlank: true,
							openBlankWithCopyAccessCode: true,
							checkLinkValidity: true,
							isForward: true,
							isForwardBlankLink: true,
							isForwardDownloadLink: true,
							schemeUri: true,
							innerTextAccessCodeBeforeMaxRange: 20,
							innerTextAccessCodeAfterMaxRange: 10,
							innerHTMLAccessCodeBeforeMaxRange: 100,
							innerHTMLAccessCodeAfterMaxRange: 15,
							ownFormList: [
								{
									text: "其它配置",
									type: "forms",
									forms: [
										{
											text: "蓝奏云域名",
											type: "input",
											attributes: {
												"data-key": "lanzou-host-name",
												"data-default-value":
													NetDiskData.lanzou_defaultHostName,
											},
											getValue() {
												return GM_getValue(
													this.attributes["data-key"],
													this.attributes["data-default-value"]
												);
											},
											callback(event, value) {
												GM_setValue(this.attributes["data-key"], value);
											},
											placeholder: `例如:${NetDiskData.lanzou_defaultHostName}`,
										},
									],
								},
							],
						},
						{
							type: "蓝奏云优享",
							key: "lanzouyx",
							enable: true,
							parseMoreFile: true,
							isBlank: true,
							openBlankWithCopyAccessCode: true,
							checkLinkValidity: true,
							isForward: true,
							isForwardDownloadLink: true,
							isForwardBlankLink: true,
							schemeUri: true,
							innerTextAccessCodeBeforeMaxRange: 20,
							innerTextAccessCodeAfterMaxRange: 10,
							innerHTMLAccessCodeBeforeMaxRange: 100,
							innerHTMLAccessCodeAfterMaxRange: 15,
						},
						{
							type: "天翼云",
							key: "tianyiyun",
							enable: true,
							parseMoreFile: true,
							parseFileDescription: "需要登录才可以下载",
							isBlank: true,
							openBlankWithCopyAccessCode: true,
							isForward: true,
							isForwardDownloadLink: true,
							isForwardBlankLink: true,
							schemeUri: true,
							checkLinkValidity: true,
							innerTextAccessCodeBeforeMaxRange: 20,
							innerTextAccessCodeAfterMaxRange: 10,
							innerHTMLAccessCodeBeforeMaxRange: 100,
							innerHTMLAccessCodeAfterMaxRange: 15,
						},
						{
							type: "中国移动云盘",
							key: "hecaiyun",
							enable: true,
							isBlank: true,
							openBlankWithCopyAccessCode: true,
							isForward: true,
							isForwardBlankLink: true,
							schemeUri: true,
							checkLinkValidity: true,
							innerTextAccessCodeBeforeMaxRange: 20,
							innerTextAccessCodeAfterMaxRange: 10,
							innerHTMLAccessCodeBeforeMaxRange: 100,
							innerHTMLAccessCodeAfterMaxRange: 15,
						},
						{
							type: "阿里云",
							key: "aliyun",
							enable: true,
							parseMoreFile: true,
							isBlank: true,
							openBlankWithCopyAccessCode: true,
							isForward: true,
							isForwardDownloadLink: true,
							isForwardBlankLink: true,
							schemeUri: true,
							checkLinkValidity: true,
							innerTextAccessCodeBeforeMaxRange: 20,
							innerTextAccessCodeAfterMaxRange: 10,
							innerHTMLAccessCodeBeforeMaxRange: 100,
							innerHTMLAccessCodeAfterMaxRange: 15,
						},
						{
							type: "文叔叔",
							key: "wenshushu",
							enable: true,
							parseOneFile: true,
							isBlank: true,
							openBlankWithCopyAccessCode: true,
							isForward: true,
							isForwardDownloadLink: true,
							isForwardBlankLink: true,
							schemeUri: true,
							checkLinkValidity: true,
							innerTextAccessCodeBeforeMaxRange: 20,
							innerTextAccessCodeAfterMaxRange: 10,
							innerHTMLAccessCodeBeforeMaxRange: 100,
							innerHTMLAccessCodeAfterMaxRange: 15,
						},
						{
							type: "奶牛",
							key: "nainiu",
							enable: true,
							parseMoreFile: true,
							isBlank: true,
							openBlankWithCopyAccessCode: true,
							isForward: true,
							isForwardDownloadLink: true,
							isForwardBlankLink: true,
							schemeUri: true,
							checkLinkValidity: true,
							innerTextAccessCodeBeforeMaxRange: 20,
							innerTextAccessCodeAfterMaxRange: 10,
							innerHTMLAccessCodeBeforeMaxRange: 100,
							innerHTMLAccessCodeAfterMaxRange: 15,
						},
						{
							type: "123盘",
							key: "_123pan",
							enable: true,
							parseMoreFile: true,
							parseFileDescription: "需要登录才可下载>100MB的文件",
							isBlank: true,
							openBlankWithCopyAccessCode: true,
							isForward: true,
							isForwardDownloadLink: true,
							isForwardBlankLink: true,
							schemeUri: true,
							checkLinkValidity: true,
							innerTextAccessCodeBeforeMaxRange: 20,
							innerTextAccessCodeAfterMaxRange: 10,
							innerHTMLAccessCodeBeforeMaxRange: 100,
							innerHTMLAccessCodeAfterMaxRange: 15,
						},
						{
							type: "微云",
							key: "weiyun",
							enable: true,
							isBlank: true,
							openBlankWithCopyAccessCode: true,
							isForward: true,
							isForwardBlankLink: true,
							schemeUri: true,
							checkLinkValidity: true,
							innerTextAccessCodeBeforeMaxRange: 20,
							innerTextAccessCodeAfterMaxRange: 10,
							innerHTMLAccessCodeBeforeMaxRange: 100,
							innerHTMLAccessCodeAfterMaxRange: 15,
						},
						{
							type: "迅雷云盘",
							key: "xunlei",
							enable: true,
							isBlank: true,
							openBlankWithCopyAccessCode: true,
							isForward: true,
							isForwardBlankLink: true,
							schemeUri: true,
							checkLinkValidity: true,
							innerTextAccessCodeBeforeMaxRange: 20,
							innerTextAccessCodeAfterMaxRange: 10,
							innerHTMLAccessCodeBeforeMaxRange: 100,
							innerHTMLAccessCodeAfterMaxRange: 15,
						},
						{
							type: "115网盘",
							key: "_115pan",
							enable: true,
							isBlank: true,
							openBlankWithCopyAccessCode: true,
							isForward: true,
							isForwardBlankLink: true,
							schemeUri: true,
							checkLinkValidity: true,
							innerTextAccessCodeBeforeMaxRange: 20,
							innerTextAccessCodeAfterMaxRange: 10,
							innerHTMLAccessCodeBeforeMaxRange: 100,
							innerHTMLAccessCodeAfterMaxRange: 15,
						},
						{
							type: "城通网盘",
							key: "chengtong",
							enable: true,
							isBlank: true,
							openBlankWithCopyAccessCode: true,
							isForward: true,
							isForwardBlankLink: true,
							schemeUri: true,
							checkLinkValidity: true,
							innerTextAccessCodeBeforeMaxRange: 20,
							innerTextAccessCodeAfterMaxRange: 10,
							innerHTMLAccessCodeBeforeMaxRange: 100,
							innerHTMLAccessCodeAfterMaxRange: 15,
						},
						{
							type: "夸克网盘",
							key: "kuake",
							enable: true,
							isBlank: true,
							openBlankWithCopyAccessCode: true,
							isForward: true,
							isForwardBlankLink: true,
							schemeUri: true,
							checkLinkValidity: true,
							innerTextAccessCodeBeforeMaxRange: 20,
							innerTextAccessCodeAfterMaxRange: 10,
							innerHTMLAccessCodeBeforeMaxRange: 100,
							innerHTMLAccessCodeAfterMaxRange: 15,
						},
						{
							type: "BT磁力",
							key: "magnet",
							enable: true,
							isBlank: true,
							isForward: true,
							isForwardBlankLink: true,
							schemeUri: true,
						},
						{
							type: "坚果云",
							key: "jianguoyun",
							enable: true,
							parseMoreFile: true,
							isBlank: true,
							openBlankWithCopyAccessCode: true,
							isForward: true,
							isForwardDownloadLink: true,
							isForwardBlankLink: true,
							schemeUri: true,
							checkLinkValidity: true,
							innerTextAccessCodeBeforeMaxRange: 20,
							innerTextAccessCodeAfterMaxRange: 10,
							innerHTMLAccessCodeBeforeMaxRange: 100,
							innerHTMLAccessCodeAfterMaxRange: 15,
						},
						{
							type: "OneDrive",
							key: "onedrive",
							enable: true,
							isBlank: true,
							openBlankWithCopyAccessCode: true,
							isForward: true,
							isForwardBlankLink: true,
							schemeUri: true,
							checkLinkValidity: true,
							innerTextAccessCodeBeforeMaxRange: 20,
							innerTextAccessCodeAfterMaxRange: 10,
							innerHTMLAccessCodeBeforeMaxRange: 100,
							innerHTMLAccessCodeAfterMaxRange: 15,
						},
						{
							type: "UC网盘",
							key: "uc",
							enable: true,
							parseMoreFile: true,
							isBlank: true,
							openBlankWithCopyAccessCode: true,
							isForward: true,
							isForwardDownloadLink: true,
							isForwardBlankLink: true,
							schemeUri: true,
							checkLinkValidity: true,
							innerTextAccessCodeBeforeMaxRange: 20,
							innerTextAccessCodeAfterMaxRange: 10,
							innerHTMLAccessCodeBeforeMaxRange: 100,
							innerHTMLAccessCodeAfterMaxRange: 15,
						},
					];
					let userCustomDetailsList =
						NetDiskCustomRules.getSettingViewDetails();
					if (userCustomDetailsList.length) {
						/* 添加自定义的设置 */
						netDiskDetailsList = [
							...netDiskDetailsList,
							...userCustomDetailsList,
						];
					}

					netDiskDetailsList.forEach((item) => {
						let formsList = [];
						if (
							typeof item.innerTextAccessCodeBeforeMaxRange === "number" ||
							typeof item.innerTextAccessCodeAfterMaxRange === "number"
						) {
							let matchTextList = [];
							if (typeof item.innerTextAccessCodeBeforeMaxRange === "number") {
								matchTextList.push(
									getSliderDetail(
										"间隔前",
										"提取码间隔前的字符长度",
										"innerText_" + item.key,
										item.innerTextAccessCodeBeforeMaxRange,
										0,
										100
									)
								);
							}
							if (typeof item.innerTextAccessCodeAfterMaxRange === "number") {
								matchTextList.push(
									getSliderDetail(
										"间隔后",
										"提取码间隔后的字符长度",
										"accessCode_after_text_" + item.key,
										item.innerTextAccessCodeAfterMaxRange,
										0,
										100
									)
								);
							}
							if (matchTextList.length) {
								formsList.push({
									text: "提取码文本匹配Text",
									type: "forms",
									forms: matchTextList,
								});
							}
						}
						if (
							typeof item.innerHTMLAccessCodeBeforeMaxRange === "number" ||
							typeof item.innerHTMLAccessCodeAfterMaxRange === "number"
						) {
							let matchTextList = [];
							if (typeof item.innerHTMLAccessCodeBeforeMaxRange === "number") {
								matchTextList.push(
									getSliderDetail(
										"间隔前",
										"提取码间隔前的字符长度",
										"innerHTML_" + item.key,
										item.innerHTMLAccessCodeBeforeMaxRange,
										0,
										500
									)
								);
							}

							if (typeof item.innerHTMLAccessCodeAfterMaxRange === "number") {
								matchTextList.push(
									getSliderDetail(
										"间隔后",
										"提取码间隔后的字符长度",
										"accessCode_after_html_" + item.key,
										item.innerHTMLAccessCodeAfterMaxRange,
										0,
										200
									)
								);
							}
							if (matchTextList.length) {
								formsList.push({
									text: "提取码文本匹配HTML",
									type: "forms",
									forms: matchTextList,
								});
							}
						}
						if (
							item.enable != null ||
							item.isBlank != null ||
							item.parseOneFile != null ||
							item.parseMoreFile != null
						) {
							/**
							 * @type {PopsPanelFormsTotalDetails[]}
							 */
							let functionFormsList = [];
							/* 是否启用 */
							if (item.enable != null) {
								functionFormsList.push({
									text: "启用",
									type: "switch",
									description: "开启可匹配该网盘",
									attributes: {
										"data-key": `${item.key}-enable`,
										"data-default-value": true,
									},
									getValue() {
										return Boolean(
											GM_getValue(
												this.attributes["data-key"],
												this.attributes["data-default-value"]
											)
										);
									},
									callback(event, value) {
										GM_setValue(this.attributes["data-key"], Boolean(value));
										if (item.key != null && NetDisk.regular[item.key] != null) {
											NetDisk.regular[item.key].forEach((__, index) => {
												NetDisk.regular[item.key][index].enable = value;
											});
										}
									},
								});
							}
							/* 新标签页打开 */
							if (typeof item.isBlank === "boolean") {
								functionFormsList.push({
									text: "新标签页打开",
									type: "switch",
									description: "关闭为默认复制链接",
									attributes: {
										"data-key": `${item.key}-open-enable`,
										"data-default-value": false,
									},
									getValue() {
										return Boolean(
											GM_getValue(
												this.attributes["data-key"],
												this.attributes["data-default-value"]
											)
										);
									},
									callback(event, value) {
										GM_setValue(this.attributes["data-key"], Boolean(value));
										if (item.parseOneFile || item.parseMoreFile) {
											let $shadowRoot = event.target.getRootNode();
											/* 新标签页打开和单/文件解析只能开启一个 */
											/**
											 * @type {HTMLInputElement}
											 */
											let checkboxElement = $shadowRoot.querySelector(
												`li[data-key="${item.key}-static-enable"] input[type=checkbox]`
											);
											let checkboxCoreElement = $shadowRoot.querySelector(
												`li[data-key="${item.key}-static-enable"] span.pops-panel-switch__core`
											);
											if (value == true && checkboxElement.checked == true) {
												checkboxCoreElement.click();
											}
										}
									},
								});
							}
							/* 新标签页打开时复制访问码 */
							if (typeof item.openBlankWithCopyAccessCode === "boolean") {
								functionFormsList.push({
									text: "跳转时复制访问码",
									type: "switch",
									description:
										"作用于【新标签页打开】且存在访问码就复制到剪贴板",
									attributes: {
										"data-key": `${item.key}-open-blank-with-copy-accesscode`,
										"data-default-value": false,
									},
									getValue() {
										return Boolean(
											GM_getValue(
												this.attributes["data-key"],
												this.attributes["data-default-value"]
											)
										);
									},
									callback(event, value) {
										GM_setValue(this.attributes["data-key"], Boolean(value));
									},
								});
							}
							/* 单文件解析|文件解析 */
							if (item.parseOneFile || item.parseMoreFile) {
								functionFormsList.push({
									text: `${item.parseOneFile ? "单文件解析" : "文件解析"}`,
									type: "switch",
									description: item["parseFileDescription"] || "解析网盘链接",
									attributes: {
										"data-key": `${item.key}-static-enable`,
										"data-default-value": false,
									},
									getValue() {
										return Boolean(
											GM_getValue(
												this.attributes["data-key"],
												this.attributes["data-default-value"]
											)
										);
									},
									callback(event, value) {
										GM_setValue(this.attributes["data-key"], Boolean(value));
										if (item.isBlank) {
											let $shadowRoot = event.target.getRootNode();
											/* 新标签页打开和单/文件解析只能开启一个 */
											/**
											 * @type {HTMLInputElement}
											 */
											let checkboxElement = $shadowRoot.querySelector(
												`li[data-key="${item.key}-open-enable"] input[type=checkbox]`
											);
											let checkboxCoreElement = $shadowRoot.querySelector(
												`li[data-key="${item.key}-open-enable"] span.pops-panel-switch__core`
											);
											if (value == true && checkboxElement.checked == true) {
												checkboxCoreElement.click();
											}
										}
									},
								});
							}

							/* 验证链接有效性 */
							if (typeof item.checkLinkValidity === "boolean") {
								functionFormsList.push({
									text: `验证链接有效性`,
									type: "switch",
									description: "自动请求链接,判断该链接是否有效",
									attributes: {
										"data-key": `${item.key}-check-link-valid`,
										"data-default-value": false,
									},
									getValue() {
										return Boolean(
											GM_getValue(
												this.attributes["data-key"],
												this.attributes["data-default-value"]
											)
										);
									},
									callback(event, value) {
										GM_setValue(this.attributes["data-key"], Boolean(value));
									},
								});
							}

							formsList.push({
								text: "功能",
								type: "forms",
								forms: functionFormsList,
							});
						}

						/* Scheme转发直链 */
						if (item.isForward) {
							/**
							 * @type {import("@whitesev/pops/dist/types/src/components/panel/indexType").PopsPanelFormsTotalDetails[]}
							 */
							let functionFormsList = [
								{
									text: "启用",
									type: "switch",
									description: "开启后可进行scheme uri转发",
									attributes: {
										"data-key": `${item.key}-forward-scheme-enable`,
										"data-default-value": false,
									},
									getValue() {
										return Boolean(
											GM_getValue(
												this.attributes["data-key"],
												this.attributes["data-default-value"]
											)
										);
									},
									callback(event, value) {
										GM_setValue(this.attributes["data-key"], Boolean(value));
									},
								},
							];
							if (typeof item.isForwardDownloadLink === "boolean") {
								functionFormsList.push({
									text: "转发直链",
									type: "switch",
									description: "对解析的直链进行scheme转换",
									attributes: {
										"data-key": `${item.key}-forward-download-link-enable`,
										"data-default-value": false,
									},
									getValue() {
										return Boolean(
											GM_getValue(
												this.attributes["data-key"],
												this.attributes["data-default-value"]
											)
										);
									},
									callback(event, value) {
										GM_setValue(this.attributes["data-key"], Boolean(value));
									},
								});
							}
							if (typeof item.isForwardBlankLink === "boolean") {
								functionFormsList.push({
									text: "转发新标签页链接",
									type: "switch",
									description: "对新标签页打开的链接进行scheme转换",
									attributes: {
										"data-key": `${item.key}-forward-blank-link-enable`,
										"data-default-value": false,
									},
									getValue() {
										return Boolean(
											GM_getValue(
												this.attributes["data-key"],
												this.attributes["data-default-value"]
											)
										);
									},
									callback(event, value) {
										GM_setValue(this.attributes["data-key"], Boolean(value));
									},
								});
							}

							/* Scheme的Uri链接 */
							if ("schemeUri" in item) {
								functionFormsList.push({
									text: "Uri链接",
									type: "input",
									description: "自定义的Scheme的Uri链接",
									attributes: {
										"data-key": `${item.key}-static-scheme-uri`,
										"data-default-value": "",
									},
									getValue() {
										return GM_getValue(
											this.attributes["data-key"],
											this.attributes["data-default-value"]
										);
									},
									callback(event, value) {
										GM_setValue(this.attributes["data-key"], value);
									},
									placeholder:
										"jumpwsv://go?package=xx&activity=xx&intentAction=xx&intentData=xx&intentExtra=xx",
								});
							}
							formsList.push({
								text: "Scheme Uri转发",
								type: "forms",
								forms: functionFormsList,
							});
						}
						if (item.ownFormList) {
							formsList = formsList.concat(item.ownFormList);
						}

						let asideTitle = item.key;
						if (item.key in NetDiskUI.src.icon) {
							if (pops.isPhone()) {
								asideTitle = /*html*/ `
								<div style="
									width: 20px;
									height: 20px;
									background: url(${NetDiskUI.src.icon[item.key]}) no-repeat;
									background-size: 100% 100%;
									">`;
							} else {
								asideTitle = /*html*/ `
								<div style="
									width: 20px;
									height: 20px;
									background: url(${NetDiskUI.src.icon[item.key]}) no-repeat;
									background-size: 100% 100%;
									"></div>
								<div style="margin-left: 4px;">${item.type}</div>`;
							}
						}
						let headerTitleText = item.type;
						if (item.isUserRule) {
							headerTitleText += /*html*/ `<div class="netdisk-custom-rule-edit" data-key="${item.key}" data-type="${item.type}">${pops.config.iconSVG.edit}</div>`;
							headerTitleText += /*html*/ `<div class="netdisk-custom-rule-delete" data-key="${item.key}" data-type="${item.type}">${pops.config.iconSVG.delete}</div>`;
						}
						contentDetails.push({
							id: "netdisk-panel-config-" + item.key,
							title: asideTitle,
							headerTitle: headerTitleText,
							attributes: {
								"data-key": item.key,
							},
							forms: formsList,
						});
					});
				}
				addNetDiskSetting();

				NetDiskUI.Alias.settingAlias = NetDiskPops.panel(
					{
						title: {
							text: `${GM_info?.script?.name || "网盘链接识别"}-设置`,
							position: "center",
						},
						content: contentDetails,
						btn: {
							close: {
								enable: true,
								callback(event) {
									event.close();
									NetDiskUI.Alias.settingAlias = void 0;
								},
							},
						},
						mask: {
							clickCallBack(originalRun) {
								originalRun();
								NetDiskUI.Alias.settingAlias = void 0;
							},
						},
						class: "whitesevPopSetting",
						style: /*css*/ `
						div[class^="netdisk-custom-rule-"]{
							display: flex;
							align-items: center;
							margin-left: 10px;
							cursor: pointer;
						}
						div[class^="netdisk-custom-rule-"] svg,
						div[class^="netdisk-custom-rule-"] svg{
							width: 1.2em;
							height: 1.2em;
						}
						`,
					},
					NetDiskUI.popsStyle.settingView
				);
				DOMUtils.on(
					NetDiskUI.Alias.settingAlias.$shadowRoot,
					"click",
					".netdisk-custom-rule-edit",
					function (event) {
						let ruleKey = event.target.getAttribute("data-key");
						let ruleName = event.target.getAttribute("data-type");
						NetDiskCustomRules.showUI(true, ruleKey);
					}
				);

				DOMUtils.on(
					NetDiskUI.Alias.settingAlias.$shadowRoot,
					"click",
					".netdisk-custom-rule-delete",
					function (event) {
						let ruleKey = event.target.getAttribute("data-key");
						let ruleName = event.target.getAttribute("data-type");
						NetDiskPops.alert({
							title: {
								text: "提示",
								position: "center",
							},
							content: {
								text: `确定删除自定义规则 ${ruleName}(${ruleKey}) 吗?`,
							},
							btn: {
								ok: {
									callback(okEvent) {
										let deleteStatus = NetDiskCustomRules.deleteRule(ruleKey);
										if (deleteStatus) {
											let asideElement =
												NetDiskUI.Alias.settingAlias.$shadowRoot.querySelector(
													`.pops-panel-aside > ul > li[data-key="${ruleKey}"]`
												);
											if (asideElement.previousElementSibling) {
												asideElement.previousElementSibling.click();
											} else if (asideElement.nextElementSibling) {
												asideElement.nextElementSibling.click();
											}
											asideElement?.remove();
											Qmsg.success("删除成功");
											okEvent.close();
										} else {
											Qmsg.error("删除自定义规则失败");
										}
									},
								},
							},
						});
					}
				);
			},
			/**
			 * 设置 悬浮按钮所有事件
			 */
			setSuspensionEvent() {
				let that = this;
				let needDragElement = NetDiskUI.suspension.suspensionNode;
				let dragNode = new AnyTouch(needDragElement);
				/** @type {?number[]} */
				let netDiskLinkViewTimer = void 0;
				let moveFlag = false;
				/* 是否是双击 */
				let isDouble = false;
				/* 点击元素,left偏移 */
				let clickElementLeftOffset = 0;
				/* 点击元素,top偏移 */
				let clickElementTopOffset = 0;
				/* 设置悬浮按钮 按下事件 */
				dragNode.on("pan", function (event) {
					if (!moveFlag) {
						moveFlag = true;
						let rect = needDragElement.getBoundingClientRect();
						clickElementLeftOffset = event.x - rect.left;
						clickElementTopOffset = event.y - rect.top;
						DOMUtils.css(needDragElement, {
							cursor: "move",
							transition: "none",
						});
					}
					/**
					 * 移动
					 */
					if (event.phase === "move") {
						/* 悬浮按钮大小不能超过250px */
						/* left偏移最大值 */
						let maxLeftOffset = DOMUtils.width(globalThis) - NetDiskUI.size;
						/* top偏移的最大值 */
						let maxTopOffset = DOMUtils.height(globalThis) - NetDiskUI.size;
						/* 当前移动的left偏移 */
						let currentSuspensionLeftOffset = event.x - clickElementLeftOffset;
						/* 当前移动的top偏移 */
						let currentSuspensionTopOffset = event.y - clickElementTopOffset;
						/* 不允许超过窗口最大宽度 */
						currentSuspensionLeftOffset =
							currentSuspensionLeftOffset > maxLeftOffset
								? maxLeftOffset
								: currentSuspensionLeftOffset;
						/* 不允许超过窗口最大高度 */
						currentSuspensionTopOffset =
							currentSuspensionTopOffset > maxTopOffset
								? maxTopOffset
								: currentSuspensionTopOffset;
						/* 不允许小于0 */
						currentSuspensionLeftOffset =
							currentSuspensionLeftOffset < 0 ? 0 : currentSuspensionLeftOffset;
						/* 不允许小于0 */
						currentSuspensionTopOffset =
							currentSuspensionTopOffset < 0 ? 0 : currentSuspensionTopOffset;
						if (NetDiskUI.suspension.isTopWindow()) {
							GM_setValue("suspensionX", currentSuspensionLeftOffset);
							GM_setValue("suspensionY", currentSuspensionTopOffset);
						}
						DOMUtils.css(needDragElement, {
							left: currentSuspensionLeftOffset + "px",
							top: currentSuspensionTopOffset + "px",
						});
					}

					/**
					 * 停止移动
					 */
					if (event.phase === "end") {
						moveFlag = false;
						DOMUtils.css(needDragElement, {
							cursor: "auto",
						});
						/* 获取当前悬浮按钮left偏移 */
						let currentSuspensionLeftOffset = parseInt(
							DOMUtils.css(needDragElement, "left")
						);
						if (GM_getValue("suspended-button-adsorption-edge")) {
							let setCSSLeft = 0;
							/* 判断悬浮按钮是否在右边区域 */
							if (
								currentSuspensionLeftOffset >=
								DOMUtils.width(globalThis) / 2
							) {
								/* 设置悬浮按钮的left偏移 */
								setCSSLeft = DOMUtils.width(globalThis) - NetDiskUI.size;
								if (NetDiskUI.suspension.isTopWindow()) {
									GM_setValue("isRight", true);
								}
							} else {
								if (NetDiskUI.suspension.isTopWindow()) {
									GM_setValue("isRight", false);
								}
							}
							if (NetDiskUI.suspension.isTopWindow()) {
								GM_setValue("suspensionX", setCSSLeft);
							}
							DOMUtils.css(needDragElement, {
								left: setCSSLeft + "px",
							});
						}
						DOMUtils.css(needDragElement, {
							transition: "left 300ms ease 0s",
						});
					}
				});
				/* 设置悬浮按钮 点击/按下事件 */
				dragNode.on(["click", "tap"], function (event) {
					clearTimeout(netDiskLinkViewTimer);
					netDiskLinkViewTimer = void 0;
					if (isDouble) {
						isDouble = false;
						/* 判定为双击 */
						NetDiskUI.suspension.showSettingView();
					} else {
						netDiskLinkViewTimer = setTimeout(() => {
							isDouble = false;
							if (
								NetDiskUIMenuData.netdiskBehaviorMode.includes("smallwindow")
							) {
								GM_setValue(
									"current_suspension_smallwindow_mode",
									"smallwindow"
								);
								NetDiskUI.suspension.hideSuspension();
							}
							NetDiskUI.view.show();
						}, 200);
						isDouble = true;
					}
				});
				NetDiskUI.setGlobalRightClickMenu(needDragElement);
			},
			/**
			 * 设置window的resize事件监听,来重新设置悬浮按钮的位置
			 */
			setResizeEventListener() {
				DOMUtils.on(globalThis, "resize", void 0, () => {
					let activeElement = document.activeElement;
					if (utils.isPhone()) {
						if (["input", "textarea"].includes(activeElement.localName)) {
							/* 可能是移动端的输入框弹出的键盘导致的resize */
							return;
						} else if (
							(activeElement.hasAttribute("contenteditable") &&
								activeElement.getAttribute("contenteditable") === "true") ||
							activeElement.closest("[contenteditable='true']")
						) {
							/* 可能是移动端的输入框弹出的键盘导致的resize */
							return;
						} else if (!document.hasFocus()) {
							/* 页面失焦 */
							return;
						}
					}
					this.setSuspensionPosition();
				});
			},
			/**
			 * 设置悬浮按钮位置
			 */
			setSuspensionPosition() {
				/* 最大的left偏移*/
				let maxLeftOffset = DOMUtils.width(globalThis) - NetDiskUI.size;
				/* 最大的top偏移 */
				let maxTopOffset = DOMUtils.height(globalThis) - NetDiskUI.size;
				/* 默认的left偏移(悬浮按钮在右边中间) */
				let defaultLeftOffset = maxLeftOffset;
				/* 默认的top偏移(悬浮按钮在右边中间) */
				let defaultTopOffset = maxTopOffset / 2;
				/* 用户自己拖动设置的悬浮按钮left偏移 */
				let userSetLeftOffset = GM_getValue("suspensionX", defaultLeftOffset);

				/* 用户自己拖动设置的悬浮按钮top偏移 */
				let userSetTopOffset = GM_getValue("suspensionY", defaultTopOffset);

				if (GM_getValue("suspended-button-adsorption-edge")) {
					/* 如果isRight为true,悬浮按钮放到最右边,否则最左边 */
					if (GM_getValue("isRight")) {
						userSetLeftOffset = maxLeftOffset;
					} else {
						userSetLeftOffset = 0;
					}
					/* 如果用户设置的top偏移超出最大的top偏移,那么设置用户的偏移为默认的最大top偏移 */
					if (userSetTopOffset > maxTopOffset) {
						userSetTopOffset = maxTopOffset;
					} else if (userSetTopOffset < 0) {
						/* 如果用户设置的top偏移为负的,那么是超出边界,归位设置为0 */
						userSetTopOffset = 0;
					}

					if (NetDiskUI.suspension.isTopWindow()) {
						/* 当前窗口是顶部窗口,才可以保存移动的值 */
						GM_setValue("suspensionX", userSetLeftOffset);
						GM_setValue("suspensionY", userSetTopOffset);
					}
				}
				DOMUtils.css(NetDiskUI.suspension.suspensionNode, {
					left: userSetLeftOffset + "px",
					top: userSetTopOffset + "px",
				});
			},
			getCSS() {
				return `
					.whitesevSuspension{
						top: 0;
						position:fixed;
						right:10px;
						border-radius: 12px;
						z-index:4000;
					}
					.whitesevSuspension .whitesevSuspensionMain{
						background:#fff;
						border:1px solid #f2f2f2;
						box-shadow:0 0 15px #e4e4e4;
						box-sizing:border-box;
						border-radius: inherit;
						height: inherit;
						width: inherit;
					}
					.whitesevSuspension .whitesevSuspensionFloor{
						border-bottom:1px solid #f2f2f2;
						position:relative;
						box-sizing:border-box;
						border-radius: inherit;
						height: inherit;
						width: inherit;
					}
					.whitesevSuspension .whitesevSuspensionFloor .netdisk{
						background-position:center center;
						background-size:115% 115%;
						background-repeat:no-repeat;
						display:flex;
						align-items:center;
						justify-content:center;
						border-radius: inherit;
						height: inherit;
						width: inherit;
					}
					.whitesevSuspension .whitesevSuspensionFloor .netdisk:hover{
						transition:all 300ms linear;
						background-color:#e4e4e4;
						transform:scale(1.1);
					}
					.whitesevPop-content p[pop]{
						height: 100%;
					}
				`;
			},
			/**
			 * 悬浮按钮背景轮播 效果为淡入淡出
			 */
			backgroundSwitch() {
				if (this.isRandBg) {
					return;
				}
				/**
				 * 获取随机背景的数组
				 * @returns {Array}
				 */
				function getRandBgList() {
					let resultList = [];
					NetDiskUI.isMatchedNetDiskIconMap.forEach((item) => {
						resultList = [...resultList, NetDiskUI.src.icon[item]];
					});
					return resultList;
				}
				/**
				 * 进行切换 淡入淡出
				 * @param {number} fadeTime 淡入\淡出的时间
				 * @param {string} currentBackgroundSrc 当前的背景资源
				 */
				function startSwitch(fadeTime, currentBackgroundSrc) {
					currentList = getRandBgList();
					DOMUtils.fadeOut(randBgNode, fadeTime, function () {
						currentIndex++;
						currentIndex = currentIndex < currentList.length ? currentIndex : 0;
						currentBackgroundSrc = currentList[currentIndex];
						DOMUtils.css(
							randBgNode,
							"background-image",
							`url(${currentBackgroundSrc})`
						);
						DOMUtils.fadeIn(randBgNode, fadeTime, function () {
							setTimeout(() => {
								startSwitch(
									parseInt(GM_getValue("randbg-time", switchBgTime)),
									currentBackgroundSrc
								);
							}, parseInt(GM_getValue("randbg-show-time", switchBgShowTime)));
						});
					});
				}
				let currentList = [];
				let currentIndex = 0;
				let switchBgTime = 1500; /* 淡入或淡出的持续时间 */
				let switchBgShowTime = 1200; /* 淡入或淡出后的延迟切换时间 */
				currentList = getRandBgList();
				let randBgSrc = currentList[currentIndex];
				let randBgNode = NetDiskUI.suspension.suspensionNode.querySelector(
					".whitesevSuspension .netdisk"
				);
				DOMUtils.css(randBgNode, "background-image", `url(${randBgSrc})`);
				if (
					currentList.length < 2 ||
					GM_getValue("randbg-time", switchBgTime) <= 0
				) {
					/* 只有一个的话或淡入/淡出的时间<=0 就不进行背景切换 */
					return;
				}
				this.isRandBg = true;

				startSwitch(
					parseInt(GM_getValue("randbg-time", switchBgTime)),
					randBgSrc
				);
			},
		},
		/**
		 * 主视图
		 */
		view: {
			show() {
				if (!NetDiskUI.Alias.uiLinkAlias) {
					this.createView();
					NetDiskUI.setRightClickMenu(
						NetDiskUI.Alias.uiLinkAlias.$shadowRoot,
						".whitesevPop .netdisk-url a"
					);
					this.registerIconGotoPagePosition(
						NetDiskUI.Alias.uiLinkAlias.$shadowRoot
					);
					this.setNetDiskUrlClickEvent(
						NetDiskUI.Alias.uiLinkAlias.$shadowRoot,
						".netdisk-url a"
					);
					NetDiskUI.setGlobalRightClickMenu(
						NetDiskUI.Alias.uiLinkAlias.$shadowRoot.querySelector(
							".pops .pops-alert-title > p"
						)
					);
				} else {
					NetDiskUI.Alias.uiLinkAlias.show();
				}
			},
			getCSS() {
				return `
        .netdisk-url-box{
          border-bottom: 1px solid #e4e6eb;
        }
        .netdisk-url-div{display:flex;align-items:center;width:100%;padding:5px 0px 5px 0px}
        .netdisk-icon{display:contents}
        .netdisk-icon .netdisk-icon-img{
          cursor: pointer;
          width:28px;
          height:28px;
          min-width:28px;
          min-height:28px;
          font-size:0.8em;
          margin: 0px 10px;
        }
        .netdisk-url-div .netdisk-icon,
        .netdisk-url-div .netdisk-status{
          flex: 0 0 auto;
        }
        .netdisk-url-div .netdisk-url{
          flex: 1;
        }
        .netdisk-icon .netdisk-icon-img{
          border-radius: 10px;
          box-shadow: 0 .3px .6px rgb(0 0 0 / 6%),0 .7px 1.3px rgb(0 0 0 / 8%),0 1.3px 2.5px rgb(0 0 0 / 10%),0 2.2px 4.5px rgb(0 0 0 / 12%),0 4.2px 8.4px rgb(0 0 0 / 14%),0 10px 20px rgb(0 0 0 / 20%)
        }
        .netdisk-status[data-check-failed]{
          padding: 5px 5px;
        }
        .netdisk-url{padding:5px 5px;}
        .netdisk-url a {
          color: #ff4848!important;
          min-height: 28px;
          overflow-x: hidden;
          overflow-y: auto;
          font-size: 0.8em;
          border: none;
          display: flex;
          align-items: center;
          width: 100%;
          height: 100%;
          padding: 0px;
          word-break: break-word;
          text-align: left;
        }
        .netdisk-status{
          display: none;
        }
        .netdisk-status[data-check-valid]{
          display: flex;
          align-items: center;
          width: 15px;
          height: 15px;
        }
        .netdisk-status[data-check-valid="failed"]{
          color: red;
        }
        .netdisk-status[data-check-valid="error"]{
          cursor: pointer;
        }
        .netdisk-status[data-check-valid="success"]{
          color: green;
        }
        .netdisk-status[data-check-valid="loading"] svg{
          animation: rotating 2s linear infinite;
        }
        .netdisk-url-box:has(.netdisk-status[data-check-valid="failed"]){
          text-decoration: line-through;
        }
        .whitesevPop-whitesevPopSetting :focus-visible{outline-offset:0;outline:0}
        .netdisk-url a[isvisited=true]{color:#8b8888!important}
        .netdisk-url a:active{box-shadow:0 0 0 1px #616161 inset}
        .netdisk-url a:focus-visible{outline:0}
        .whitesevPop-content p[pop]{text-indent:0}
        .whitesevPop-button[type=primary]{border-color:#2d8cf0;background-color:#2d8cf0}
				`;
			},
			/**
			 * 创建视图
			 */
			createView() {
				let viewAddHTML = "";
				NetDiskUI.isMatchedNetDiskIconMap.forEach((netDiskName) => {
					let netDiskDict = NetDisk.linkDict.get(netDiskName);
					let netDiskData = netDiskDict.getItems();
					Object.keys(netDiskData).forEach((shareCode) => {
						let accessCodeDict = netDiskData[shareCode];
						let uiLink = NetDisk.handleLinkShow(
							netDiskName,
							accessCodeDict["netDiskIndex"],
							shareCode,
							accessCodeDict["accessCode"],
							accessCodeDict["matchText"]
						);
						viewAddHTML =
							viewAddHTML +
							this.getViewHTML(
								NetDiskUI.src.icon[netDiskName],
								netDiskName,
								accessCodeDict["netDiskIndex"],
								shareCode,
								accessCodeDict["accessCode"],
								uiLink
							);
					});
				});
				let viewHTML = `
					<div class="netdisk-url-box-all">
						${viewAddHTML}
					</div>`;

				if (
					NetDiskUIMenuData.netdiskBehaviorMode
						.toLowerCase()
						.includes("smallwindow")
				) {
					NetDiskUI.Alias.uiLinkAlias = NetDiskPops.alert(
						{
							title: {
								text: "网盘",
								position: "center",
							},
							content: {
								text: viewHTML,
								html: true,
							},
							btn: {
								ok: {
									enable: false,
								},
								close: {
									callback(event) {
										if (
											NetDiskUIMenuData.netdiskBehaviorMode
												.toLowerCase()
												.includes("suspension")
										) {
											GM_setValue(
												"current_suspension_smallwindow_mode",
												"suspension"
											);
											event.hide();
											NetDiskUI.suspension.show();
										} else {
											NetDiskUI.Alias.uiLinkAlias = void 0;
											event.close();
										}
									},
								},
							},
							mask: {
								enable: false,
							},
							animation: "",
							beforeAppendToPageCallBack($shadowRoot, $shadowContainer) {
								let buttonHeaderControl = $shadowRoot.querySelector(
									".pops-header-control"
								);
								let alertContent = $shadowRoot.querySelector(
									".pops-alert-content"
								);
								/* 展开 */
								let launchIcon = DOMUtils.createElement(
									"button",
									{
										className: "pops-header-control",
										innerHTML: `
                    <i class="pops-icon">
                      <svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
                        <path fill="currentColor" d="M290.816 774.144h167.936c12.288 0 20.48 8.192 20.48 20.48s-8.192 20.48-20.48 20.48h-219.136c-12.288 0-20.48-8.192-20.48-20.48v-2.048-206.848c0-12.288 8.192-20.48 20.48-20.48s20.48 8.192 20.48 20.48v163.84l210.944-198.656c8.192-8.192 20.48-8.192 28.672 0s8.192 20.48 0 28.672l-208.896 194.56z m462.848-524.288h-167.936c-12.288 0-20.48-8.192-20.48-20.48s8.192-20.48 20.48-20.48h219.136c12.288 0 20.48 8.192 20.48 20.48v208.896c0 12.288-8.192 20.48-20.48 20.48s-20.48-8.192-20.48-20.48v-163.84l-210.944 198.656c-8.192 8.192-20.48 8.192-28.672 0s-8.192-20.48 0-28.672l208.896-194.56z m188.416 323.584c0 12.288-8.192 20.48-20.48 20.48s-20.48-8.192-20.48-20.48v-389.12c0-34.816-26.624-61.44-61.44-61.44h-655.36c-34.816 0-61.44 26.624-61.44 61.44v655.36c0 34.816 26.624 61.44 61.44 61.44h655.36c34.816 0 61.44-26.624 61.44-61.44v-94.208c0-12.288 8.192-20.48 20.48-20.48s20.48 8.192 20.48 20.48v94.208c0 57.344-45.056 102.4-102.4 102.4h-655.36c-57.344 0-102.4-45.056-102.4-102.4v-655.36c0-57.344 45.056-102.4 102.4-102.4h655.36c57.344 0 102.4 45.056 102.4 102.4v389.12z">
                        </path>
                      </svg>
                    </i>
                  `,
									},
									{
										type: "launch",
										"data-header": true,
									}
								);
								/* 收起 */
								let shrinkIcon = DOMUtils.createElement(
									"button",
									{
										className: "pops-header-control",
										innerHTML: `
                    <i class="pops-icon">
                      <svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
                        <path fill="currentColor" d="M618.496 425.984h167.936c12.288 0 20.48 8.192 20.48 20.48s-8.192 20.48-20.48 20.48h-219.136c-12.288 0-20.48-8.192-20.48-20.48v-2.048-206.848c0-12.288 8.192-20.48 20.48-20.48s20.48 8.192 20.48 20.48v163.84l210.944-198.656c8.192-8.192 20.48-8.192 28.672 0s8.192 20.48 0 28.672l-208.896 194.56z m-192.512 172.032h-167.936c-12.288 0-20.48-8.192-20.48-20.48s8.192-20.48 20.48-20.48h219.136c12.288 0 20.48 8.192 20.48 20.48v208.896c0 12.288-8.192 20.48-20.48 20.48s-20.48-8.192-20.48-20.48v-163.84l-210.944 198.656c-8.192 8.192-20.48 8.192-28.672 0s-8.192-20.48 0-28.672l208.896-194.56z m516.096-24.576c0 12.288-8.192 20.48-20.48 20.48s-20.48-8.192-20.48-20.48v-389.12c0-34.816-26.624-61.44-61.44-61.44h-655.36c-34.816 0-61.44 26.624-61.44 61.44v655.36c0 34.816 26.624 61.44 61.44 61.44h655.36c34.816 0 61.44-26.624 61.44-61.44v-94.208c0-12.288 8.192-20.48 20.48-20.48s20.48 8.192 20.48 20.48v94.208c0 57.344-45.056 102.4-102.4 102.4h-655.36c-57.344 0-102.4-45.056-102.4-102.4v-655.36c0-57.344 45.056-102.4 102.4-102.4h655.36c57.344 0 102.4 45.056 102.4 102.4v389.12z">
                        </path>
                      </svg>
                    </i>
                  `,
									},
									{
										type: "shrink",
										"data-header": true,
									}
								);
								DOMUtils.before(buttonHeaderControl, launchIcon);
								DOMUtils.before(buttonHeaderControl, shrinkIcon);
								DOMUtils.on(
									launchIcon,
									"click",
									void 0,
									function () {
										/* 展开-切换为收缩图标 */
										launchIcon.classList.add("pops-hide-important");
										shrinkIcon.classList.remove("pops-hide-important");
										alertContent.classList.remove("pops-hide-important");
										GM_setValue("netdisl-small-window-shrink-status", false);
									},
									{
										capture: true,
									}
								);
								DOMUtils.on(
									shrinkIcon,
									"click",
									void 0,
									function () {
										/* 收缩-切换为展开图标 */
										shrinkIcon.classList.add("pops-hide-important");
										launchIcon.classList.remove("pops-hide-important");
										alertContent.classList.add("pops-hide-important");
										alertContent.classList.add("pops-no-border-important");
										GM_setValue("netdisl-small-window-shrink-status", true);
									},
									{
										capture: true,
									}
								);
								if (GM_getValue("netdisl-small-window-shrink-status", false)) {
									shrinkIcon.click();
								} else {
									launchIcon.click();
								}
							},
							dragMoveCallBack(moveElement, left, top) {
								GM_setValue("netdisk-ui-small-window-position", {
									left: left,
									top: top,
								});
							},
							class: "whitesevPop",
							style: `
              ${this.getCSS()}

              .pops {
                --container-title-height: 35px;
                --content-max-height: ${GM_getValue(
									"netdisk-ui-small-window-max-height",
									NetDiskData.defaultSmallWindowMaxHeight
								)}px;
                --netdisk-line-space: 8px;
                --netdisk-icon-size: 24px;
              }
              .pops[type-value="alert"]{
                transform: none;
              }
              .pops {
                max-height: var(--content-max-height);
              }
              .pops[type-value=alert] .pops-alert-content{
                max-height: calc(var(--content-max-height) - var(--container-title-height) - var(--container-bottom-btn-height));
              }
              .pops-header-controls button.pops-header-control[type][data-header]{
                padding: 0px 5px;
              }
              .netdisk-url-div{
                padding: 0px;
              }
              .netdisk-icon .netdisk-icon-img{
                width: var(--netdisk-icon-size);
                height: var(--netdisk-icon-size);
                min-width: var(--netdisk-icon-size);
                min-height: var(--netdisk-icon-size);
                margin: 0px var(--netdisk-line-space);
              }
              .netdisk-status{
                margin-right: var(--netdisk-line-space);
              }
              .netdisk-url{
                padding: 2px 0px;
              }
              `,
						},
						NetDiskUI.popsStyle.mainViewSmallWindow
					);

					let smallWindowPosition = GM_getValue(
						"netdisk-ui-small-window-position"
					);
					let popsElement = NetDiskUI.Alias.uiLinkAlias.popsElement;
					if (smallWindowPosition) {
						let viewWidth = DOMUtils.width(popsElement, true);
						let viewHeight = DOMUtils.height(popsElement, true);
						let maxWindowLeft = DOMUtils.width(globalThis);
						let maxWindowTop = DOMUtils.height(globalThis);
						const { transformLeft, transformTop } =
							DOMUtils.getTransform(popsElement);
						/* 最大的left偏移*/
						let maxLeft = maxWindowLeft - viewWidth + transformLeft;
						/* 最大的top偏移 */
						let maxTop = maxWindowTop - viewHeight + transformTop;
						/* 最小的left偏移*/
						let minLeft = 0 + transformLeft;
						/* 最小的top偏移*/
						let minTop = 0 + transformTop;
						if (smallWindowPosition.top > maxTop) {
							smallWindowPosition.top = maxTop;
						} else if (smallWindowPosition.top < minTop) {
							smallWindowPosition.top = minTop;
						}
						if (smallWindowPosition.left > maxLeft) {
							smallWindowPosition.left = maxLeft;
						} else if (smallWindowPosition.left < minLeft) {
							smallWindowPosition.left = minLeft;
						}
						popsElement.style.transitionDuration = "0s";
						popsElement.style.left = smallWindowPosition["left"] + "px";
						popsElement.style.top = smallWindowPosition["top"] + "px";
						setTimeout(() => {
							popsElement.style.transitionDuration = "0s";
						}, 300);
					}
				} else {
					NetDiskUI.Alias.uiLinkAlias = NetDiskPops.alert(
						{
							title: {
								text: "网盘",
								position: "center",
							},
							content: {
								text: viewHTML,
								html: true,
							},
							btn: {
								ok: {
									enable: false,
								},
								close: {
									callback(event) {
										NetDiskUI.Alias.uiLinkAlias = void 0;
										event.close();
									},
								},
							},
							mask: {
								clickCallBack(originalRun) {
									originalRun();
									NetDiskUI.Alias.uiLinkAlias = void 0;
								},
							},
							class: "whitesevPop",
							style: `
              ${this.getCSS()}

              .pops {
                max-height: ${pops.isPhone() ? "50vh" : "60vh"};
              }
              `,
						},
						NetDiskUI.popsStyle.mainView
					);
				}

				NetDiskUI.Alias.uiLinkAlias.popsElement
					.querySelectorAll(".netdisk-url-box-all .netdisk-url-box")
					.forEach((ele) => {
						let netDiskName = ele
							.querySelector(".netdisk-link")
							.getAttribute("data-netdisk");
						let netDiskIndex = parseInt(
							ele
								.querySelector(".netdisk-link")
								.getAttribute("data-netdisk-index")
						);
						let shareCode = ele
							.querySelector(".netdisk-link")
							.getAttribute("data-sharecode");
						let accessCode = ele
							.querySelector(".netdisk-link")
							.getAttribute("data-accesscode");
						NetDiskCheckLinkValidity.check(
							ele,
							netDiskName,
							netDiskIndex,
							shareCode,
							accessCode
						);
					});
			},
			/**
			 * 获取视图html
			 * @param {string} netDiskImgSrc 网盘图标src
			 * @param {string} netDiskName 网盘名称
			 * @param {number} netDiskIndex 网盘名称索引下标
			 * @param {string} shareCode
			 * @param {string} accessCode
			 * @param {string} uiLinkText 显示出来的链接文本
			 * @returns {string}
			 */
			getViewHTML(
				netDiskImgSrc,
				netDiskName,
				netDiskIndex,
				shareCode,
				accessCode,
				uiLinkText
			) {
				return `
				<div class="netdisk-url-box">
					<div class="netdisk-url-div">
						<div class="netdisk-icon">
							<div class="netdisk-icon-img"
                  style="background: url(${netDiskImgSrc}) no-repeat;background-size: 100%;"
                  data-netdisk="${netDiskName}"
                  data-sharecode="${shareCode}"
                  data-accesscode="${accessCode}">
						  </div>
            </div>
            <div class="netdisk-status">

            </div>
						<div class="netdisk-url">
							<a  class="netdisk-link"
                  href="javascript:;" 
                  isvisited="false"
                  data-netdisk="${netDiskName}"
                  data-netdisk-index="${netDiskIndex}"
                  data-sharecode="${shareCode}"
                  data-accesscode="${accessCode}"
                  data-open-enable-key="${netDiskName}-open-enable"
                  data-static-enable-key="${netDiskName}-static-enable"
                  data-forward-scheme-key="${netDiskName}-forward-scheme-enable">${uiLinkText}</a>
						</div>
					</div>
				</div>`;
			},
			/**
			 * 设置网盘链接点击事件,要求,它是<a>元素且存在以下属性
			 * isvisited  string true|false
			 * data-netdisk  string
			 * data-netdisk-index number
			 * data-sharecode string
			 * data-accesscode string
			 * data-open-enable-key string
			 * data-static-enable-key string
			 * data-forward-scheme-key string
			 * @param {*} target
			 * @param {string} clickNodeSelector - 元素选择器
			 */
			setNetDiskUrlClickEvent(target, clickNodeSelector) {
				function clickEvent(event) {
					event.target.setAttribute("isvisited", "true");
					let netDiskName = event.target.getAttribute("data-netdisk");
					let netDiskIndex = parseInt(
						event.target.getAttribute("data-netdisk-index")
					);
					let shareCode = event.target.getAttribute("data-sharecode");
					let accessCode = event.target.getAttribute("data-accesscode");
					let openEnable = GM_getValue(
						event.target.getAttribute("data-open-enable-key"),
						false
					);
					let staticEnable = GM_getValue(
						event.target.getAttribute("data-static-enable-key"),
						false
					);
					let schemeEnable = GM_getValue(
						event.target.getAttribute("data-forward-scheme-key"),
						false
					);
					if (openEnable) {
						let url = NetDiskParse.getBlankUrl(
							netDiskName,
							netDiskIndex,
							shareCode,
							accessCode
						);
						NetDiskParse.blank(
							url,
							netDiskName,
							netDiskIndex,
							shareCode,
							accessCode
						);
					} else if (staticEnable) {
						NetDiskParse.parse(
							netDiskName,
							netDiskIndex,
							shareCode,
							accessCode
						);
					} else if (schemeEnable) {
						NetDiskParse.openScheme(
							netDiskName,
							netDiskIndex,
							shareCode,
							accessCode
						);
					} else {
						NetDiskParse.copyText(
							netDiskName,
							netDiskIndex,
							shareCode,
							accessCode
						);
					}
				}
				DOMUtils.on(target, "click", clickNodeSelector, clickEvent);
			},
			/**
			 * 注册右键菜单
			 * @param {HTMLElement|Window} target
			 * @param {?string} selector
			 * @param {{text:string,callback:Function}[]} showTextList 右键菜单的内容
			 * @param {string} className className属性
			 */
			registerContextMenu(
				target,
				selector,
				showTextList = [],
				className = "whitesevSuspensionContextMenu"
			) {
				let data = [];
				showTextList.forEach((item) => {
					data.push({
						icon: "",
						text: item.text,
						callback: item.callback,
					});
				});
				pops.rightClickMenu({
					target: target,
					targetSelector: selector,
					data: data,
					isAnimation: false,
					className: className,
				});
			},
			/**
			 * 添加新的链接
			 * @param {string} netDiskName 网盘名称
			 * @param {number} netDiskIndex 网盘名称索引下标
			 * @param {string} shareCode 分享码
			 * @param {string} accessCode 访问码
			 * @param {string} matchText 匹配到的文本
			 */
			addLinkView(netDiskName, netDiskIndex, shareCode, accessCode, matchText) {
				NetDiskUI.netDiskHistoryMatch.setNetDiskHistoryMatchData(
					netDiskName,
					netDiskIndex,
					shareCode,
					accessCode,
					matchText
				);
				if (!NetDiskUI.Alias.uiLinkAlias) {
					return;
				}
				log.info([netDiskName, netDiskIndex, shareCode, accessCode]);
				let icon = NetDiskUI.src.icon[netDiskName];
				let uiLink = NetDisk.handleLinkShow(
					netDiskName,
					netDiskIndex,
					shareCode,
					accessCode,
					matchText
				);
				let insertDOM = this.getViewHTML(
					icon,
					netDiskName,
					netDiskIndex,
					shareCode,
					accessCode,
					uiLink
				);
				DOMUtils.append(
					NetDiskUI.Alias.uiLinkAlias.popsElement.querySelector(
						".netdisk-url-box-all"
					),
					insertDOM
				);
				NetDiskCheckLinkValidity.check(
					NetDiskUI.Alias.uiLinkAlias.popsElement.querySelector(
						".netdisk-url-box-all"
					).children[
						NetDiskUI.Alias.uiLinkAlias.popsElement.querySelector(
							".netdisk-url-box-all"
						).children.length - 1
					],
					netDiskName,
					netDiskIndex,
					shareCode,
					accessCode
				);
			},
			/**
			 * 修改已存在的view
			 * @param {string} netDiskName 网盘名称
			 * @param {number} netDiskIndex 网盘名称索引下标
			 * @param {string} shareCode 分享码
			 * @param {string} accessCode 访问码
			 * @param {string} matchText 匹配到的文本
			 */
			changeLinkView(
				netDiskName,
				netDiskIndex,
				shareCode,
				accessCode,
				matchText
			) {
				NetDiskUI.netDiskHistoryMatch.setNetDiskHistoryMatchData(
					netDiskName,
					netDiskIndex,
					shareCode,
					accessCode,
					matchText
				);
				if (!NetDiskUI.Alias.uiLinkAlias) {
					return;
				}
				let uiLink = NetDisk.handleLinkShow(
					netDiskName,
					netDiskIndex,
					shareCode,
					accessCode,
					matchText
				);
				let needChangeDOM =
					NetDiskUI.Alias.uiLinkAlias.popsElement.querySelector(
						`.netdisk-url a[data-sharecode='${shareCode}'][data-netdisk-index='${netDiskIndex}']`
					);
				log.info("修改网盘链接视图");
				log.info(needChangeDOM);
				needChangeDOM.setAttribute("data-accesscode", accessCode);
				DOMUtils.html(needChangeDOM, uiLink);
			},
			/**
			 * 设置点击图标按钮导航至该网盘链接所在网页中位置
			 */
			registerIconGotoPagePosition(target) {
				/**
				 * @type {?Generator<HTMLElement, void, any>}
				 */
				let findGenerator = void 0;
				/**
				 * @type {?IteratorResult<HTMLElement, void>}
				 */
				let iterator = void 0;
				/**
				 * 上一个的shareCode
				 */
				let prevSearchShareCode = void 0;
				DOMUtils.on(
					target,
					"click",
					".whitesevPop .netdisk-icon .netdisk-icon-img",
					function (event) {
						let dataSharecode = event.target.getAttribute("data-sharecode");
						if (
							!GM_getValue(
								"pops-netdisk-icon-click-event-find-sharecode",
								NetDiskData.iconDefaultClickEventToFindShareCode
							)
						) {
							return;
						}
						if (typeof dataSharecode !== "string") {
							Qmsg.error("获取data-sharecode属性失败");
							return;
						}
						if (prevSearchShareCode == void 0) {
							prevSearchShareCode = dataSharecode;
						} else if (prevSearchShareCode !== dataSharecode) {
							/* 切换到另一个shareCode搜索 */
							log.info(
								`上一个搜索:${prevSearchShareCode},切换至:${dataSharecode}`
							);
							findGenerator = void 0;
							iterator = void 0;
							prevSearchShareCode = dataSharecode;
						}
						if (findGenerator == void 0) {
							/* 未找到元素或者已迭代完毕 */
							findGenerator = utils.findElementsWithText(
								document.documentElement,
								dataSharecode
							);
							iterator = findGenerator.next();
						}
						if (iterator.value) {
							log.success(["定位元素", iterator]);
							if (
								iterator.value.nodeType === Node.ELEMENT_NODE &&
								iterator.value.getClientRects().length
							) {
								/* 可见 */
								/* 滚动到该元素 */
								iterator.value.scrollIntoView({
									behavior: "smooth",
									block: "center",
									inline: "nearest",
								});
								if (
									GM_getValue(
										"pops-netdisk-icon-click-event-find-sharecode-with-select",
										NetDiskData.iconDefaultClickEventToFindShareCodeWithSelect
									)
								) {
									/* 开启功能 */
									let elementText =
										iterator.value.innerText || iterator.value.textContent;
									let childTextNode = void 0;
									let startIndex = void 0;
									let endIndex = void 0;
									if (elementText.includes(dataSharecode)) {
										/* 文字包含shareCode */
										let textNodeList = Array.from(
											iterator.value.childNodes
										).filter((ele) => ele.nodeType === Node.TEXT_NODE);
										for (const textNode of textNodeList) {
											if (textNode.textContent.includes(dataSharecode)) {
												childTextNode = textNode;
												startIndex =
													textNode.textContent.indexOf(dataSharecode);
												endIndex = startIndex + dataSharecode.length;
												break;
											}
										}
									}
									try {
										utils.selectElementText(
											iterator.value,
											childTextNode,
											startIndex,
											endIndex
										);
									} catch (error) {
										log.error(error);
										utils.selectElementText(iterator.value);
									}
								}
							} else if (
								iterator.value.nodeType === Node.TEXT_NODE &&
								iterator.value.parentElement.getClientRects().length
							) {
								/* #text元素且可见 */
								if (
									GM_getValue(
										"pops-netdisk-icon-click-event-find-sharecode-with-select",
										NetDiskData.iconDefaultClickEventToFindShareCodeWithSelect
									)
								) {
									let elementText =
										iterator.value.textContent || iterator.value.nodeValue;
									let childTextNode = iterator.value;
									let startIndex = elementText.indexOf(dataSharecode);
									let endIndex = startIndex + dataSharecode.length;
									try {
										utils.selectElementText(
											iterator.value,
											childTextNode,
											startIndex,
											endIndex
										);
									} catch (error) {
										log.error(error);
										utils.selectElementText(iterator.value.parentElement);
									}
									let selection = globalThis.getSelection();
									if (selection.rangeCount > 0) {
										let range = selection.getRangeAt(0);
										let rect = range.getBoundingClientRect();
										let scrollYOffset = globalThis.scrollY;
										/* 居中定位 */
										let position =
											rect.top + scrollYOffset - globalThis.innerHeight / 2;
										globalThis.scrollTo({
											behavior: "smooth",
											top: position,
										});
									} else {
										iterator.value.parentElement.scrollIntoView({
											behavior: "smooth",
											block: "center",
											inline: "nearest",
										});
									}
								} else {
									try {
										let range = new Range();
										range.selectNodeContents(iterator.value);
										let rect = range.getBoundingClientRect();
										let scrollYOffset = globalThis.scrollY;
										/* 居中定位 */
										let position =
											rect.top + scrollYOffset - globalThis.innerHeight / 2;
										globalThis.scrollTo({
											behavior: "smooth",
											top: position,
										});
									} catch (error) {
										log.error(error);
										iterator.value.parentElement.scrollIntoView({
											behavior: "smooth",
											block: "center",
											inline: "nearest",
										});
									}
								}
							} else {
								log.error(["无法定位该元素位置", iterator.value]);
								Qmsg.error(
									`无法定位该元素位置,类型:<${(
										iterator.value.nodeName ||
										iterator.value.localName ||
										iterator.value.tagName
									).toLowerCase()}>`,
									{
										html: false,
									}
								);
							}
						}

						iterator = findGenerator.next();
						if (iterator.done) {
							/* 循环查找 */
							if (
								!GM_getValue(
									"pops-netdisk-icon-click-event-loop-find-sharecode",
									NetDiskData.iconDefaultClickEventToFindShareCodeByLoop
								)
							) {
								Qmsg.info("已经定位至最后一个元素了");
								return;
							}
							findGenerator = void 0;
							iterator = void 0;
						}
					}
				);
			},
		},
		/**
		 * 显示直链的弹窗
		 */
		staticView: {
			getCSS() {
				return `
        .pops-folder-list .list-name-text{
          max-width: 300px;
        }
        .netdisk-static-link-onefile .pops-folder-list .list-name-text{
          max-width: 220px;
        }
        .netdisk-static-link-onefile .pops-mobile-folder-content .pops-folder-list .list-name-text{
          max-width: unset;
        }
        `;
			},
			/**
			 * 单文件直链弹窗
			 * @param {{
			 * title: string,
			 * fileName: string,
			 * fileType: ?string,
			 * fileSize: ?string,
			 * downloadUrl: string,
			 * fileUploadTime: ?string,
			 * fileLatestTime: ?string
			 * clickCallBack: ?(_fileDetails_:{
			 *    title:string,
			 *    fileName:string,
			 *    fileType:?string,
			 *    fileSize:?string,
			 *    downloadUrl:string,
			 *    fileUploadTime:?string,
			 *    fileLatestTime:?string,
			 * })=>{}
			 * }} fileDetails 配置
			 */
			oneFile(fileDetails) {
				log.success(["成功获取单文件直链", fileDetails]);
				NetDiskPops.folder(
					{
						title: {
							text: fileDetails.title,
						},
						folder: [
							{
								fileName: fileDetails.fileName,
								fileSize: fileDetails.fileSize,
								fileType: fileDetails.fileType ?? "",
								createTime:
									fileDetails.fileUploadTime || fileDetails.fileLatestTime,
								latestTime:
									fileDetails.fileLatestTime || fileDetails.fileUploadTime,
								isFolder: false,
								index: 0,
								async clickEvent() {
									if (typeof fileDetails.clickCallBack === "function") {
										fileDetails.clickCallBack(fileDetails);
									} else {
										return {
											autoDownload: true,
											mode: "aBlank",
											url: fileDetails.downloadUrl,
										};
									}
								},
							},
						],
						btn: {
							ok: {
								text: "下载",
								callback() {
									if (typeof fileDetails.clickCallBack === "function") {
										fileDetails.clickCallBack(fileDetails);
									} else {
										window.open(fileDetails.downloadUrl, "_blank");
									}
								},
							},
						},
						class: "netdisk-static-link-onefile",
						style: this.getCSS(),
					},
					NetDiskUI.popsStyle.oneFileStaticView
				);
			},
			/**
			 * 多文件直链弹窗
			 * @param {string} title 标题
			 * @param {?{
			 * fileName: string,
			 * fileSize: string|number,
			 * fileType: ?string,
			 * createTime: ?string,
			 * latestTime: ?string,
			 * isFolder: boolean,
			 * index: ?number,
			 * clickCallBack: ?(event:Event,_config_: object)=>{}
			 * }[]} [folderInfoList=[]] 文件夹信息
			 */
			moreFile(title, folderInfoList = []) {
				log.success(["文件解析信息", folderInfoList]);
				NetDiskPops.folder(
					{
						title: {
							text: title,
						},
						folder: folderInfoList,
						style: this.getCSS(),
					},
					NetDiskUI.popsStyle.moreFileStaticView
				);
			},
		},
		/**
		 * 需要重新输入新密码的弹窗
		 * @param {string} [title="密码错误"] 标题
		 * @param {string} [netDiskName=""] 网盘名称
		 * @param {number} netDiskIndex 网盘名称索引下标
		 * @param {string} shareCode
		 * @param {Function} [okCallBack=()=>{}]
		 */
		newAccessCodeView(
			title = "密码错误",
			netDiskName = "",
			netDiskIndex,
			shareCode,
			okCallBack = () => {}
		) {
			const accessCodeConfirm = NetDiskPops.prompt(
				{
					title: {
						text: title,
						position: "center",
						html: false,
					},
					btn: {
						reverse: true,
						position: "end",
						cancel: {
							text: "取消",
						},
						ok: {
							callback: (event) => {
								/* 把输入的新密码去空格 */
								let userInputAccessCode = event.text.replace(/[\s]*/gi, "");
								/* 处理已显示的链接 */
								let uiLink = NetDisk.handleLinkShow(
									netDiskName,
									netDiskIndex,
									shareCode,
									userInputAccessCode,
									void 0
								);
								let currentItemSelector = `.netdisk-url a[data-netdisk='${netDiskName}'][data-sharecode='${shareCode}']`;
								let currentHistoryItemSelector = `.netdiskrecord-link a[data-netdisk='${netDiskName}'][data-sharecode='${shareCode}']`;
								let currentItemElement =
									NetDiskUI.Alias.uiLinkAlias?.$shadowRoot?.querySelector(
										currentItemSelector
									);
								let currentHistoryItemElement =
									NetDiskUI.Alias.historyAlias?.$shadowRoot?.querySelector(
										currentHistoryItemSelector
									);
								if (currentItemElement) {
									currentItemElement.setAttribute(
										"data-accesscode",
										userInputAccessCode
									);
									DOMUtils.html(currentItemElement, uiLink);
								}
								/* 历史记录的弹出的 */
								if (currentHistoryItemElement) {
									currentHistoryItemElement.setAttribute(
										"data-accesscode",
										userInputAccessCode
									);
									DOMUtils.html(currentHistoryItemElement, uiLink);
								}

								log.info(
									`${netDiskName} 重新输入的密码:${userInputAccessCode}`
								);
								okCallBack(userInputAccessCode);
								event.close();
							},
						},
					},
					content: {
						placeholder: "请重新输入密码",
						focus: true,
					},
				},
				NetDiskUI.popsStyle.inputNewAccessCodeView
			);
			/**
			 * 注册键盘回车事件
			 */
			utils.listenKeyboard(
				accessCodeConfirm.$shadowRoot,
				"keypress",
				(keyName) => {
					if (keyName === "Enter") {
						accessCodeConfirm.$shadowRoot
							.querySelector(".pops-prompt-btn-ok")
							?.click();
					}
				}
			);
		},
		/**
		 * 网盘历史匹配到的记录弹窗
		 */
		netDiskHistoryMatch: {
			/**
			 * 本地存储的keyName
			 */
			storageKey: "netDiskHistoryMatch",
			/**
			 * 是否已设置其它DOM事件
			 */
			isSetOtherEvent: false,
			/**
			 * 分页
			 */
			dataPaging: void 0,
			/**
			 * 显示弹窗
			 */
			show() {
				let data = this.getNetDiskHistoryMatchData();
				let dataHTML = "";
				let that = this;
				data = this.orderNetDiskHistoryMatchData(data);
				for (let index = 0; index < 10; index++) {
					if (data[index]) {
						dataHTML += that.getTableHTML(data[index]);
					}
				}
				dataHTML = `
        <div class="netdiskrecord-search">
          <input type="text" placeholder="搜索链接/网址/网址标题,可正则搜索">
        </div>
        <div class="netdiskrecord-table"><ul>${dataHTML}</ul></div>
        <div class="netdiskrecord-page">

        </div>`;
				NetDiskUI.Alias.historyAlias = NetDiskPops.confirm(
					{
						title: {
							text: "历史匹配记录",
							position: "center",
						},
						content: {
							text: dataHTML,
							html: true,
						},
						btn: {
							reverse: true,
							position: "space-between",
							ok: {
								enable: true,
								callback(event) {
									event.close();
									NetDiskUI.Alias.historyAlias = void 0;
								},
							},
							close: {
								callback(event) {
									event.close();
									NetDiskUI.Alias.historyAlias = void 0;
								},
							},
							cancel: {
								enable: false,
							},
							other: {
								enable: true,
								text: `清空所有(${data.length})`,
								type: "xiaomi-primary",
								callback: (event) => {
									NetDiskPops.confirm({
										title: {
											text: "删除",
											position: "center",
										},
										content: {
											text: "确定清空所有的记录?",
											html: false,
										},
										btn: {
											ok: {
												enable: true,
												callback(okEvent) {
													that.clearNetDiskHistoryMatchData();
													DOMUtils.remove(
														NetDiskUI.Alias.historyAlias.$shadowRoot.querySelectorAll(
															".whitesevPopNetDiskHistoryMatch .pops-confirm-content ul li"
														)
													);
													okEvent.close();
													DOMUtils.html(
														NetDiskUI.Alias.historyAlias.$shadowRoot.querySelector(
															".whitesevPopNetDiskHistoryMatch .netdiskrecord-page"
														),
														""
													);
													DOMUtils.text(
														NetDiskUI.Alias.historyAlias.$shadowRoot.querySelector(
															".whitesevPopNetDiskHistoryMatch .pops-confirm-btn-other"
														),
														DOMUtils.text(
															NetDiskUI.Alias.historyAlias.$shadowRoot.querySelector(
																".whitesevPopNetDiskHistoryMatch .pops-confirm-btn-other"
															)
														).replace(/[\d]+/gi, "0")
													);
												},
											},
											cancel: {
												text: "取消",
												enable: true,
											},
										},
									});
								},
							},
						},
						mask: {
							clickCallBack(originalRun) {
								originalRun();
								NetDiskUI.Alias.historyAlias = null;
							},
						},
						class: "whitesevPopNetDiskHistoryMatch",
						style: this.getCSS(),
					},
					NetDiskUI.popsStyle.historyMatchView
				);
				this.setDataPaging(data);
				this.setEvent(NetDiskUI.Alias.historyAlias.$shadowRoot);
				this.setSearchEvent();
				NetDiskUI.setRightClickMenu(
					NetDiskUI.Alias.historyAlias.$shadowRoot.querySelector(
						".whitesevPopNetDiskHistoryMatch"
					),
					".netdiskrecord-link a",
					true
				);
			},
			/**
			 * 获取CSS
			 */
			getCSS() {
				return `
        .whitesevPopNetDiskHistoryMatch .pops-confirm-content ul{

        }
        .whitesevPopNetDiskHistoryMatch .pops-confirm-content li{
          display: flex;
          flex-direction: column;
          justify-content: center;
          border-radius: 10px;
          box-shadow: 0 0.3px 0.6px rgb(0 0 0 / 6%), 0 0.7px 1.3px rgb(0 0 0 / 8%), 0 1.3px 2.5px rgb(0 0 0 / 10%), 0 2.2px 4.5px rgb(0 0 0 / 12%), 0 4.2px 8.4px rgb(0 0 0 / 14%), 0 10px 20px rgb(0 0 0 / 20%);
          margin: 20px 10px;
          padding: 10px;
        }
        .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-search{
          height: 11%;
        }
        .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-table{
          height: calc( 85% - 40px);
          overflow: auto;
        }
        .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-page{
          display: flex;
          justify-content: center;
          align-items: center;
          margin-top: 10px;
        }
        .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-search input{
          border: none;
          border-bottom: 1px solid #000000;
          padding: 0px 5px;
          line-height: 28px;
          width: -moz-available;
          width: -webkit-fill-available;
          width: fill-available;
          margin: 5px 5px 0px 5px;
          background: none;
        }
        .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-search input:focus-visible{
          outline: none;
          border-bottom: 1px solid #0009ff;
        }
        .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-link{
          
        }
        .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-link a{
          color: #ff4848;
          font-size: 0.8em;
          border: none;
          word-break: break-word;
        }
        .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-link a[isvisited=true]{
          color: #8b8888;
        }
        .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-icon{
          
        }
        .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-icon .netdisk-icon-img{
          width: 28px;
          height: 28px;
          min-width: 28px;
          min-height: 28px;
          font-size: 0.8em;
          border-radius: 10px;
          box-shadow: 0 0.3px 0.6px rgb(0 0 0 / 6%), 0 0.7px 1.3px rgb(0 0 0 / 8%), 0 1.3px 2.5px rgb(0 0 0 / 10%), 0 2.2px 4.5px rgb(0 0 0 / 12%), 0 4.2px 8.4px rgb(0 0 0 / 14%), 0 10px 20px rgb(0 0 0 / 20%);
        }
        .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-url{
          color: #000;
        }
        .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-top-url{
          color: #000;
        }
        .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-functions button.btn-delete{
          background: #263cf3;
          color: #fff;
        }
        .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-functions button.btn-delete:active{
          background: #6e7be8;
        }
        .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-link,
        .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-icon,
        .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-url,
        .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-top-url,
        .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-add-time,
        .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-update-time,
        .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-url-title,
        .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-functions{
          display: flex;
          margin: 5px 0px;
        }
        .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-link p,
        .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-icon p,
        .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-url p,
        .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-top-url p,
        .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-add-time p,
        .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-update-time p,
        .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-url-title p,
        .whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-functions p{
          min-width: 80px;
          max-width: 80px;
          align-self: center;
        }
        `;
			},
			/**
			 * 获取显示出的每一项的html
			 * @param {NetDiskHistoryDataOption} data
			 * @returns {string}
			 */
			getTableHTML(data) {
				let netDiskURL = NetDisk.handleLinkShow(
					data.netDiskName,
					data.netDiskIndex,
					data.shareCode,
					data.accessCode,
					data.matchText
				);
				return `
        <li>
          <div class="netdiskrecord-link">
            <p>链接</p>
            <a  href="javascript:;"
                isvisited="false"
                data-netdisk="${data.netDiskName}"
                data-netdisk-index="${data.netDiskIndex}"
                data-sharecode="${data.shareCode}"
                data-accesscode="${data.accessCode}"
                data-open-enable-key="${data.netDiskName}-open-enable"
                data-static-enable-key="${data.netDiskName}-static-enable"
                data-forward-scheme-key="${
									data.netDiskName
								}-forward-scheme-enable">${netDiskURL}</a>
          </div>
          <div class="netdiskrecord-icon">
            <p>网盘</p>
            <div class="netdisk-icon-img" style="background: url(${
							NetDiskUI.src.icon[data.netDiskName]
						}) no-repeat;background-size:100%"></div>
          </div>
          ${
						data.url === data.topURL
							? `
          <div class="netdiskrecord-url">
            <p>网址</p>
            <a href="${data.url}" target="_blank">${data.url}</a>
          </div>
          `
							: `
          <div class="netdiskrecord-url">
            <p>网址</p>
            <a href="${data.url}" target="_blank">${data.url}</a>
          </div>
          <div class="netdiskrecord-top-url">
            <p>TOP网址</p>
            <a href="${data.topURL}" target="_blank">${data.topURL}</a>
          </div>
          `
					}
          <div class="netdiskrecord-url-title">
            <p>网址标题</p>
            ${data.title}
          </div>
          <div class="netdiskrecord-add-time">
            <p>记录时间</p>
            ${utils.formatTime(data.addTime)}
          </div>
          <div class="netdiskrecord-update-time">
            <p>更新时间</p>
            ${utils.formatTime(data.updateTime)}
          </div>
          <div class="netdiskrecord-functions">
            <p>功能</p>
            <button class="btn-delete" data-json='${JSON.stringify(
							data
						)}'>删除</button>
          </div>
        </li>`;
			},
			/**
			 * 设置只执行一次的事件
			 * @param {HTMLElement} target
			 */
			setEvent(target) {
				let that = this;
				NetDiskUI.view.setNetDiskUrlClickEvent(
					target,
					".whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-link a"
				);

				/**
				 * 设置删除按钮点击事件
				 */
				DOMUtils.on(
					target,
					"click",
					".whitesevPopNetDiskHistoryMatch .pops-confirm-content .netdiskrecord-functions button.btn-delete",
					function (event) {
						/* 删除中的遮罩层 */
						let deleteLoading = NetDiskPops.loading({
							parent: target.querySelector(
								".whitesevPopNetDiskHistoryMatch .pops-confirm-content ul"
							),
							content: {
								text: "删除中...",
							},
							only: true,
							addIndexCSS: false,
						});
						let clickNode = event.target;
						let dataJSON = clickNode.getAttribute("data-json");
						clickNode.closest("li")?.remove();
						that.deleteNetDiskHistoryMatchData(dataJSON);
						deleteLoading?.close();
						let totalNumberText = DOMUtils.text(
							target.querySelector(
								".whitesevPopNetDiskHistoryMatch .pops-confirm-btn-other"
							)
						);
						let totalNumber = totalNumberText.match(/[\d]+/gi);
						totalNumber = parseInt(totalNumber[totalNumber.length - 1]);
						totalNumber--;
						totalNumberText = totalNumberText.replace(/[\d]+/gi, totalNumber);
						DOMUtils.text(
							target.querySelector(
								".whitesevPopNetDiskHistoryMatch .pops-confirm-btn-other"
							),
							totalNumberText
						);
						let data = that.getNetDiskHistoryMatchData();
						data = that.orderNetDiskHistoryMatchData(data);
						that.dataPaging.refresh(data);
						that.pageChangeCallBack(data, that.dataPaging.CONFIG.currentPage);
					}
				);
			},
			/**
			 * @param {object[]} data
			 * @param {number} page
			 */
			pageChangeCallBack(data, page) {
				let startIndex = (page - 1) * 10;
				let dataHTML = "";
				for (let index = 0; index < 10; index++) {
					if (data[startIndex]) {
						dataHTML += this.getTableHTML(data[startIndex]);
					} else {
						break;
					}
					startIndex++;
				}
				NetDiskUI.Alias.historyAlias.$shadowRoot
					.querySelectorAll(
						".whitesevPopNetDiskHistoryMatch .netdiskrecord-table ul li"
					)
					.forEach((ele) => ele.remove());
				DOMUtils.append(
					NetDiskUI.Alias.historyAlias.$shadowRoot.querySelector(
						".whitesevPopNetDiskHistoryMatch .netdiskrecord-table ul"
					),
					dataHTML
				);
			},
			/**
			 * 设置分页
			 * @param {NetDiskHistoryDataOption} data
			 */
			setDataPaging(data) {
				let that = this;
				this.dataPaging = new DataPaging({
					data: data,
					pageCount: 10,
					pageStep: pops.isPhone() ? 2 : 4,
					currentPage: 1,
					pageChangeCallBack: function (page) {
						that.pageChangeCallBack(data, page);
					},
				});
				this.dataPaging.addCSS(NetDiskUI.Alias.historyAlias.$shadowRoot);
				this.dataPaging.append(
					NetDiskUI.Alias.historyAlias.$shadowRoot.querySelector(
						".whitesevPopNetDiskHistoryMatch .netdiskrecord-page"
					)
				);
			},
			/**
			 * 设置搜索框的回车事件
			 */
			setSearchEvent() {
				let isSeaching = false; /* 当前搜索的状态 */
				let searchLoading = void 0; /* 搜索中的遮罩层 */
				let that = this;
				function searchEvent() {
					if (isSeaching) {
						return;
					}
					isSeaching = true;
					searchLoading = NetDiskPops.loading({
						parent: NetDiskUI.Alias.historyAlias.$shadowRoot.querySelector(
							".whitesevPopNetDiskHistoryMatch .pops-confirm-content ul"
						),
						content: {
							text: "搜索中...",
						},
						only: true,
						addIndexCSS: false,
					});
					let inputText = NetDiskUI.Alias.historyAlias.$shadowRoot
						.querySelector(
							".whitesevPopNetDiskHistoryMatch .netdiskrecord-search input"
						)
						.value.trim();
					let data = that.getNetDiskHistoryMatchData();
					data = that.orderNetDiskHistoryMatchData(data);
					if (inputText === "") {
						/* 输入空就关闭遮罩层且恢复style */
						let historyDataHTML = "";
						data.forEach((item, index) => {
							if (index > 9) {
								return;
							}
							historyDataHTML += that.getTableHTML(item);
						});
						NetDiskUI.Alias.historyAlias.$shadowRoot
							.querySelectorAll(
								".whitesevPopNetDiskHistoryMatch .netdiskrecord-table ul li"
							)
							.forEach((ele) => ele.remove());
						DOMUtils.append(
							NetDiskUI.Alias.historyAlias.$shadowRoot.querySelector(
								".whitesevPopNetDiskHistoryMatch .netdiskrecord-table ul"
							),
							historyDataHTML
						);
						searchLoading?.close();
						isSeaching = false;
						that.setDataPaging(data);
						return;
					}
					let isFind = false; /* 找到的状态 */

					let isFindHTML = ""; /* 找到的链接文本 */
					data.forEach((item) => {
						let netDiskURL = NetDisk.handleLinkShow(
							item.netDiskName,
							item.netDiskIndex,
							item.shareCode,
							item.accessCode,
							item.matchText
						);
						if (
							netDiskURL.match(new RegExp(inputText, "ig")) ||
							item.url.match(new RegExp(inputText, "ig")) ||
							item.topURL.match(new RegExp(inputText, "ig")) ||
							item.title.match(new RegExp(inputText, "ig"))
						) {
							/* 匹配到 */
							isFind = true;
							isFindHTML += that.getTableHTML(item);
						}
					});
					DOMUtils.remove(
						NetDiskUI.Alias.historyAlias.$shadowRoot.querySelectorAll(
							".whitesevPopNetDiskHistoryMatch .netdiskrecord-table ul li"
						)
					);
					DOMUtils.append(
						NetDiskUI.Alias.historyAlias.$shadowRoot.querySelector(
							".whitesevPopNetDiskHistoryMatch .netdiskrecord-table ul"
						),
						isFindHTML
					);
					DOMUtils.remove(
						NetDiskUI.Alias.historyAlias.$shadowRoot.querySelectorAll(
							".whitesevPopNetDiskHistoryMatch .netdiskrecord-page > *"
						)
					);
					searchLoading?.close();
					searchLoading = void 0;
					isSeaching = false;
				}

				utils.listenKeyboard(
					NetDiskUI.Alias.historyAlias.$shadowRoot.querySelector(
						".whitesevPopNetDiskHistoryMatch .netdiskrecord-search input"
					),
					"keypress",
					(keyName) => {
						if (keyName === "Enter") {
							searchEvent();
						}
					}
				);
			},
			/**
			 * 排序数据
			 * @returns {NetDiskHistoryDataOption[]}
			 */
			orderNetDiskHistoryMatchData(data) {
				let localOrder = GM_getValue(
					"netdisk-history-match-ordering-rule",
					"按 更新时间 - 降序"
				);
				let isDesc =
					localOrder.indexOf("降序") !== -1 ? true : false; /* 降序 */
				let orderField =
					localOrder.indexOf("记录时间") !== -1
						? "addTime"
						: "updateTime"; /* 排序字段 */

				utils.sortListByProperty(
					data,
					(item) => {
						return item[orderField];
					},
					isDesc
				);
				return data;
			},
			/**
			 * 存储匹配到的链接
			 * @param {string} netDiskName 网盘名称
			 * @param {number} netDiskIndex 网盘名称索引下标
			 * @param {string} shareCode 分享码
			 * @param {string} accessCode 访问码
			 * @param {string} matchText 匹配到的文本
			 * @returns
			 */
			setNetDiskHistoryMatchData(
				netDiskName,
				netDiskIndex,
				shareCode,
				accessCode,
				matchText
			) {
				if (!GM_getValue("saveMatchNetDisk", false)) {
					return;
				}
				let localData = this.getNetDiskHistoryMatchData();
				for (let index = 0; index < localData.length; index++) {
					const data = localData[index];
					if (
						data.url === window.location.href &&
						data.topURL === top.window.location.href &&
						data.netDiskName === netDiskName &&
						shareCode.startsWith(data.shareCode) &&
						data.netDiskIndex === netDiskIndex
					) {
						if (data.matchText !== matchText) {
							/* 修改/设置新的matchText */
							log.success(["匹配历史记录 -> 设置新的matchText", [matchText]]);
							localData[index].matchText = matchText;
							localData[index].updateTime = Date.now();
							if (localData[index].title) {
								localData[index].title = document.title;
							}
							GM_setValue(this.storageKey, localData);
							return;
						}
						if (data.accessCode !== accessCode) {
							/* 修改accessCode */
							log.success("匹配历史记录 -> 修改accessCode");
							localData[index].accessCode = accessCode;
							localData[index].updateTime = Date.now();
							if (localData[index].title) {
								localData[index].title = document.title;
							}
							GM_setValue(this.storageKey, localData);
							return;
						}
						if (data.accessCode === accessCode) {
							/* 已存在一模一样的 */
							return;
						}
					}
				}
				log.success("匹配历史记录 -> 增加新的");
				let time = Date.now();
				localData = [
					...localData,
					{
						url: window.location.href,
						topURL: top.window.location.href,
						netDiskName: netDiskName,
						netDiskIndex: netDiskIndex,
						shareCode: shareCode,
						accessCode,
						addTime: time,
						updateTime: time,
						title: document.title || top.document.title,
						matchText: matchText,
					},
				];
				GM_setValue(this.storageKey, localData);
			},
			/**
			 * 获取历史匹配到的链接
			 * @returns {NetDiskHistoryDataOption[]}
			 */
			getNetDiskHistoryMatchData() {
				let data = GM_getValue(this.storageKey);
				if (data == void 0) {
					data = [];
					GM_setValue(this.storageKey, data);
				}
				return data;
			},
			/**
			 * 检测并尝试修复本地的数据
			 */
			checkAndRepairLocalData() {
				let repairCount = 0;
				let data = GM_getValue(this.storageKey);
				if (Array.isArray(data)) {
					for (let index = 0; index < data.length; index++) {
						const itemData = data[index];
						if (typeof itemData["matchText"] !== "string") {
							itemData["matchText"] = "";
							repairCount++;
						}
					}
				} else {
					data = [];
				}
				GM_setValue(this.storageKey, data);
				return {
					count: data.length,
					repairCount: repairCount,
				};
			},
			/**
			 * 删除存储的某个项
			 * @param {string} dataJSONText
			 */
			deleteNetDiskHistoryMatchData(dataJSONText) {
				let isSuccess = false;
				let data = this.getNetDiskHistoryMatchData();
				for (let index = 0; index < data.length; index++) {
					if (JSON.stringify(data[index]) === dataJSONText) {
						log.success("删除 ===> ", data[index]);
						data.splice(index, 1);
						isSuccess = true;
						break;
					}
				}
				if (isSuccess) {
					GM_setValue(this.storageKey, data);
				}
				return isSuccess;
			},
			/**
			 * 清空所有配置
			 */
			clearNetDiskHistoryMatchData() {
				GM_setValue(this.storageKey, []);
			},
		},
		/**
		 * 自定义访问码规则,用于设置某个网站下的某个网盘链接的固定访问码
		 */
		accessCodeRule: {
			/**
			 * 弹窗的className
			 */
			accessCodeRuleDialogClassName: "whitesevPopNetDiskAccessCodeRule",
			/**
			 * 显示弹窗
			 */
			show() {
				let that = this;
				let popsConfirm = NetDiskPops.confirm(
					{
						title: {
							text: "自定义访问码规则",
							position: "center",
						},
						content: {
							text: /*html*/ `
							<div class="netdisk-accesscode-rule-table">
								<ul>
								${that.getShowItemHTML()}
								</ul>
							</div>
							`,
							html: true,
						},
						btn: {
							merge: true,
							reverse: false,
							position: "space-between",
							ok: {
								enable: true,
								text: "添加",
								callback(event) {
									that.showRule(event);
								},
							},
							close: {
								callback(event) {
									event.close();
								},
							},
							cancel: {
								enable: true,
							},
							other: {
								enable: true,
								type: "xiaomi-primary",
								text: `清空所有`,
								callback(event) {
									NetDiskPops.confirm({
										title: {
											text: "删除",
											position: "center",
										},
										content: {
											text: "确定清空所有的规则?",
											html: false,
										},
										btn: {
											ok: {
												enable: true,
												callback: function (okEvent) {
													log.success("清空所有");
													that.deleteAllValue();
													if (that.getValue().length) {
														Qmsg.error("清空全部规则失败");
														return;
													} else {
														Qmsg.success("已清空全部规则");
													}
													that.setDeleteAllBtnText(event.animElement);
													event.animElement.querySelector(
														".pops-confirm-content ul"
													).innerHTML = "";
													okEvent.close();
												},
											},
											cancel: {
												text: "取消",
												enable: true,
											},
										},
									});
								},
							},
						},
						class: this.accessCodeRuleDialogClassName,
						style: this.getCSS(),
					},
					NetDiskUI.popsStyle.accessCodeRuleView
				);
				that.setDeleteAllBtnText(popsConfirm.animElement);
				this.setEvent(popsConfirm);
			},
			getShowItemHTML() {
				let result = "";
				this.getValue().forEach((item) => {
					let netdiskName = "";
					item.netdisk.forEach((_netdisk_) => {
						netdiskName += _netdisk_.name;
						netdiskName += "、";
					});
					netdiskName = netdiskName.replace(/、$/g, "");
					result += /*html*/ `
					<li>
						<div class="accesscode-rule-url-regexp">
						<p>匹配规则</p>
						${item.urlRegexp}
						</div>
						<div class="accesscode-rule-netdisk-name">
						<p>匹配网盘</p>
						${netdiskName}
						</div>
						<div class="accesscode-rule-accesscode">
						<p>固定值</p>
						${item.accessCode}
						</div>
						<div class="accesscode-rule-functions" data-json='${JSON.stringify(item)}'>
						<p>功能</p>
						<button style="background: #46cb31;color: #fff;" data-edit>修改</button>
						<button style="background: #263cf3;color: #fff;" data-delete>删除</button>
						</div>
					</li>
          			`;
				});
				return result;
			},
			getCSS() {
				return /*css*/ `
			.pops-confirm-content .whitesev-accesscode-rule{
				display: flex;
				align-items: center;
				justify-content: space-between;
				margin: 15px 15px;
			}
			
			.pops-confirm-content div.netdisk-accesscode-rule-table{
				/* height: calc( 85% - 40px); */
				overflow: auto;
			}

			.pops-confirm-content .netdisk-accesscode-rule-table .accesscode-rule-url-regexp,
			.pops-confirm-content .netdisk-accesscode-rule-table .accesscode-rule-netdisk-name,
			.pops-confirm-content .netdisk-accesscode-rule-table .accesscode-rule-accesscode,
			.pops-confirm-content .netdisk-accesscode-rule-table .accesscode-rule-functions{
				display: flex;
				margin: 5px 0px;
			}

			.pops-confirm-content .netdisk-accesscode-rule-table .accesscode-rule-url-regexp p,
			.pops-confirm-content .netdisk-accesscode-rule-table .accesscode-rule-netdisk-name p,
			.pops-confirm-content .netdisk-accesscode-rule-table .accesscode-rule-accesscode p,
			.pops-confirm-content .netdisk-accesscode-rule-table .accesscode-rule-functions p{
				min-width: 80px;
				max-width: 80px;
				align-self: center;
			}
			.pops-confirm-content .netdisk-accesscode-rule-table li {
				display: flex;
				flex-direction: column;
				justify-content: center;
				border-radius: 10px;
				box-shadow: 0 0.3px 0.6px rgb(0 0 0 / 6%), 0 0.7px 1.3px rgb(0 0 0 / 8%), 0 1.3px 2.5px rgb(0 0 0 / 10%), 0 2.2px 4.5px rgb(0 0 0 / 12%), 0 4.2px 8.4px rgb(0 0 0 / 14%), 0 10px 20px rgb(0 0 0 / 20%);
				margin: 20px 10px;
				padding: 10px;
			}
			`;
			},
			/**
			 * 显示规则弹窗进行添加/修改
			 * @param {object} mainEvent
			 * @param {boolean} isEdit 是否是修改模式
			 * @param {{
			 * urlRegexp: string,
			 * netdisk: {
			 *  name:string,
			 *  value:string,
			 * }[],
			 * accessCode: string,
			 * }} oldValue 当isEdie为true时传入的值
			 */
			showRule(mainEvent, isEdit = false, oldValue) {
				let that = this;
				let popsConfirm = NetDiskPops.confirm(
					{
						title: {
							text: isEdit ? "修改规则" : "添加规则",
							position: "center",
						},
						content: {
							text: /*html*/ `
							<div class="whitesev-accesscode-rule">
								<div type-name>匹配网站</div>
								<div class="pops-panel-input">
								<input type="text" placeholder="请输入需要匹配的正则规则" val-key="access-rule-url" />
								</div>
							</div>
							<div class="whitesev-accesscode-rule">
								<div>匹配网盘</div>
								<div class="pops-panel-select">
								<select val-key="access-rule-netdisk" multiple="true" style="height: auto;">
									<option data-value="baidu">百度网盘</option>
									<option data-value="lanzou">蓝奏云</option>
									<option data-value="tianyiyun">天翼云</option>
									<option data-value="hecaiyun">中国移动云盘</option>
									<option data-value="aliyun">阿里云</option>
									<option data-value="wenshushu">文叔叔</option>
									<option data-value="nainiu">奶牛</option>
									<option data-value="_123pan">123盘</option>
									<option data-value="weiyun">微云</option>
									<option data-value="xunlei">迅雷云盘</option>
									<option data-value="_115pan">115网盘</option>
									<option data-value="chengtong">城通网盘</option>
									<option data-value="kuake">夸克网盘</option>
									<option data-value="jianguoyun">坚果云</option>
									<option data-value="onedrive">OneDrive</option>
								</select>
								</div>
							</div>
							<div class="whitesev-accesscode-rule">
								<div>固定值</div>
								<div class="pops-panel-input">
								<input type="text" placeholder="请输入固定的访问码" val-key="access-rule-accesscode" />
								</div>
							</div>
							`,
							html: true,
						},
						btn: {
							ok: {
								enable: true,
								text: isEdit ? "修改" : "添加",
								callback(event) {
									let accessRuleUrl = event.popsElement.querySelector(
										'input[val-key="access-rule-url"]'
									).value;
									/**
									 * @type {{name:string,value:string}[]}
									 */
									let accessRuleNetDisk = [];
									let accessRuleNetDiskElement =
										event.popsElement.querySelector(
											'select[val-key="access-rule-netdisk"]'
										);
									Array.from(accessRuleNetDiskElement.selectedOptions).forEach(
										(item) => {
											accessRuleNetDisk.push({
												name: item.value,
												value: item.getAttribute("data-value"),
											});
										}
									);
									let accessRuleAccessCode = event.popsElement.querySelector(
										'input[val-key="access-rule-accesscode"]'
									).value;
									if (!that.checkRuleUrlValid(accessRuleUrl)) {
										log.error(["验证失败", accessRuleUrl]);
										return;
									}
									if (isEdit) {
										/* 编辑 */
										if (
											that.changeValue(oldValue, {
												urlRegexp: accessRuleUrl,
												netdisk: accessRuleNetDisk,
												accessCode: accessRuleAccessCode,
											})
										) {
											log.success([
												"修改成功",
												{
													urlRegexp: accessRuleUrl,
													netdisk: accessRuleNetDisk,
													accessCode: accessRuleAccessCode,
												},
											]);
											Qmsg.success("修改成功");
											mainEvent.animElement.querySelector(
												".netdisk-accesscode-rule-table ul"
											).innerHTML = that.getShowItemHTML();
											popsConfirm.close();
										} else {
											Qmsg.error("修改失败");
										}
									} else {
										/* 添加 */
										if (
											that.addValue({
												urlRegexp: accessRuleUrl,
												netdisk: accessRuleNetDisk,
												accessCode: accessRuleAccessCode,
											})
										) {
											Qmsg.success("添加成功");
											mainEvent.animElement.querySelector(
												".netdisk-accesscode-rule-table ul"
											).innerHTML = that.getShowItemHTML();
											that.setDeleteAllBtnText(mainEvent.animElement);
											popsConfirm.close();
										} else {
											Qmsg.error("已存在重复的规则");
										}
									}
								},
							},
							cancel: {
								text: "取消",
								enable: true,
							},
						},
						class: "whitesevPopNetDiskAccessCodeRuleAddOrEdit",
						style: /*css*/ `
						${pops.config.cssText.panelCSS}

						.whitesevPopNetDiskAccessCodeRuleAddOrEdit .whitesev-accesscode-rule{
							display: flex;
							justify-content: space-between;
							margin: 4px 4px;
						}
						.whitesevPopNetDiskAccessCodeRuleAddOrEdit .whitesev-accesscode-rule select{
							height: 150px;
						}
						`,
					},
					NetDiskUI.popsStyle.accessCodeRuleEditView
				);
				this.setRuleEvent(popsConfirm.element);
				if (isEdit) {
					popsConfirm.element.querySelector(
						'.whitesev-accesscode-rule input[val-key="access-rule-url"]'
					).value = oldValue.urlRegexp;
					let optionElement = popsConfirm.element.querySelectorAll(
						'.whitesev-accesscode-rule select[val-key="access-rule-netdisk"] option'
					);
					oldValue.netdisk.forEach((item) => {
						optionElement.forEach((element) => {
							if (element.getAttribute("data-value") === item.value) {
								element.selected = true;
								log.success(["选中", element]);
								return;
							}
						});
					});
					popsConfirm.element.querySelector(
						'.whitesev-accesscode-rule input[val-key="access-rule-accesscode"]'
					).value = oldValue.accessCode;
				}
			},
			/**
			 * 修改 删除所有(xx)的文字
			 * @param {HTMLElement} element
			 */
			setDeleteAllBtnText(element) {
				if (
					element.querySelector(
						".pops-confirm-btn button.pops-confirm-btn-other"
					)
				) {
					element.querySelector(
						".pops-confirm-btn button.pops-confirm-btn-other"
					).textContent = `清空所有(${this.getValue().length})`;
				} else if (element.getRootNode() instanceof ShadowRoot) {
					element
						.getRootNode()
						.querySelector(
							".whitesevPopNetDiskAccessCodeRule .pops-confirm-btn button.pops-confirm-btn-other"
						).textContent = `清空所有(${this.getValue().length})`;
				}
			},
			/**
			 * 校验填写的匹配网站正则规则是否正确
			 * @param {string} accessRuleUrl 填写的匹配网站正则规则
			 * @returns {boolean}
			 */
			checkRuleUrlValid(accessRuleUrl) {
				if (utils.isNull(accessRuleUrl)) {
					Qmsg.error("匹配网站的正则不能为空或纯空格");
					return false;
				}
				try {
					new RegExp(accessRuleUrl);
				} catch (error) {
					log.error(error);
					Qmsg.error("匹配网站的正则错误</br>" + error.message, {
						html: true,
						timeout: 5000,
					});
					return false;
				}
				return true;
			},
			/**
			 * 设置事件
			 * @param {object} event
			 */
			setEvent(event) {
				let that = this;
				DOMUtils.on(
					event.animElement,
					"click",
					".netdisk-accesscode-rule-table div.accesscode-rule-functions button[data-delete]",
					function () {
						let dataJSON = this.closest(
							".accesscode-rule-functions"
						).getAttribute("data-json");
						dataJSON = utils.toJSON(dataJSON);
						log.success(["删除👉", dataJSON]);
						if (that.deleteValue(dataJSON)) {
							this.closest("li").remove();
							that.setDeleteAllBtnText(event.animElement);
						} else {
							Qmsg.error("删除失败");
						}
					}
				);
				DOMUtils.on(
					event.element,
					"click",
					".netdisk-accesscode-rule-table div.accesscode-rule-functions button[data-edit]",
					function () {
						let dataJSON = this.closest(
							".accesscode-rule-functions"
						).getAttribute("data-json");
						dataJSON = utils.toJSON(dataJSON);
						log.success(["修改👉", dataJSON]);
						let newEvent = Object.assign({}, event);
						newEvent.animElement = newEvent.element;
						that.showRule(newEvent, true, dataJSON);
					}
				);
			},
			/**
			 * 设置事件
			 * @param {HTMLElement} element 弹窗元素
			 */
			setRuleEvent(element) {},
			/**
			 * 获取值
			 * @returns {{
			 * urlRegexp: string,
			 * netdisk: {name:string,value:string}[]
			 * accessCode: string,
			 * }[]}
			 */
			getValue() {
				return GM_getValue("accessCodeRule", []);
			},
			/**
			 * 设置值
			 * @param {{
			 * urlRegexp: string,
			 * netdisk: {name:string,value:string}[]
			 * accessCode: string,
			 * }} value
			 */
			setValue(value) {
				let localData = this.getValue();
				localData.push(value);
				GM_setValue("accessCodeRule", localData);
			},
			/**
			 * 修改值
			 * @param {{
			 * urlRegexp: string,
			 * netdisk: {name:string,value:string}[]
			 * accessCode: string,
			 * }} oldValue
			 * @param {{
			 * urlRegexp: string,
			 * netdisk: {name:string,value:string}[]
			 * accessCode: string,
			 * }} newValue
			 * @returns {boolean} 是否修改成功
			 */
			changeValue(oldValue, newValue) {
				let result = false;
				let localData = this.getValue();
				let oldValueStr = JSON.stringify(oldValue);
				for (let i = 0; i < localData.length; i++) {
					if (JSON.stringify(localData[i]) === oldValueStr) {
						localData[i] = newValue;
						result = true;
						break;
					}
				}
				GM_setValue("accessCodeRule", localData);
				return result;
			},
			/**
			 * 添加值
			 * @param {{
			 * urlRegexp: string,
			 * netdisk: {name:string,value:string}[]
			 * accessCode: string,
			 * }} value
			 */
			addValue(value) {
				let result = true;
				let localData = this.getValue();
				for (let i = 0; i < localData.length; i++) {
					if (
						localData[i].urlRegexp === value.urlRegexp &&
						localData[i].netdisk === value.netdisk
					) {
						result = false;
						break;
					}
				}
				if (result) {
					localData.push(value);
					this.setValue(value);
				}
				return result;
			},
			/**
			 * 删除值
			 */
			deleteValue(value) {
				let result = false;
				let localData = this.getValue();
				let valueStr = JSON.stringify(value);
				for (let i = 0; i < localData.length; i++) {
					if (JSON.stringify(localData[i]) === valueStr) {
						localData.splice(i, 1);
						result = true;
						break;
					}
				}
				if (result) {
					GM_setValue("accessCodeRule", localData);
				}
				return result;
			},
			/**
			 * 清空所有规则
			 */
			deleteAllValue() {
				GM_setValue("accessCodeRule", []);
			},
		},
		/**
		 * 主动识别文本
		 */
		matchPasteText: {
			show() {
				let popsConfirm = NetDiskPops.confirm(
					{
						title: {
							text: "主动识别文本",
							position: "center",
						},
						content: {
							text: /*html*/ `
							<textarea class="netdisk-match-paste-text"></textarea>
							`,
							html: true,
						},
						btn: {
							ok: {
								text: "识别",
								callback() {
									let inputText =
										popsConfirm.popsElement?.querySelector(
											".netdisk-match-paste-text"
										)?.value || "";
									if (inputText.trim() !== "") {
										/* 排除中文 */
										inputText = inputText.replace(/[\u4e00-\u9fa5]/g, "");
										NetDiskWorker.postMessage({
											textList: [inputText],
											matchTextRange: GM_getValue(
												"pageMatchRange",
												"all"
											).toLowerCase(),
											regular: NetDisk.regular,
											startTime: Date.now(),
											from: "PasteText",
										});
									}
								},
							},
						},
						class: "whitesevPopNetDiskMatchPasteText",
						style: this.getCSS(),
					},
					NetDiskUI.popsStyle.matchPasteTextView
				);
				popsConfirm.popsElement.querySelector("textarea").focus();
			},
			getCSS() {
				return /*css*/ `
			.pops[type-value=confirm] .pops-confirm-content{
				overflow: hidden;
			}
			.netdisk-match-paste-text {
				--textarea-bd-color: #dcdfe6;
				display: inline-block;
				resize: vertical;
				padding: 5px 15px;
				line-height: 1.5;
				box-sizing: border-box;
				color: #606266;
				border: 1px solid var(--textarea-bd-color);
				border-radius: 4px;
				transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
				outline: none;
				margin: 0;
				-webkit-appearance: none;
				-moz-appearance: none;
				appearance: none;
				background: none;
				width: 100%;
				height: 100%;
				appearance: none;
				resize: none;
			}
			.netdisk-match-paste-text:hover{
				--textarea-bd-color: #c0c4cc;
			}
			.netdisk-match-paste-text:focus{
				--textarea-bd-color: #3677f0;
			}
			`;
			},
			/**
			 *
			 * @param {NetDiskWorkerCallBackOptions} data
			 */
			matchEndCallBack(data) {
				if (data.data.length) {
					Qmsg.success(
						`成功匹配${data.data.length}个,用时${
							Date.now() - data.startTime
						}ms`
					);
				} else {
					Qmsg.error("未识别到链接");
				}
			},
		},
		/**
		 * 设置标题的右键菜单
		 */
		setGlobalRightClickMenu(element) {
			NetDiskUI.view.registerContextMenu(element, void 0, [
				{
					text: "设置",
					callback() {
						log.info("打开-设置");
						NetDiskUI.suspension.showSettingView();
					},
				},
				{
					text: "历史匹配记录",
					callback() {
						log.info("打开-历史匹配记录");
						NetDiskUI.netDiskHistoryMatch.show();
					},
				},
				{
					text: "访问码规则",
					callback() {
						log.info("打开-访问码规则");
						NetDiskUI.accessCodeRule.show();
					},
				},
				{
					text: "自定义规则",
					callback() {
						log.info("打开-自定义规则");
						NetDiskCustomRules.showUI(false);
					},
				},
				{
					text: "主动识别文本",
					callback() {
						log.info("打开-主动识别文本");
						NetDiskUI.matchPasteText.show();
					},
				},
			]);
		},
		/**
		 * 设置右键菜单
		 * @param {HTMLElement | Window} target
		 * @param {string} selector
		 * @param {boolean} isHistoryView
		 */
		setRightClickMenu(target, selector, isHistoryView) {
			let showTextList = [
				{
					text: "复制链接",
					callback: function (event, contextMenuEvent) {
						let linkElement = contextMenuEvent.target;
						const { netDiskName, netDiskIndex, shareCode, accessCode } =
							NetDiskUI.getElementNetDiskLinkData(linkElement);
						NetDiskParse.copyText(
							netDiskName,
							netDiskIndex,
							shareCode,
							accessCode
						);
					},
				},
				{
					text: "访问链接",
					callback: function (event, contextMenuEvent) {
						let linkElement = contextMenuEvent.target;
						const { netDiskName, netDiskIndex, shareCode, accessCode } =
							NetDiskUI.getElementNetDiskLinkData(linkElement);
						let url = NetDiskParse.getBlankUrl(
							netDiskName,
							netDiskIndex,
							shareCode,
							accessCode
						);
						NetDiskParse.blank(
							url,
							netDiskName,
							netDiskIndex,
							shareCode,
							accessCode
						);
					},
				},
				{
					text: "修改访问码",
					callback: function (event, contextMenuEvent) {
						let linkElement = contextMenuEvent.target;
						const { netDiskName, netDiskIndex, shareCode, accessCode } =
							NetDiskUI.getElementNetDiskLinkData(linkElement);
						function newAccessCodeByHistoryViewCallBack(userInputAccessCode) {
							let currentTime = new Date().getTime();
							let data = GM_getValue(NetDiskUI.netDiskHistoryMatch.storageKey);
							let editFlag = false;
							data.forEach((item) => {
								if (
									item["netDiskName"] === netDiskName &&
									item["netDiskIndex"] === netDiskIndex &&
									item["shareCode"] === shareCode &&
									item["accessCode"] === accessCode
								) {
									item = utils.assign(item, {
										accessCode: userInputAccessCode,
										updateTime: currentTime,
									});
									log.success(["成功找到项", item]);
									editFlag = true;
									return;
								}
							});
							if (editFlag) {
								GM_setValue(NetDiskUI.netDiskHistoryMatch.storageKey, data);
								linkElement
									.closest("li")
									.querySelector(
										".netdiskrecord-update-time"
									).lastChild.textContent = utils.formatTime(currentTime);
								linkElement.setAttribute(
									"data-accesscode",
									userInputAccessCode
								);
								Qmsg.success(
									/*html*/ `
									<div style="text-align: left;">旧: ${accessCode}</div>
									<div style="text-align: left;">新: ${userInputAccessCode}</div>`,
									{
										html: true,
									}
								);
							} else {
								Qmsg.error("修改失败");
							}
						}
						function newAccessCodeCallBack_(userInputAccessCode) {
							event.target.setAttribute("data-accesscode", userInputAccessCode);
							let netDiskDict = NetDisk.linkDict.get(netDiskName);
							if (netDiskDict.has(shareCode)) {
								let currentDict = netDiskDict.get(shareCode);
								netDiskDict.set(
									shareCode,
									NetDisk.getLinkDickObj(
										userInputAccessCode,
										netDiskIndex,
										true,
										currentDict.matchText
									)
								);
								Qmsg.success(
									/*html*/ `
									<div style="text-align: left;">旧: ${accessCode}</div>
									<div style="text-align: left;">新: ${userInputAccessCode}</div>`,
									{
										html: true,
									}
								);
							} else {
								Qmsg.error("该访问码不在已获取的字典中:" + shareCode);
							}
						}
						NetDiskUI.newAccessCodeView(
							this.text,
							netDiskName,
							netDiskIndex,
							shareCode,
							(userInputAccessCode) => {
								if (isHistoryView) {
									newAccessCodeByHistoryViewCallBack(userInputAccessCode);
								} else {
									newAccessCodeCallBack_(userInputAccessCode);
								}
							}
						);
					},
				},
			];
			NetDiskUI.view.registerContextMenu(target, selector, showTextList);
		},
		/**
		 * 获取元素.netdisk-link上的data属性
		 * @param {HTMLAnchorElement} $netDiskLink
		 */
		getElementNetDiskLinkData($netDiskLink) {
			let netDiskName = $netDiskLink.getAttribute("data-netdisk");
			let netDiskIndex = parseInt(
				$netDiskLink.getAttribute("data-netdisk-index")
			);
			if (isNaN(netDiskIndex)) {
				log.warn(["元素上的netDiskIndex的值是NaN", $netDiskLink]);
				netDiskIndex = 0;
			}
			let shareCode = $netDiskLink.getAttribute("data-sharecode");
			let accessCode = $netDiskLink.getAttribute("data-accesscode");
			return {
				netDiskName,
				netDiskIndex,
				shareCode,
				accessCode,
			};
		},
	};

	/** 全局快捷键 */
	const NetDiskShortcut = {
		/**
		 * 是否正在等待用户按下键盘
		 */
		isWaitUserPressKeyboard: false,
		/**
		 * 获取本地存储的值
		 * @param {?string} key
		 * @param {?string} defaultVal
		 * @returns {{
		 * key: string,
		 * value: {
		 * keyName: string,
		 * keyValue: number|string,
		 * ohterCodeList: string[]
		 * }
		 * }|{
		 * keyName: string,
		 * keyValue: number|string,
		 * ohterCodeList: string[]
		 * }[]}
		 */
		getValue(key, defaultVal) {
			let value = GM_getValue("GM_shortcut", []);
			if (key) {
				for (let index = 0; index < value.length; index++) {
					let item = value[index];
					if (item["key"] === key) {
						return item["value"];
					}
				}
				return defaultVal;
			} else {
				return value;
			}
		},
		/**
		 * 删除本地存储的快捷键值
		 * @param {string} key
		 */
		deleteValue(key) {
			let value = this.getValue();
			let findValueIndex = value.findIndex((item) => item["key"] === key);
			if (findValueIndex !== -1) {
				value.splice(findValueIndex, 1);
			}
			GM_setValue("GM_shortcut", value);
		},
		/**
		 * 保存设置的快捷键到本地存储
		 * @param {string} key
		 * @param {string} keyName
		 * @param {string} keyValue
		 * @param {string[]} ohterCodeList
		 */
		setValue(key, keyName, keyValue, ohterCodeList) {
			let value = this.getValue();
			value.push({
				key: key,
				value: {
					keyName: keyName,
					keyValue: keyValue,
					ohterCodeList: ohterCodeList,
				},
			});
			GM_setValue("GM_shortcut", value);
		},
		/**
		 * 获取快捷键显示的文字
		 * @param {string} key
		 * @param {string} defaultValue
		 */
		getShowText(key, defaultValue) {
			let localValue = this.getValue(key);
			if (localValue) {
				/* 如果获取到,转需要显示的文字 */
				let result = "";
				localValue["ohterCodeList"].forEach((item) => {
					result += utils.stringTitleToUpperCase(item, true) + " + ";
				});
				result += localValue["keyName"];
				return result;
			} else {
				/* 未获取到,显示为默认的文字 */
				return defaultValue;
			}
		},
		/**
		 * 快捷键按钮录入的点击事件
		 */
		buttonClickCallBack(event, key, defaultValue) {
			let localValue = this.getValue(key, defaultValue);
			let spanElement = event.target
				.closest(".pops-panel-button")
				.querySelector("span");
			if (localValue === defaultValue) {
				/* 设置快捷键 */
				let loadingQmsg = Qmsg.loading("请按下快捷键...", {
					showClose: true,
					onClose() {
						keyboardListener.removeListen();
					},
				});
				NetDiskShortcut.isWaitUserPressKeyboard = true;
				let keyboardListener = utils.listenKeyboard(
					window,
					"keyup",
					(keyName, keyValue, ohterCodeList) => {
						let shortcutJSONString = JSON.stringify({
							keyName: keyName,
							keyValue: keyValue,
							ohterCodeList: ohterCodeList,
						});
						let allDetails = this.getValue();
						for (let index = 0; index < allDetails.length; index++) {
							if (
								shortcutJSONString ===
								JSON.stringify(allDetails[index]["value"])
							) {
								Qmsg.error(
									`快捷键 ${this.getShowText(
										allDetails[index]["key"]
									)} 已被占用`
								);
								NetDiskShortcut.isWaitUserPressKeyboard = false;
								loadingQmsg.close();
								return;
							}
						}
						this.setValue(key, keyName, keyValue, ohterCodeList);
						spanElement.innerHTML = this.getShowText(key, defaultValue);
						NetDiskShortcut.isWaitUserPressKeyboard = false;
						loadingQmsg.close();
					}
				);
			} else {
				/* 清空快捷键 */
				this.deleteValue(key);
			}

			spanElement.innerHTML = this.getShowText(key, defaultValue);
		},
		/**
		 * 初始化全局键盘监听
		 */
		initGlobalKeyboardListener() {
			let localValue = this.getValue();
			if (!localValue.length) {
				/* 没有设置快捷键 */
				return;
			}
			utils.listenKeyboard(
				window,
				"keydown",
				(keyName, keyValue, ohterCodeList) => {
					if (NetDiskShortcut.isWaitUserPressKeyboard) {
						return;
					}
					localValue = this.getValue();
					let findShortcutIndex = localValue.findIndex((item) => {
						let itemValue = item["value"];
						let tempValue = {
							keyName: keyName,
							keyValue: keyValue,
							ohterCodeList: ohterCodeList,
						};
						if (JSON.stringify(itemValue) === JSON.stringify(tempValue)) {
							return item;
						}
					});
					if (findShortcutIndex != -1) {
						let findShortcut = localValue[findShortcutIndex];
						log.info(["调用快捷键", findShortcut]);
						if (findShortcut["key"] === "netdisk-keyboard-open-setting") {
							log.info("打开设置");
							NetDiskUI.suspension.showSettingView();
						} else if (
							findShortcut["key"] ===
							"netdisk-keyboard-open-history-matching-records"
						) {
							log.info("打开历史匹配记录");
							NetDiskUI.netDiskHistoryMatch.show();
						} else if (
							findShortcut["key"] === "netdisk-keyboard-open-accesscode-rule"
						) {
							log.info("打开访问码规则");
							NetDiskUI.accessCodeRule.show();
						} else if (
							findShortcut["key"] === "netdisk-keyboard-open-user-rule"
						) {
							log.info("打开用户自定义规则");
							NetDiskCustomRules.showUI(false);
						} else if (
							findShortcut["key"] ===
							"netdisk-keyboard-open-proactively-recognize-text"
						) {
							log.info("打开主动识别文本");
							NetDiskUI.matchPasteText.show();
						} else {
							log.error("还未配置调用函数");
						}
					}
				}
			);
		},
	};

	/** pops弹窗 */
	const NetDiskPops = {
		/**
		 * 普通信息框
		 * @param {PopsAlertDetails} details 配置
		 * @param {{
		 * PC: {
		 *  width: string,
		 *  height: string,
		 * },
		 * Mobile: {
		 *  width: string,
		 *  height: string
		 * }
		 * }} sizeConfig 大小配置
		 * @returns {PopsCallResult}
		 */
		alert(details, sizeConfig) {
			details = this.handleDetails(details, sizeConfig);
			return pops.alert(details);
		},
		/**
		 * 询问框
		 * @param {PopsConfirmDetails} details 配置
		 * @param {?{
		 * PC: {
		 *  width: string,
		 *  height: string,
		 * },
		 * Mobile: {
		 *  width: string,
		 *  height: string
		 * }
		 * }} sizeConfig 大小配置
		 * @returns {PopsCallResult}
		 */
		confirm(details, sizeConfig) {
			details = this.handleDetails(details, sizeConfig);
			return pops.confirm(details);
		},
		/**
		 * 加载层
		 * @param {PopsLoadingDetails} details 配置
		 * @returns {PopsCallResult}
		 */
		loading(details) {
			if (typeof details["animation"] === "undefined") {
				details["animation"] = GM_getValue(
					"popsAnimation",
					NetDiskUI.defaultAnimation
				);
			}
			if (typeof details["forbiddenScroll"] === "undefined") {
				details["forbiddenScroll"] = NetDiskUI.defaultForbiddenScroll;
			}
			return pops.loading(details);
		},
		/**
		 * 输入框
		 * @param {PopsPromptDetails} details 配置
		 * @param {?{
		 * PC: {
		 *  width: string,
		 *  height: string,
		 * },
		 * Mobile: {
		 *  width: string,
		 *  height: string
		 * }
		 * }} sizeConfig 大小配置
		 * @returns {PopsCallResult}
		 */
		prompt(details, sizeConfig) {
			details = this.handleDetails(details, sizeConfig);
			return pops.prompt(details);
		},
		/**
		 * 文件夹
		 * @param {PopsFolderDetails} details 配置
		 * @returns {PopsCallResult}
		 */
		folder(details, sizeConfig) {
			details = this.handleDetails(details, sizeConfig);
			details["sort"] = {
				name: GM_getValue("pops-folder-sort-name", NetDiskUI.defaultSortName),
				isDesc: GM_getValue(
					"pops-folder-sort-is-desc",
					NetDiskUI.defaultSortDesc
				),
				callback(target, event, sortName, sortDesc) {
					GM_setValue("pops-folder-sort-name", sortName);
					GM_setValue("pops-folder-sort-is-desc", sortDesc);
				},
			};
			return pops.folder(details);
		},
		/**
		 * 菜单面板
		 * @param {PopsPanelDetails} details 配置
		 * @returns {PopsCallResult}
		 */
		panel(details, sizeConfig) {
			details = this.handleDetails(details, sizeConfig);
			return pops.panel(details);
		},
		/**
		 *
		 * @param {PopsConfirmDetails} details
		 * @param {?{
		 * PC: {
		 *  width: string,
		 *  height: string,
		 * },
		 * Mobile: {
		 *  width: string,
		 *  height: string
		 * }
		 * }} sizeConfig 大小配置
		 */
		handleDetails(details, sizeConfig) {
			details = Object.assign(
				{
					animation: GM_getValue("popsAnimation", NetDiskUI.defaultAnimation),
					drag: GM_getValue("pcDrag", NetDiskUI.defaultPCDrag),
					dragLimit: GM_getValue("pcDragLimit", NetDiskUI.defaultPCDragLimit),
					forbiddenScroll: NetDiskUI.defaultForbiddenScroll,
				},
				details
			);
			if (sizeConfig != null) {
				details.width = pops.isPhone()
					? sizeConfig.Mobile.width
					: sizeConfig.PC.width;
				details.height = pops.isPhone()
					? sizeConfig.Mobile.height
					: sizeConfig.PC.height;
			}

			if (details.mask == null) {
				details.mask = {};
			}
			if (details.mask.enable == null) {
				details.mask.enable = true;
			}
			if (details.mask.clickEvent == null) {
				details.mask.clickEvent = {};
			}
			if (details.mask.clickEvent.toClose == null) {
				details.mask.clickEvent.toClose = GM_getValue(
					"clickMaskToCloseDialog",
					NetDiskUI.defaultClickMaskToCloseDialog
				);
			}
			if (GM_getValue("popsAcrylic", NetDiskUI.defaultPopsAcrylic)) {
				let acrylicCSS = /*css*/ `
				.pops {
					--acrylic-opacity: 0.7;
					--acrylic-color: rgba(232, 232, 232, var(--acrylic-opacity));
					--acrylic-blur: 30px;
					--acrylic-saturate: 125%;
					--pops-bg-opacity: var(--acrylic-opacity);
				}
				.pops {
					backdrop-filter: blur(var(--acrylic-blur)) saturate(var(--acrylic-saturate));
					background-color: var(--acrylic-color);
				}
				.pops[type-value=panel]{
					--aside-bg-color: rgba(221, 221, 221, var(--acrylic-opacity));
				}
				`;
				if (typeof details.style === "string") {
					details.style += acrylicCSS;
				} else {
					details.style = acrylicCSS;
				}
			}
			return details;
		},
	};

	/** 油猴菜单 */
	const NetDiskMenu = {
		/**
		 * 初始化
		 */
		init() {
			/* 不在iframe内进行注册 */
			if (!NetDiskUI.suspension.isTopWindow()) {
				return;
			}
			GM_Menu.add([
				{
					key: "showSetting",
					text: "⚙ 设置",
					showText(text) {
						return text;
					},
					callback() {
						NetDiskUI.suspension.showSettingView();
					},
				},
				{
					key: "showNetDiskHistoryMatch",
					text: "⚙ 历史匹配记录",
					showText(text) {
						return text;
					},
					callback() {
						NetDiskUI.netDiskHistoryMatch.show();
					},
				},
				{
					key: "showAccessCodeRule",
					text: "⚙ 访问码规则",
					showText(text) {
						return text;
					},
					callback() {
						NetDiskUI.accessCodeRule.show();
					},
				},
				{
					key: "showUserRule",
					text: "⚙ 用户自定义规则",
					showText(text) {
						return text;
					},
					callback() {
						NetDiskCustomRules.showUI(false);
					},
				},
				{
					key: "showMatchPasteText",
					text: "⚙ 主动识别文本",
					showText(text) {
						return text;
					},
					callback() {
						NetDiskUI.matchPasteText.show();
					},
				},
			]);
		},
		/**
		 * 初始化环境变量
		 */
		initEnv() {
			if (GM_getValue("allowMatchLocationHref")) {
				NetDisk.allowMatchLocationHref = true;
			}
		},
	};

	/* -------入口------- */
	log.config({
		logMaxCount: 100,
		autoClearConsole: true,
	});
	Object.assign(
		NetDiskUI.src.icon,
		typeof RESOURCE_ICON === "undefined" ? {} : RESOURCE_ICON
	);
	NetDiskMenu.init();
	NetDiskMenu.initEnv();
	NetDiskUI.initQmsg();
	NetDiskCustomRules.init();
	NetDisk.init();
	NetDiskShortcut.initGlobalKeyboardListener();
	DOMUtils.ready(function () {
		httpx.config({
			headers: {
				"User-Agent": utils.getRandomPCUA(),
			},
			onabort() {
				Qmsg.error("请求被取消");
			},
			ontimeout() {
				Qmsg.error("请求超时");
			},
			onerror(response) {
				Qmsg.error("请求异常");
				log.error(["httpx-onerror", response]);
			},
		});
		NetDiskAutoFillAccessCode.init();
		NetDiskAuthorization.init();
		NetDiskWorker.monitorDOMChange();
	});
})();