Greasy Fork is available in English.

网盘链接识别

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

// ==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.4.15.16
// @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\/.*$/
// @require      https://update.greasyfork.org/scripts/462234/1322684/Message.js
// @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://update.greasyfork.org/scripts/456485/1360571/pops.js
// @require      https://update.greasyfork.org/scripts/455186/1360586/WhiteSevsUtils.js
// @require      https://update.greasyfork.org/scripts/465772/1360574/DOMUtils.js
// @require      https://update.greasyfork.org/scripts/486152/1360580/Crypto-JS.js
// ==/UserScript==

(function () {
  if (typeof unsafeWindow === "undefined") {
    unsafeWindow = globalThis || window;
  }
  /**
   * @type {import("../库/CryptoJS/index")}
   */
  const Cryptojs = CryptoJS ?? window.CryptoJS ?? unsafeWindow.CryptoJS;
  /**
   * @type {import("../库/Qmsg")}
   */
  const Qmsg = window.Qmsg;
  /**
   * @type {import("../库/pops")}
   */
  const pops = window.pops;
  const AnyTouch = pops.config.Utils.AnyTouch();
  /** @type {Utils} */
  const utils = window.Utils.noConflict();
  /** @type {DOMUtils} */
  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",
  };

  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 {UtilsDictionaryConstructor<string,UtilsDictionaryConstructor<string,NetDiskDictData>>}
     */
    linkDict: void 0,
    /**
     * (临时)链接字典
     * @type {UtilsDictionaryConstructor<string,UtilsDictionaryConstructor<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)/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 = `
          <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 = `
          <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 = `
          <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 = `
          <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 = `
          <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 postResp = await httpx.post(
            "https://pc-api.uc.cn/1/clouddrive/share/sharepage/token?pr=UCBrowser&fr=pc",
            {
              data: JSON.stringify({ pwd_id: shareCode, passcode: accessCode }),
              headers: {
                "User-Agent": utils.getRandomPCUA(),
                Host: "drive.uc.cn",
                Referer: NetDiskParse.getBlankUrl(
                  "uc",
                  netDiskIndex,
                  shareCode,
                  accessCode
                ),
                Origin: "https://drive.uc.cn",
              },
              ontimeout() {},
              onerror() {},
            }
          );
          let responseText = postResp.data.responseText;
          if (!postResp.status && utils.isNull(responseText)) {
            return NetDiskCheckLinkValidity.status.error;
          }
          let data = utils.toJSON(responseText);
          if (data["status"] === 200) {
            return NetDiskCheckLinkValidity.status.success;
          }
          if (data["message"].includes("需要提取码")) {
            return NetDiskCheckLinkValidity.status.needAccessCode;
          }
          if (data["message"].includes("inner error")) {
            return NetDiskCheckLinkValidity.status.error;
          }
          return NetDiskCheckLinkValidity.status.failed;
        },
      },
    },
    /**
     * 校验链接的有效性,这里是用于订阅-消费
     * @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 {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 {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 {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) {
                if (NetDiskFilterScheme.isForwardDownloadLink("_123pan")) {
                  downloadUrl = NetDiskFilterScheme.parseDataToSchemeUri(
                    "_123pan",
                    downloadInfo["data"]["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
         * @returns
         */
        this.decodeDownloadUrl = async function (url) {
          if (url === "") {
            return "";
          }
          let decodeURL = new URL(url);
          let params = decodeURL.search.replace(/^\?params=/gi, "");
          params = params.split("&")[0];
          try {
            let newDecodeUrl = decodeURI(atob(params));
            Qmsg.info("正在获取重定向直链");
            let getResp = await httpx.get({
              url: newDecodeUrl,
              responseType: "json",
              headers: {
                "User-Agent": utils.getRandomAndroidUA(),
                Referer: "https://www.123pan.com/s/" + that.shareCode,
                Origin: "https://www.123pan.com",
              },
              onerror: function () {},
            });
            log.info(getResp);
            if (!getResp.status && getResp.data.status !== 210) {
              /* 很奇怪,123盘返回的状态码是210 */
              return newDecodeUrl;
            }
            let respData = getResp.data;
            let resultJSON = utils.toJSON(respData.responseText);
            let newURL = new URL(resultJSON.data.redirect_url);
            newURL.searchParams.set("auto_redirect", 1);
            log.success(resultJSON);
            return newURL.toString();
          } catch (error) {
            log.error(error);
            return url;
          }
        };
        return this;
      },
      /**
       * 坚果云
       * @constructor
       * @returns {object}
       */
      jianguoyun: function () {
        let that = this;
        /**
         * 所在规则的下标
         */
        this.netDiskIndex = 0;
        /**
         * 分享码
         */
        this.shareCode = "";
        /**
         * 提取码
         */
        this.accessCode = "";
        this.errorCode = {
          UnAuthorized: "请先登录坚果云账号",
        };
        this.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;
          }
          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 errorTip = Qmsg.error(
              `请在阿里云盘页面解析,<a href="${url}">点我前往</a>`,
              {
                html: true,
                timeout: 10000,
              }
            );
            DOMUtils.on(
              errorTip.$elem.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 = {
    /** 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) {
      NetDiskWorker.GM_matchWorker.postMessage(message, options);
    },
    /**
     * Worker的onmessage
     * @param {MessageEvent<NetDiskWorkerCallBackOptions>} event
     */
    onMessage(event) {
      const data = event.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) {
        NetDiskUI.isHandleMatch = false;
      } else {
        const delaytime =
          parseFloat(
            GM_getValue("delaytime", NetDiskData.defaultMatchIntervalTime)
          ) * 1000;
        setTimeout(() => {
          NetDiskWorker.matchingEndCallBack(true);
        }, delaytime);
      }
    },
  };

  /** 网盘-引用/获取文件 */
  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)),
    /**
     * 是否正在文本匹配中
     */
    isHandleMatch: false,
    /**
     * 是否正在循环切换按钮背景
     */
    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: "88dvw",
          height: "50dvh",
        },
      },
      /**
       * (主)网盘链接界面-小窗
       */
      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: "88dvw",
          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: "55dvw",
          height: "70dvh",
        },
        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: [
              {
                className: "netdisk-panel-forms-pops",
                text: "弹窗",
                type: "forms",
                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,
                    ""
                  ),
                ],
              },
              {
                className: "netdisk-panel-forms-pops-folder",
                text: "文件弹窗",
                type: "forms",
                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: "降序",
                      },
                    ]
                  ),
                ],
              },
              {
                text: "小图标导航",
                type: "forms",
                forms: [
                  getSwtichDetail(
                    "点击定位分享码",
                    "pops-netdisk-icon-click-event-find-sharecode",
                    true,
                    NetDiskData.iconDefaultClickEventToFindShareCode,
                    "自动滚动页面至包含分享码的元素"
                  ),
                  getSwtichDetail(
                    "选中分享码",
                    "pops-netdisk-icon-click-event-find-sharecode-with-select",
                    true,
                    NetDiskData.iconDefaultClickEventToFindShareCodeWithSelect,
                    "使用光标选中分享码/元素"
                  ),
                  getSwtichDetail(
                    "循环定位",
                    "pops-netdisk-icon-click-event-loop-find-sharecode",
                    true,
                    NetDiskData.iconDefaultClickEventToFindShareCodeByLoop,
                    "关闭则是每一个元素只定位一次"
                  ),
                ],
              },
              {
                text: "悬浮按钮",
                type: "forms",
                forms: [
                  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,
                    "移动悬浮按钮松开后自动吸附边缘"
                  ),
                ],
              },
              {
                className: "netdisk-panel-forms-toast",
                text: "Toast",
                type: "forms",
                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"
                  ),
                ],
              },
              {
                className: "netdisk-panel-forms-small-window",
                text: "小窗模式",
                type: "forms",
                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`;
                    }
                  ),
                ],
              },
              {
                className: "netdisk-panel-history-match",
                text: "匹配记录",
                type: "forms",
                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,
                    "将匹配到的链接信息进行本地存储,可点击【油猴菜单-⚙ 历史匹配记录】进行查看"
                  ),
                ],
              },
              {
                className: "netdisk-panel-forms-function",
                text: "功能",
                type: "forms",
                forms: [
                  getSelectDetail(
                    "行为模式",
                    "匹配到链接时触发的UI执行",
                    "netdisk-behavior-mode",
                    NetDiskData.defaultNetdiskBehaviorMode,
                    [
                      {
                        text: "悬浮按钮+小窗",
                        value: "suspension_smallwindow",
                      },
                      {
                        text: "悬浮按钮+大窗",
                        value: "suspension_window",
                      },
                      {
                        text: "小窗",
                        value: "smallwindow",
                      },
                    ],
                    void 0
                  ),
                  getSliderDetail(
                    "匹配间隔",
                    "匹配文本完毕后的延迟xxx秒允许下一次匹配",
                    "delaytime",
                    NetDiskData.defaultMatchIntervalTime,
                    NetDiskData.matchIntervalMinTime,
                    NetDiskData.matchIntervalMaxTime,
                    0.1,
                    void 0,
                    (value) => {
                      return `${value}s`;
                    }
                  ),
                  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(
                    "自动输入访问码",
                    "autoFillAccessCode",
                    false,
                    void 0,
                    "通过主动点击链接跳转时,会自动输入网盘访问码"
                  ),
                  getSwtichDetail(
                    "获取重定向后的直链",
                    "getTheDirectLinkAfterRedirection",
                    false,
                    void 0,
                    "对获取的链接再进行一次重定向获取链接"
                  ),
                  getSwtichDetail(
                    "允许匹配当前URL",
                    "allowMatchLocationHref",
                    false,
                    void 0,
                    "匹配window.location.href"
                  ),
                  getSwtichDetail(
                    "添加元素时进行匹配",
                    "isAddedNodesToMatch",
                    false,
                    void 0,
                    "当监听到页面添加元素时才进行匹配文本"
                  ),
                ],
              },
              {
                className: "netdisk-panel-forms-share-code",
                text: "分享码相关",
                type: "forms",
                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 = {
          className: "netdisk-panel-forms-shortcut-keys",
          text: "快捷键",
          type: "forms",
          forms: [],
        };
        let shortcurFormsDetailsList = [
          {
            text: "【打开】⚙ 设置",
            key: "netdisk-keyboard-open-setting",
          },
          {
            text: "【打开】⚙ 历史匹配记录",
            key: "netdisk-keyboard-open-history-matching-records",
          },
          {
            text: "【打开】⚙ 访问码规则",
            key: "netdisk-keyboard-open-accesscode-rule",
          },
          {
            text: "【打开】⚙ 用户自定义规则",
            key: "netdisk-keyboard-open-user-rule",
          },
          {
            text: "【打开】⚙ 主动识别文本",
            key: "netdisk-keyboard-open-proactively-recognize-text",
          },
        ];
        shortcurFormsDetailsList.forEach((item) => {
          shortcutDetails.forms.push({
            text: item.text,
            type: "button",
            attributes: {
              "data-key": item.key,
              "data-default-value": "暂无快捷键",
            },
            buttonIcon: "keyboard",
            buttonIconIsLoading: false,
            buttonType: "default",
            buttonText() {
              return NetDiskShortcut.getShowText(
                this.attributes["data-key"],
                this.attributes["data-default-value"]
              );
            },
            callback(event) {
              NetDiskShortcut.buttonClickCallBack(
                event,
                this.attributes["data-key"],
                this.attributes["data-default-value"]
              );
            },
          });
        });
        contentDetails[0].forms.push(shortcutDetails);
        /**
         * 追加网盘设置
         */
        function addNetDiskSetting() {
          /**
           * @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 {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 = `
                <div style="
                    width: 20px;
                    height: 20px;
                    background: url(${NetDiskUI.src.icon[item.key]}) no-repeat;
                    background-size: 100% 100%;
                    ">`;
              } else {
                asideTitle = `
                <div style="
                    width: 20px;
                    height: 20px;
                    background: url(${NetDiskUI.src.icon[item.key]}) no-repeat;
                    background-size: 100% 100%;
                    "></div>
                <div style="margin-left: 4px;">${item.type}</div>`;
              }
            }
            let headerTitleText = item.type;
            if (item.isUserRule) {
              headerTitleText += `<div class="netdisk-custom-rule-edit" data-key="${item.key}" data-type="${item.type}">${pops.config.iconSVG.edit}</div>`;
              headerTitleText += `<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: `
            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() ? "50dvh" : "60dvh"};
              }
              `,
            },
            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: `
            <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 += `
          <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 `
        .pops-confirm-content .whitesev-accesscode-rule{
          display: flex;
          align-items: center;
          justify-content: space-between;
          margin: 15px 15px;
        }
        
        .pops-confirm-content div.netdisk-accesscode-rule-table{
          /* height: calc( 85% - 40px); */
          overflow: auto;
        }

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

        .pops-confirm-content .netdisk-accesscode-rule-table .accesscode-rule-url-regexp p,
        .pops-confirm-content .netdisk-accesscode-rule-table .accesscode-rule-netdisk-name p,
        .pops-confirm-content .netdisk-accesscode-rule-table .accesscode-rule-accesscode p,
        .pops-confirm-content .netdisk-accesscode-rule-table .accesscode-rule-functions p{
          min-width: 80px;
          max-width: 80px;
          align-self: center;
        }
        .pops-confirm-content .netdisk-accesscode-rule-table li {
          display: flex;
          flex-direction: column;
          justify-content: center;
          border-radius: 10px;
          box-shadow: 0 0.3px 0.6px rgb(0 0 0 / 6%), 0 0.7px 1.3px rgb(0 0 0 / 8%), 0 1.3px 2.5px rgb(0 0 0 / 10%), 0 2.2px 4.5px rgb(0 0 0 / 12%), 0 4.2px 8.4px rgb(0 0 0 / 14%), 0 10px 20px rgb(0 0 0 / 20%);
          margin: 20px 10px;
          padding: 10px;
        }
        `;
      },
      /**
       * 显示规则弹窗进行添加/修改
       * @param {object} mainEvent
       * @param {boolean} isEdit 是否是修改模式
       * @param {{
       * urlRegexp: string,
       * netdisk: {
       *  name:string,
       *  value:string,
       * }[],
       * accessCode: string,
       * }} oldValue 当isEdie为true时传入的值
       */
      showRule(mainEvent, isEdit = false, oldValue) {
        let that = this;
        let popsConfirm = NetDiskPops.confirm(
          {
            title: {
              text: isEdit ? "修改规则" : "添加规则",
              position: "center",
            },
            content: {
              text: `
              <div class="whitesev-accesscode-rule">
                <div type-name>匹配网站</div>
                <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: `
            ${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: `
            <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 `
        .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("未识别到链接");
        }
      },
    },
    /**
     * 监听页面节点内容或节点文本的变动,从而进行匹配网盘链接
     */
    monitorDOMInsert() {
      NetDiskWorker.initWorkerBlobLink();
      NetDiskWorker.initWorker();
      /**
       * 设置-判定为添加元素才进行匹配
       * @type {boolean}
       */
      const isAddedNodesToMatch = GM_getValue("isAddedNodesToMatch");
      /**
       * 观察者的事件
       * @param {?MutationRecord[]} mutations
       * @returns
       */
      async function observeEvent(mutations) {
        if (NetDiskUI.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;
          }
        }
        NetDiskUI.isHandleMatch = true;
        /** 开始时间 */
        const startTime = Date.now();
        if (GM_getValue("readClipboard", false)) {
          NetDisk.clipboardText = await NetDisk.getClipboardText();
        }
        if (typeof NetDisk.clipboardText !== "string") {
          NetDisk.clipboardText = "";
        }
        let matchTextRangeLowerCase = GM_getValue(
          "pageMatchRange",
          "all"
        ).toLowerCase();
        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,
        config: {
          /* 子节点的变动(新增、删除或者更改) */
          childList: true,
          /* 节点内容或节点文本的变动 */
          characterData: true,
          /* 是否将观察器应用于该节点的所有后代节点 */
          subtree: true,
        },
      });
      /* 主动触发一次,因为有的页面上没触发mutationObserver */
      observeEvent();
    },
    /**
     * 设置标题的右键菜单
     */
    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(
                  `
                  <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(
                  `
                  <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 = `
        .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: 200000,
    autoClearConsole: false,
  });
  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();
    NetDiskUI.monitorDOMInsert();
  });
})();