MT论坛优化

MT论坛效果增强,如自动签到、自动展开帖子、用户状态查看、美化导航、动态头像上传、最新发表、评论过滤器等

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         MT论坛优化
// @namespace    https://github.com/WhiteSevs/TamperMonkeyScript
// @version      2025.11.27
// @author       WhiteSevs
// @description  MT论坛效果增强,如自动签到、自动展开帖子、用户状态查看、美化导航、动态头像上传、最新发表、评论过滤器等
// @license      GPL-3.0-only
// @icon         data:image/png;base64,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
// @supportURL   https://github.com/WhiteSevs/TamperMonkeyScript/issues
// @match        *://bbs.binmt.cc/*
// @exclude      /^http(s|)://bbs.binmt.cc/uc_server.*$/
// @require      https://fastly.jsdelivr.net/gh/WhiteSevs/TamperMonkeyScript@86be74b83fca4fa47521cded28377b35e1d7d2ac/lib/CoverUMD/index.js
// @require      https://fastly.jsdelivr.net/npm/@whitesev/[email protected]/dist/index.umd.js
// @require      https://fastly.jsdelivr.net/npm/@whitesev/[email protected]/dist/index.umd.js
// @require      https://fastly.jsdelivr.net/npm/@whitesev/[email protected]/dist/index.umd.js
// @require      https://fastly.jsdelivr.net/npm/[email protected]/dist/index.umd.js
// @require      https://fastly.jsdelivr.net/npm/[email protected]/dist/viewer.min.js
// @require      https://fastly.jsdelivr.net/npm/@highlightjs/[email protected]/highlight.min.js
// @resource     HljsCSS    https://fastly.jsdelivr.net/npm/[email protected]/styles/github-dark.min.css
// @resource     ViewerCSS  https://fastly.jsdelivr.net/npm/[email protected]/dist/viewer.min.css
// @connect      *
// @grant        GM.cookie
// @grant        GM_addStyle
// @grant        GM_deleteValue
// @grant        GM_getResourceText
// @grant        GM_getValue
// @grant        GM_info
// @grant        GM_listValues
// @grant        GM_registerMenuCommand
// @grant        GM_setValue
// @grant        GM_setValues
// @grant        GM_unregisterMenuCommand
// @grant        GM_xmlhttpRequest
// @grant        unsafeWindow
// @run-at       document-start
// ==/UserScript==

(function (Qmsg, DOMUtils, pops, Utils, hljs, Viewer) {
  "use strict";

  const d = new Set();
  const importCSS = async (t) => {
    d.has(t) ||
      (d.add(t),
      ((a) => {
        function r(n) {
          if (typeof GM_addStyle == "function") return GM_addStyle(n);
          const e = document.createElement("style");
          if ((e.setAttribute("type", "text/css"), e.setAttribute("data-type", "gm-css"), globalThis.trustedTypes)) {
            const c = globalThis.trustedTypes.createPolicy("safe-innerHTML", { createHTML: (i) => i });
            e.innerHTML = c.createHTML(n);
          } else e.innerHTML = n;
          return ((document.head || document.documentElement).appendChild(e), e);
        }
        r(a);
      })(t));
  };

  var _GM = (() => (typeof GM != "undefined" ? GM : void 0))();
  var _GM_deleteValue = (() => (typeof GM_deleteValue != "undefined" ? GM_deleteValue : void 0))();
  var _GM_getResourceText = (() => (typeof GM_getResourceText != "undefined" ? GM_getResourceText : void 0))();
  var _GM_getValue = (() => (typeof GM_getValue != "undefined" ? GM_getValue : void 0))();
  var _GM_info = (() => (typeof GM_info != "undefined" ? GM_info : void 0))();
  var _GM_listValues = (() => (typeof GM_listValues != "undefined" ? GM_listValues : void 0))();
  var _GM_registerMenuCommand = (() =>
    typeof GM_registerMenuCommand != "undefined" ? GM_registerMenuCommand : void 0)();
  var _GM_setValue = (() => (typeof GM_setValue != "undefined" ? GM_setValue : void 0))();
  var _GM_setValues = (() => (typeof GM_setValues != "undefined" ? GM_setValues : void 0))();
  var _GM_unregisterMenuCommand = (() =>
    typeof GM_unregisterMenuCommand != "undefined" ? GM_unregisterMenuCommand : void 0)();
  var _GM_xmlhttpRequest = (() => (typeof GM_xmlhttpRequest != "undefined" ? GM_xmlhttpRequest : void 0))();
  var _unsafeWindow = (() => (typeof unsafeWindow != "undefined" ? unsafeWindow : void 0))();
  var _monkeyWindow = (() => window)();
  const GM_RESOURCE_MAPPING = {
    Viewer: {
      keyName: "ViewerCSS",
      url: "https://fastly.jsdelivr.net/npm/viewerjs@latest/dist/viewer.min.css",
    },
    Hljs: {
      keyName: "HljsCSS",
      url: "https://fastly.jsdelivr.net/npm/highlight.js@latest/styles/github-dark.min.css",
    },
  };
  const PanelSettingConfig = {
    qmsg_config_position: {
      key: "qmsg-config-position",
      defaultValue: "bottom",
    },
    qmsg_config_maxnums: {
      key: "qmsg-config-maxnums",
      defaultValue: 3,
    },
    qmsg_config_showreverse: {
      key: "qmsg-config-showreverse",
      defaultValue: false,
    },
  };
  const CommonUtil = {
    waitRemove(...args) {
      args.forEach((selector) => {
        if (typeof selector !== "string") {
          return;
        }
        DOMUtils.waitNodeList(selector).then((nodeList) => {
          nodeList.forEach(($el) => $el.remove());
        });
      });
    },
    createBlockCSSNode(...args) {
      let selectorList = [];
      if (args.length === 0) {
        return;
      }
      if (args.length === 1 && typeof args[0] === "string" && args[0].trim() === "") {
        return;
      }
      args.forEach((selector) => {
        if (Array.isArray(selector)) {
          selectorList = selectorList.concat(selector);
        } else {
          selectorList.push(selector);
        }
      });
      return DOMUtils.createElement("style", {
        type: "text/css",
        innerHTML: `${selectorList.join(",\n")}{display: none !important;}`,
      });
    },
    addBlockCSS(...args) {
      let selectorList = [];
      if (args.length === 0) {
        return;
      }
      if (args.length === 1 && typeof args[0] === "string" && args[0].trim() === "") {
        return;
      }
      args.forEach((selector) => {
        if (Array.isArray(selector)) {
          selectorList = selectorList.concat(selector);
        } else {
          selectorList.push(selector);
        }
      });
      return addStyle(`${selectorList.join(",\n")}{display: none !important;}`);
    },
    setGMResourceCSS(resourceMapData) {
      const cssText = typeof _GM_getResourceText === "function" ? _GM_getResourceText(resourceMapData.keyName) : null;
      if (typeof cssText === "string" && cssText) {
        return addStyle(cssText);
      } else {
        return CommonUtil.loadStyleLink(resourceMapData.url);
      }
    },
    async loadStyleLink(url) {
      let $link = document.createElement("link");
      $link.rel = "stylesheet";
      $link.type = "text/css";
      $link.href = url;
      return new Promise((resolve) => {
        DOMUtils.onReady(() => {
          document.head.appendChild($link);
          resolve($link);
        });
      });
    },
    async loadScript(url) {
      let $script = document.createElement("script");
      $script.src = url;
      return new Promise((resolve) => {
        $script.onload = () => {
          resolve(null);
        };
        (document.head || document.documentElement).appendChild($script);
      });
    },
    fixUrl(url) {
      url = url.trim();
      if (url.startsWith("data:")) {
        return url;
      }
      if (url.match(/^http(s|):\/\//i)) {
        return url;
      } else if (url.startsWith("//")) {
        if (url.startsWith("///"));
        else {
          url = window.location.protocol + url;
        }
        return url;
      } else {
        if (!url.startsWith("/")) {
          url += "/";
        }
        url = window.location.origin + url;
        return url;
      }
    },
    fixHttps(url) {
      if (url.startsWith("https://")) {
        return url;
      }
      if (!url.startsWith("http://")) {
        return url;
      }
      try {
        let urlInstance = new URL(url);
        urlInstance.protocol = "https:";
        return urlInstance.toString();
      } catch {
        return url;
      }
    },
    lockScroll(...args) {
      let $hidden = document.createElement("style");
      $hidden.innerHTML = `
			.pops-overflow-hidden-important {
				overflow: hidden !important;
			}
		`;
      let $elList = [document.documentElement, document.body].concat(...(args || []));
      $elList.forEach(($el) => {
        $el.classList.add("pops-overflow-hidden-important");
      });
      (document.head || document.documentElement).appendChild($hidden);
      return {
        recovery() {
          $elList.forEach(($el) => {
            $el.classList.remove("pops-overflow-hidden-important");
          });
          $hidden.remove();
        },
      };
    },
    async getClipboardText() {
      function readClipboardText(resolve) {
        navigator.clipboard
          .readText()
          .then((clipboardText) => {
            resolve(clipboardText);
          })
          .catch((error) => {
            log.error("读取剪贴板内容失败👉", error);
            resolve("");
          });
      }
      function requestPermissionsWithClipboard(resolve) {
        navigator.permissions
          .query({
            name: "clipboard-read",
          })
          .then((permissionStatus) => {
            readClipboardText(resolve);
          })
          .catch((error) => {
            log.error("申请剪贴板权限失败,尝试直接读取👉", error.message ?? error.name ?? error.stack);
            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,
            }
          );
        }
      });
    },
    escapeHtml(unsafe) {
      return unsafe
        .replace(/&/g, "&")
        .replace(/</g, "&lt;")
        .replace(/>/g, "&gt;")
        .replace(/"/g, "&quot;")
        .replace(/'/g, "&#039;")
        .replace(/©/g, "&copy;")
        .replace(/®/g, "&reg;")
        .replace(/™/g, "&trade;")
        .replace(/→/g, "&rarr;")
        .replace(/←/g, "&larr;")
        .replace(/↑/g, "&uarr;")
        .replace(/↓/g, "&darr;")
        .replace(/—/g, "&mdash;")
        .replace(/–/g, "&ndash;")
        .replace(/…/g, "&hellip;")
        .replace(/ /g, "&nbsp;")
        .replace(/\r\n/g, "<br>")
        .replace(/\r/g, "<br>")
        .replace(/\n/g, "<br>")
        .replace(/\t/g, "&nbsp;&nbsp;&nbsp;&nbsp;");
    },
    interval(fn, intervalTime, timeout = 5e3) {
      let timeId;
      let maxTimeout = timeout - intervalTime;
      let intervalTimeCount = intervalTime;
      let loop = async (isTimeout) => {
        let result = await fn(isTimeout);
        if ((typeof result === "boolean" && !result) || isTimeout) {
          utils.workerClearTimeout(timeId);
          return;
        }
        intervalTimeCount += intervalTime;
        if (intervalTimeCount > maxTimeout) {
          loop(true);
          return;
        }
        timeId = utils.workerSetTimeout(() => {
          loop(false);
        }, intervalTime);
      };
      loop(false);
    },
    findParentNode($el, selector, parentSelector) {
      if (parentSelector) {
        let $parent = DOMUtils.closest($el, parentSelector);
        if ($parent) {
          let $target = $parent.querySelector(selector);
          return $target;
        }
      } else {
        if (DOMUtils.matches($el, selector)) {
          return $el;
        }
        let $parent = DOMUtils.closest($el, selector);
        return $parent;
      }
    },
    toStr(data) {
      const undefinedReplacedStr = `__undefined__placeholder__replaced__str__`;
      const dataStr = JSON.stringify(
        data,
        (key, value) => {
          return value === void 0 ? undefinedReplacedStr : value;
        },
        2
      ).replace(new RegExp(`"${undefinedReplacedStr}"`, "g"), "undefined");
      return dataStr;
    },
  };
  const utils = Utils.noConflict();
  const domUtils = DOMUtils.noConflict();
  const __pops__ = pops;
  const log = new utils.Log(_GM_info, _unsafeWindow.console || _monkeyWindow.console);
  const SCRIPT_NAME = _GM_info?.script?.name || void 0;
  const AnyTouch = pops.config.Utils.AnyTouch();
  const DEBUG = false;
  log.config({
    debug: false,
    logMaxCount: 250,
    autoClearConsole: true,
    tag: true,
  });
  Qmsg.config({
    isHTML: true,
    autoClose: true,
    showClose: false,
    consoleLogContent(qmsgInst) {
      const qmsgType = qmsgInst.setting.type;
      if (qmsgType === "loading") {
        return false;
      }
      const content = qmsgInst.setting.content;
      if (qmsgType === "warning") {
        log.warn(content);
      } else if (qmsgType === "error") {
        log.error(content);
      } else {
        log.info(content);
      }
      return true;
    },
    get position() {
      return Panel.getValue(
        PanelSettingConfig.qmsg_config_position.key,
        PanelSettingConfig.qmsg_config_position.defaultValue
      );
    },
    get maxNums() {
      return Panel.getValue(
        PanelSettingConfig.qmsg_config_maxnums.key,
        PanelSettingConfig.qmsg_config_maxnums.defaultValue
      );
    },
    get showReverse() {
      return Panel.getValue(
        PanelSettingConfig.qmsg_config_showreverse.key,
        PanelSettingConfig.qmsg_config_showreverse.defaultValue
      );
    },
    get zIndex() {
      let maxZIndex = Utils.getMaxZIndex();
      let popsMaxZIndex = pops.config.InstanceUtils.getPopsMaxZIndex().zIndex;
      return Utils.getMaxValue(maxZIndex, popsMaxZIndex) + 100;
    },
  });
  __pops__.GlobalConfig.setGlobalConfig({
    zIndex: () => {
      const maxZIndex = Utils.getMaxZIndex(void 0, void 0, ($ele) => {
        if ($ele?.classList?.contains("qmsg-shadow-container")) {
          return false;
        }
        if ($ele?.closest("qmsg") && $ele.getRootNode() instanceof ShadowRoot) {
          return false;
        }
      });
      const popsMaxZIndex = pops.config.InstanceUtils.getPopsMaxZIndex().zIndex;
      return Utils.getMaxValue(maxZIndex, popsMaxZIndex) + 100;
    },
    mask: {
      enable: true,
      clickEvent: {
        toClose: false,
        toHide: false,
      },
    },
    drag: true,
  });
  const MenuRegister = new utils.GM_Menu({
    GM_getValue: _GM_getValue,
    GM_setValue: _GM_setValue,
    GM_registerMenuCommand: _GM_registerMenuCommand,
    GM_unregisterMenuCommand: _GM_unregisterMenuCommand,
  });
  const httpx = new utils.Httpx({
    xmlHttpRequest: _GM_xmlhttpRequest,
    logDetails: DEBUG,
  });
  httpx.interceptors.request.use((data) => {
    return data;
  });
  httpx.interceptors.response.use(void 0, (data) => {
    log.error("拦截器-请求错误", data);
    if (data.type === "onabort") {
      Qmsg.warning("请求取消", { consoleLogContent: true });
    } else if (data.type === "onerror") {
      Qmsg.error("请求异常", { consoleLogContent: true });
    } else if (data.type === "ontimeout") {
      Qmsg.error("请求超时", { consoleLogContent: true });
    } else {
      Qmsg.error("其它错误", { consoleLogContent: true });
    }
    return data;
  });
  ({
    Object: {
      defineProperty: _unsafeWindow.Object.defineProperty,
    },
    Function: {
      apply: _unsafeWindow.Function.prototype.apply,
      call: _unsafeWindow.Function.prototype.call,
    },
    Element: {
      appendChild: _unsafeWindow.Element.prototype.appendChild,
    },
    setTimeout: _unsafeWindow.setTimeout,
  });
  const addStyle = domUtils.addStyle.bind(domUtils);
  const $ = DOMUtils.selector.bind(DOMUtils);
  const $$ = DOMUtils.selectorAll.bind(DOMUtils);
  new utils.GM_Cookie();
  const KEY = "GM_Panel";
  const ATTRIBUTE_INIT = "data-init";
  const ATTRIBUTE_KEY = "data-key";
  const ATTRIBUTE_DEFAULT_VALUE = "data-default-value";
  const ATTRIBUTE_INIT_MORE_VALUE = "data-init-more-value";
  const ATTRIBUTE_PLUGIN_SEARCH_CONFIG = "data-plugin-search-config";
  const PROPS_STORAGE_API = "data-storage-api";
  const PanelSizeUtil = {
    get width() {
      return globalThis.innerWidth;
    },
    get height() {
      return globalThis.innerHeight;
    },
  };
  const PanelUISize = {
    setting: {
      get width() {
        if (PanelSizeUtil.width < 550) {
          return "88vw";
        } else if (PanelSizeUtil.width < 700) {
          return "550px";
        } else {
          return "700px";
        }
      },
      get height() {
        if (PanelSizeUtil.height < 450) {
          return "70vh";
        } else if (PanelSizeUtil.height < 550) {
          return "450px";
        } else {
          return "550px";
        }
      },
    },
    settingMiddle: {
      get width() {
        return PanelSizeUtil.width < 350 ? "88vw" : "350px";
      },
    },
    settingBig: {
      get width() {
        return PanelSizeUtil.width < 800 ? "92vw" : "800px";
      },
      get height() {
        return PanelSizeUtil.height < 600 ? "80vh" : "600px";
      },
    },
    info: {
      get width() {
        return PanelSizeUtil.width < 350 ? "88vw" : "350px";
      },
      get height() {
        return PanelSizeUtil.height < 250 ? "88vh" : "250px";
      },
    },
  };
  const PanelContent = {
    $data: {
      __contentConfig: null,
      get contentConfig() {
        if (this.__contentConfig == null) {
          this.__contentConfig = new utils.Dictionary();
        }
        return this.__contentConfig;
      },
      __defaultBottomContentConfig: [],
    },
    addContentConfig(configList) {
      if (!Array.isArray(configList)) {
        configList = [configList];
      }
      let index = this.$data.contentConfig.keys().length;
      this.$data.contentConfig.set(index, configList);
    },
    getAllContentConfig() {
      return this.$data.contentConfig.values().flat();
    },
    getConfig(index = 0) {
      return this.$data.contentConfig.get(index) ?? [];
    },
    getDefaultBottomContentConfig() {
      if (this.$data.__defaultBottomContentConfig.length) {
        return this.$data.__defaultBottomContentConfig;
      }
      let isDoubleClick = false;
      let timer = void 0;
      const exportToFile = (fileName, fileData) => {
        if (typeof fileData !== "string") {
          fileData = CommonUtil.toStr(fileData);
        }
        const blob = new Blob([fileData]);
        const blobUrl = globalThis.URL.createObjectURL(blob);
        const $anchor = domUtils.createElement("a", {
          href: blobUrl,
          download: fileName,
        });
        $anchor.click();
        utils.workerSetTimeout(() => {
          globalThis.URL.revokeObjectURL(blobUrl);
        }, 500);
      };
      const dbclick_callback = () => {
        const importConfig = (importEndCallBack) => {
          const $alert = __pops__.alert({
            title: {
              text: "请选择导入方式",
              position: "center",
            },
            content: {
              text: `
            <div class="btn-control" data-mode="local">本地导入</div>
            <div class="btn-control" data-mode="network">网络导入</div>
            <div class="btn-control" data-mode="clipboard">剪贴板导入</div>`,
              html: true,
            },
            btn: {
              ok: { enable: false },
              close: {
                enable: true,
                callback(details, event) {
                  details.close();
                },
              },
            },
            drag: true,
            mask: {
              enable: true,
            },
            width: PanelUISize.info.width,
            height: PanelUISize.info.height,
            style: `
          .btn-control{
              display: inline-block;
              margin: 10px;
              padding: 10px;
              border: 1px solid #ccc;
              border-radius: 5px;
              cursor: pointer;
          }
          .btn-control:hover{
            color: #409eff;
            border-color: #c6e2ff;
            background-color: #ecf5ff;
          }`,
          });
          const $local = $alert.$shadowRoot.querySelector(".btn-control[data-mode='local']");
          const $network = $alert.$shadowRoot.querySelector(".btn-control[data-mode='network']");
          const $clipboard = $alert.$shadowRoot.querySelector(".btn-control[data-mode='clipboard']");
          const updateConfigToStorage = async (data) => {
            const clearLocalStorage = confirm("是否清空脚本存储的配置?(如果点击取消按钮,则仅做配置覆盖处理)");
            if (clearLocalStorage) {
              if (typeof _GM_listValues === "function") {
                if (typeof _GM_deleteValue === "function") {
                  const localStorageKeys = _GM_listValues();
                  localStorageKeys.forEach((key) => {
                    _GM_deleteValue(key);
                  });
                  Qmsg.success("已清空脚本存储的配置");
                } else {
                  Qmsg.error("不支持GM_deleteValue函数,无法执行删除脚本配置");
                }
              } else {
                Qmsg.error("不支持GM_listValues函数,无法清空脚本存储的配置");
              }
            }
            if (typeof _GM_setValues === "function") {
              _GM_setValues(data);
            } else {
              const keys = Object.keys(data);
              keys.forEach((key) => {
                const value = data[key];
                _GM_setValue(key, value);
              });
            }
            Qmsg.success("配置导入完毕");
          };
          const importFile = (configText) => {
            return new Promise(async (resolve) => {
              const data = utils.toJSON(configText);
              if (Object.keys(data).length === 0) {
                Qmsg.warning("解析为空配置,不导入");
              } else {
                await updateConfigToStorage(data);
              }
              resolve(true);
            });
          };
          domUtils.on($local, "click", (event) => {
            domUtils.preventEvent(event);
            $alert.close();
            const $input = domUtils.createElement("input", {
              type: "file",
              accept: ".json",
            });
            domUtils.on($input, ["propertychange", "input"], (event2) => {
              if (!$input.files?.length) {
                return;
              }
              const uploadFile = $input.files[0];
              const fileReader = new FileReader();
              fileReader.onload = () => {
                importFile(fileReader.result);
              };
              fileReader.readAsText(uploadFile, "UTF-8");
            });
            $input.click();
          });
          domUtils.on($network, "click", (event) => {
            domUtils.preventEvent(event);
            $alert.close();
            const $prompt = __pops__.prompt({
              title: {
                text: "网络导入",
                position: "center",
              },
              content: {
                text: "",
                placeholder: "请填写URL",
                focus: true,
              },
              btn: {
                close: {
                  enable: true,
                  callback(details, event2) {
                    details.close();
                  },
                },
                ok: {
                  text: "导入",
                  callback: async (details, event2) => {
                    const url = details.text;
                    if (utils.isNull(url)) {
                      Qmsg.error("请填入完整的url");
                      return;
                    }
                    const $loading = Qmsg.loading("正在获取配置...");
                    const response = await httpx.get(url, {
                      allowInterceptConfig: false,
                    });
                    $loading.close();
                    if (!response.status) {
                      log.error(response);
                      Qmsg.error("获取配置失败", { consoleLogContent: true });
                      return;
                    }
                    const flag = await importFile(response.data.responseText);
                    if (!flag) {
                      return;
                    }
                    details.close();
                  },
                },
                cancel: {
                  enable: false,
                },
              },
              drag: true,
              mask: {
                enable: true,
              },
              width: PanelUISize.info.width,
              height: "auto",
            });
            const $promptInput = $prompt.$shadowRoot.querySelector("input");
            const $promptOk = $prompt.$shadowRoot.querySelector(".pops-prompt-btn-ok");
            domUtils.on($promptInput, ["input", "propertychange"], (event2) => {
              const value = domUtils.val($promptInput);
              if (value === "") {
                domUtils.attr($promptOk, "disabled", "true");
              } else {
                domUtils.removeAttr($promptOk, "disabled");
              }
            });
            domUtils.onKeyboard($promptInput, "keydown", (keyName, keyValue, otherCodeList) => {
              if (keyName === "Enter" && otherCodeList.length === 0) {
                const value = domUtils.val($promptInput);
                if (value !== "") {
                  domUtils.emit($promptOk, "click");
                }
              }
            });
            domUtils.emit($promptInput, "input");
          });
          domUtils.on($clipboard, "click", async (event) => {
            domUtils.preventEvent(event);
            $alert.close();
            let clipboardText = await CommonUtil.getClipboardText();
            if (clipboardText.trim() === "") {
              Qmsg.warning("获取到的剪贴板内容为空");
              return;
            }
            const flag = await importFile(clipboardText);
            if (!flag) {
              return;
            }
          });
        };
        const exportConfig = (
          fileName = `${SCRIPT_NAME}_panel-setting-${utils.formatTime(Date.now(), "yyyy_MM_dd_HH_mm_ss")}.json`,
          fileData
        ) => {
          const $alert = __pops__.alert({
            title: {
              text: "请选择导出方式",
              position: "center",
            },
            content: {
              text: `
            <div class="btn-control" data-mode="export-to-file">导出至文件</div>
            <div class="btn-control" data-mode="export-to-clipboard">导出至剪贴板</div>
            `,
              html: true,
            },
            btn: {
              ok: { enable: false },
              close: {
                enable: true,
                callback(details, event) {
                  details.close();
                },
              },
            },
            drag: true,
            mask: {
              enable: true,
            },
            width: PanelUISize.info.width,
            height: PanelUISize.info.height,
            style: `
          .btn-control{
              display: inline-block;
              margin: 10px;
              padding: 10px;
              border: 1px solid #ccc;
              border-radius: 5px;
              cursor: pointer;
          }
          .btn-control:hover{
            color: #409eff;
            border-color: #c6e2ff;
            background-color: #ecf5ff;
          }`,
          });
          const $exportToFile = $alert.$shadowRoot.querySelector(".btn-control[data-mode='export-to-file']");
          const $exportToClipboard = $alert.$shadowRoot.querySelector(".btn-control[data-mode='export-to-clipboard']");
          domUtils.on($exportToFile, "click", (event) => {
            domUtils.preventEvent(event);
            try {
              exportToFile(fileName, fileData);
              $alert.close();
            } catch (error) {
              Qmsg.error(error.toString(), { consoleLogContent: true });
            }
          });
          domUtils.on($exportToClipboard, "click", async (event) => {
            const result = await utils.copy(fileData);
            if (result) {
              Qmsg.success("复制成功");
              $alert.close();
            } else {
              Qmsg.error("复制失败");
            }
          });
        };
        const $dialog = __pops__.confirm({
          title: {
            text: "配置",
            position: "center",
          },
          content: {
            text: `
            <textarea name="config-value" id="config" readonly></textarea>
          `,
            html: true,
          },
          btn: {
            ok: {
              enable: true,
              type: "primary",
              text: "导入",
              callback(eventDetails, event) {
                importConfig();
              },
            },
            cancel: {
              enable: true,
              text: "导出",
              callback(eventDetails, event) {
                exportConfig(void 0, configDataStr);
              },
            },
          },
          width: PanelSizeUtil.width < 450 ? "90vw" : "450px",
          height: "auto",
          style: `
          .pops-content textarea {
            --textarea-bd-color: #dcdfe6;
            display: inline-block;
            resize: vertical;
            padding: 5px 15px;
            margin: 0;
            line-height: normal;
            box-sizing: border-box;
            color: #606266;
            border: 0;
            border-radius: 0;
            outline: none;
            -webkit-appearance: none;
            -moz-appearance: none;
            appearance: none;
            background: none;
            width: 100%;
            height: 100%;
            appearance: none;
            resize: none;
          }
          .pops-content textarea{
            height: 500px;
          }
          .pops-content textarea:focus {
            --textarea-bd-color: #3677f0;
          }
          .pops-content textarea:hover {
            --textarea-bd-color: #c0c4cc;
          }
        `,
        });
        const $textarea = $dialog.$shadowRoot.querySelector("textarea");
        const configData = {};
        if (typeof _GM_listValues === "function") {
          const LocalKeys = _GM_listValues();
          LocalKeys.forEach((key) => {
            const value = _GM_getValue(key);
            Reflect.set(configData, key, value);
          });
        } else {
          Qmsg.warning("不支持函数GM_listValues,仅导出菜单配置");
          const panelLocalValue = _GM_getValue(KEY);
          Reflect.set(configData, KEY, panelLocalValue);
        }
        const configDataStr = CommonUtil.toStr(configData);
        $textarea.value = configDataStr;
      };
      const click_callback = () => {
        let supportURL = _GM_info?.script?.supportURL || _GM_info?.script?.namespace;
        if (typeof supportURL === "string" && utils.isNotNull(supportURL)) {
          window.open(supportURL, "_blank");
        }
      };
      return [
        {
          id: "script-version",
          title: `版本:${_GM_info?.script?.version || "未知"}`,
          isBottom: true,
          views: [],
          clickFirstCallback() {
            return false;
          },
          afterRender(config) {
            const anyTouch = new AnyTouch(config.$asideLiElement);
            anyTouch.on("tap", function (event) {
              clearTimeout(timer);
              timer = void 0;
              if (isDoubleClick) {
                isDoubleClick = false;
                dbclick_callback();
              } else {
                timer = setTimeout(() => {
                  isDoubleClick = false;
                  click_callback();
                }, 200);
                isDoubleClick = true;
              }
            });
          },
        },
      ];
    },
    setDefaultBottomContentConfig(config) {
      this.$data.__defaultBottomContentConfig = config;
    },
  };
  const PanelMenu = {
    $data: {
      __menuOption: [
        {
          key: "show_pops_panel_setting",
          text: "⚙ 设置",
          autoReload: false,
          isStoreValue: false,
          showText(text) {
            return text;
          },
          callback: () => {
            Panel.showPanel(PanelContent.getConfig(0));
          },
        },
      ],
      get menuOption() {
        return this.__menuOption;
      },
    },
    init() {
      this.initExtensionsMenu();
    },
    initExtensionsMenu() {
      if (!Panel.isTopWindow()) {
        return;
      }
      MenuRegister.add(this.$data.menuOption);
    },
    addMenuOption(option) {
      if (!Array.isArray(option)) {
        option = [option];
      }
      this.$data.menuOption.push(...option);
    },
    updateMenuOption(option) {
      if (!Array.isArray(option)) {
        option = [option];
      }
      option.forEach((optionItem) => {
        let findIndex = this.$data.menuOption.findIndex((it) => {
          return it.key === optionItem.key;
        });
        if (findIndex !== -1) {
          this.$data.menuOption[findIndex] = optionItem;
        }
      });
    },
    getMenuOption(index = 0) {
      return this.$data.menuOption[index];
    },
    deleteMenuOption(index = 0) {
      this.$data.menuOption.splice(index, 1);
    },
  };
  class StorageUtils {
    storageKey;
    listenerData;
    constructor(key) {
      if (typeof key === "string") {
        const trimKey = key.trim();
        if (trimKey == "") {
          throw new Error("key参数不能为空字符串");
        }
        this.storageKey = trimKey;
      } else {
        throw new Error("key参数类型错误,必须是字符串");
      }
      this.listenerData = new Utils.Dictionary();
      this.getLocalValue = this.getLocalValue.bind(this);
      this.set = this.set.bind(this);
      this.get = this.get.bind(this);
      this.getAll = this.getAll.bind(this);
      this.delete = this.delete.bind(this);
      this.has = this.has.bind(this);
      this.keys = this.keys.bind(this);
      this.values = this.values.bind(this);
      this.clear = this.clear.bind(this);
      this.addValueChangeListener = this.addValueChangeListener.bind(this);
      this.removeValueChangeListener = this.removeValueChangeListener.bind(this);
      this.emitValueChangeListener = this.emitValueChangeListener.bind(this);
    }
    getLocalValue() {
      let localValue = _GM_getValue(this.storageKey);
      if (localValue == null) {
        localValue = {};
        this.setLocalValue(localValue);
      }
      return localValue;
    }
    setLocalValue(value) {
      _GM_setValue(this.storageKey, value);
    }
    set(key, value) {
      const oldValue = this.get(key);
      const localValue = this.getLocalValue();
      Reflect.set(localValue, key, value);
      this.setLocalValue(localValue);
      this.emitValueChangeListener(key, oldValue, value);
    }
    get(key, defaultValue) {
      const localValue = this.getLocalValue();
      return Reflect.get(localValue, key) ?? defaultValue;
    }
    getAll() {
      const localValue = this.getLocalValue();
      return localValue;
    }
    delete(key) {
      const oldValue = this.get(key);
      const localValue = this.getLocalValue();
      Reflect.deleteProperty(localValue, key);
      this.setLocalValue(localValue);
      this.emitValueChangeListener(key, oldValue, void 0);
    }
    has(key) {
      const localValue = this.getLocalValue();
      return Reflect.has(localValue, key);
    }
    keys() {
      const localValue = this.getLocalValue();
      return Reflect.ownKeys(localValue);
    }
    values() {
      const localValue = this.getLocalValue();
      return Reflect.ownKeys(localValue).map((key) => Reflect.get(localValue, key));
    }
    clear() {
      _GM_deleteValue(this.storageKey);
    }
    addValueChangeListener(key, callback) {
      const listenerId = Math.random();
      const listenerData = this.listenerData.get(key) || [];
      listenerData.push({
        id: listenerId,
        key,
        callback,
      });
      this.listenerData.set(key, listenerData);
      return listenerId;
    }
    removeValueChangeListener(listenerId) {
      let flag = false;
      for (const [key, listenerData] of this.listenerData.entries()) {
        for (let index = 0; index < listenerData.length; index++) {
          const value = listenerData[index];
          if (
            (typeof listenerId === "string" && value.key === listenerId) ||
            (typeof listenerId === "number" && value.id === listenerId)
          ) {
            listenerData.splice(index, 1);
            index--;
            flag = true;
          }
        }
        this.listenerData.set(key, listenerData);
      }
      return flag;
    }
    async emitValueChangeListener(...args) {
      const [key, oldValue, newValue] = args;
      if (!this.listenerData.has(key)) {
        return;
      }
      let listenerData = this.listenerData.get(key);
      for (let index = 0; index < listenerData.length; index++) {
        const data = listenerData[index];
        if (typeof data.callback === "function") {
          let value = this.get(key);
          let __newValue;
          let __oldValue;
          if (typeof oldValue !== "undefined" && args.length >= 2) {
            __oldValue = oldValue;
          } else {
            __oldValue = value;
          }
          if (typeof newValue !== "undefined" && args.length > 2) {
            __newValue = newValue;
          } else {
            __newValue = value;
          }
          await data.callback(key, __oldValue, __newValue);
        }
      }
    }
  }
  const PopsPanelStorageApi = new StorageUtils(KEY);
  const Panel = {
    $data: {
      __contentConfigInitDefaultValue: null,
      __onceExecMenuData: null,
      __urlChangeReloadMenuExecOnce: null,
      __onceExecData: null,
      __panelConfig: {},
      $panel: null,
      panelContent: [],
      get contentConfigInitDefaultValue() {
        if (this.__contentConfigInitDefaultValue == null) {
          this.__contentConfigInitDefaultValue = new utils.Dictionary();
        }
        return this.__contentConfigInitDefaultValue;
      },
      contentConfigInitDisabledKeys: [],
      get onceExecMenuData() {
        if (this.__onceExecMenuData == null) {
          this.__onceExecMenuData = new utils.Dictionary();
        }
        return this.__onceExecMenuData;
      },
      get urlChangeReloadMenuExecOnce() {
        if (this.__urlChangeReloadMenuExecOnce == null) {
          this.__urlChangeReloadMenuExecOnce = new utils.Dictionary();
        }
        return this.__urlChangeReloadMenuExecOnce;
      },
      get onceExecData() {
        if (this.__onceExecData == null) {
          this.__onceExecData = new utils.Dictionary();
        }
        return this.__onceExecData;
      },
      get scriptName() {
        return SCRIPT_NAME;
      },
      get panelConfig() {
        return this.__panelConfig;
      },
      set panelConfig(value) {
        this.__panelConfig = value;
      },
      key: KEY,
      attributeKeyName: ATTRIBUTE_KEY,
      attributeDefaultValueName: ATTRIBUTE_DEFAULT_VALUE,
    },
    init() {
      this.initContentDefaultValue();
      PanelMenu.init();
    },
    isTopWindow() {
      return _unsafeWindow.top === _unsafeWindow.self;
    },
    initContentDefaultValue() {
      const initDefaultValue = (config) => {
        if (!config.attributes) {
          return;
        }
        if (config.type === "button" || config.type === "container" || config.type === "deepMenu") {
          return;
        }
        const attributes = config.attributes;
        let __attr_init__ = attributes[ATTRIBUTE_INIT];
        if (typeof __attr_init__ === "function") {
          let __attr_result__ = __attr_init__();
          if (typeof __attr_result__ === "boolean" && !__attr_result__) {
            return;
          }
        }
        let menuDefaultConfig = new Map();
        let key = attributes[ATTRIBUTE_KEY];
        if (key != null) {
          const defaultValue = attributes[ATTRIBUTE_DEFAULT_VALUE];
          menuDefaultConfig.set(key, defaultValue);
        }
        let moreMenuDefaultConfig = attributes[ATTRIBUTE_INIT_MORE_VALUE];
        if (typeof moreMenuDefaultConfig === "object" && moreMenuDefaultConfig) {
          Object.keys(moreMenuDefaultConfig).forEach((key2) => {
            const defaultValue = moreMenuDefaultConfig[key2];
            menuDefaultConfig.set(key2, defaultValue);
          });
        }
        if (!menuDefaultConfig.size) {
          log.warn(["请先配置键", config]);
          return;
        }
        if (config.type === "switch") {
          let disabled = typeof config.disabled === "function" ? config.disabled() : config.disabled;
          if (typeof disabled === "boolean" && disabled) {
            this.$data.contentConfigInitDisabledKeys.push(...menuDefaultConfig.keys());
          }
        }
        for (const [__key, __defaultValue] of menuDefaultConfig.entries()) {
          this.setDefaultValue(__key, __defaultValue);
        }
      };
      const loopInitDefaultValue = (configList) => {
        for (let index = 0; index < configList.length; index++) {
          let configItem = configList[index];
          initDefaultValue(configItem);
          let childViews = configItem.views;
          if (childViews && Array.isArray(childViews)) {
            loopInitDefaultValue(childViews);
          }
        }
      };
      const contentConfigList = [...PanelContent.getAllContentConfig()];
      for (let index = 0; index < contentConfigList.length; index++) {
        let leftContentConfigItem = contentConfigList[index];
        if (!leftContentConfigItem.views) {
          continue;
        }
        const rightContentConfigList = leftContentConfigItem.views;
        if (rightContentConfigList && Array.isArray(rightContentConfigList)) {
          loopInitDefaultValue(rightContentConfigList);
        }
      }
      this.$data.contentConfigInitDisabledKeys = [...new Set(this.$data.contentConfigInitDisabledKeys)];
    },
    setDefaultValue(key, defaultValue) {
      if (this.$data.contentConfigInitDefaultValue.has(key)) {
        log.warn("请检查该key(已存在): " + key);
      }
      this.$data.contentConfigInitDefaultValue.set(key, defaultValue);
    },
    getDefaultValue(key) {
      return this.$data.contentConfigInitDefaultValue.get(key);
    },
    setValue(key, value) {
      PopsPanelStorageApi.set(key, value);
    },
    getValue(key, defaultValue) {
      const localValue = PopsPanelStorageApi.get(key);
      if (localValue == null) {
        if (this.$data.contentConfigInitDefaultValue.has(key)) {
          return this.$data.contentConfigInitDefaultValue.get(key);
        }
        return defaultValue;
      }
      return localValue;
    },
    deleteValue(key) {
      PopsPanelStorageApi.delete(key);
    },
    hasKey(key) {
      return PopsPanelStorageApi.has(key);
    },
    addValueChangeListener(key, callback) {
      const listenerId = PopsPanelStorageApi.addValueChangeListener(key, (__key, __newValue, __oldValue) => {
        callback(key, __oldValue, __newValue);
      });
      return listenerId;
    },
    removeValueChangeListener(listenerId) {
      PopsPanelStorageApi.removeValueChangeListener(listenerId);
    },
    emitMenuValueChange(key, newValue, oldValue) {
      PopsPanelStorageApi.emitValueChangeListener(key, oldValue, newValue);
    },
    async exec(queryKey, callback, checkExec, once = true) {
      const that = this;
      let queryKeyFn;
      if (typeof queryKey === "string" || Array.isArray(queryKey)) {
        queryKeyFn = () => queryKey;
      } else {
        queryKeyFn = queryKey;
      }
      let isArrayKey = false;
      const queryKeyResult = queryKeyFn();
      let keyList = [];
      if (Array.isArray(queryKeyResult)) {
        isArrayKey = true;
        keyList = queryKeyResult;
      } else {
        keyList.push(queryKeyResult);
      }
      const findNotInDataKey = keyList.find((it) => !this.$data.contentConfigInitDefaultValue.has(it));
      if (findNotInDataKey) {
        log.warn(`${findNotInDataKey} 键不存在`);
        return;
      }
      const storageKey = JSON.stringify(keyList);
      if (once) {
        if (this.$data.onceExecMenuData.has(storageKey)) {
          return this.$data.onceExecMenuData.get(storageKey);
        }
      }
      let storeValueList = [];
      const listenerIdList = [];
      let destoryFnList = [];
      const addStoreValueCallback = (enableValue, args) => {
        let dynamicMenuStoreValueList = [];
        let dynamicDestoryFnList = [];
        let resultValueList = [];
        if (Array.isArray(args)) {
          resultValueList = resultValueList.concat(args);
        } else {
          const handlerArgs = (obj) => {
            if (typeof obj === "object" && obj != null) {
              if (obj instanceof Element) {
                resultValueList.push(obj);
              } else {
                const { $css, destory } = obj;
                if ($css != null) {
                  if (Array.isArray($css)) {
                    resultValueList = resultValueList.concat($css);
                  } else {
                    resultValueList.push($css);
                  }
                }
                if (typeof destory === "function") {
                  resultValueList.push(destory);
                }
              }
            } else {
              resultValueList.push(obj);
            }
          };
          if (args != null && Array.isArray(args)) {
            for (const it of args) {
              handlerArgs(it);
            }
          } else {
            handlerArgs(args);
          }
        }
        for (const it of resultValueList) {
          if (it == null) {
            continue;
          }
          if (it instanceof Element) {
            dynamicMenuStoreValueList.push(it);
            continue;
          }
          if (typeof it === "function") {
            destoryFnList.push(it);
            continue;
          }
        }
        if (enableValue) {
          storeValueList = storeValueList.concat(dynamicMenuStoreValueList);
          destoryFnList = destoryFnList.concat(dynamicDestoryFnList);
        } else {
          execClearStoreStyleElements();
          execDestory();
        }
      };
      const getMenuValue = (key) => {
        const value = this.getValue(key);
        return Boolean(value);
      };
      const execClearStoreStyleElements = () => {
        for (let index = 0; index < storeValueList.length; index++) {
          const $css = storeValueList[index];
          $css?.remove();
          storeValueList.splice(index, 1);
          index--;
        }
      };
      const execDestory = () => {
        for (let index = 0; index < destoryFnList.length; index++) {
          const destoryFnItem = destoryFnList[index];
          destoryFnItem();
          destoryFnList.splice(index, 1);
          index--;
        }
      };
      const checkMenuExec = () => {
        let flag = false;
        if (typeof checkExec === "function") {
          flag = checkExec(keyList);
        } else {
          flag = keyList.every((key) => getMenuValue(key));
        }
        return flag;
      };
      const valueChangeCallback = async (valueOption) => {
        const execFlag = checkMenuExec();
        if (execFlag) {
          const valueList = keyList.map((key) => this.getValue(key));
          const callbackResult = await callback({
            value: isArrayKey ? valueList : valueList[0],
            addStoreValue: (...args) => {
              return addStoreValueCallback(true, args);
            },
          });
          addStoreValueCallback(true, callbackResult);
        } else {
          addStoreValueCallback(false, []);
        }
      };
      once &&
        keyList.forEach((key) => {
          const listenerId = this.addValueChangeListener(key, (key2, newValue, oldValue) => {
            return valueChangeCallback();
          });
          listenerIdList.push(listenerId);
        });
      await valueChangeCallback();
      const result = {
        reload() {
          this.clearStoreStyleElements();
          this.destory();
          valueChangeCallback();
        },
        clear() {
          this.clearStoreStyleElements();
          this.destory();
          this.removeValueChangeListener();
          this.clearOnceExecMenuData();
        },
        clearStoreStyleElements: () => {
          return execClearStoreStyleElements();
        },
        destory() {
          return execDestory();
        },
        removeValueChangeListener: () => {
          listenerIdList.forEach((listenerId) => {
            this.removeValueChangeListener(listenerId);
          });
        },
        clearOnceExecMenuData() {
          once && that.$data.onceExecMenuData.delete(storageKey);
        },
      };
      this.$data.onceExecMenuData.set(storageKey, result);
      return result;
    },
    async execMenu(key, callback, isReverse = false, once = false) {
      return await this.exec(
        key,
        async (option) => {
          return await callback(option);
        },
        (keyList) => {
          const execFlag = keyList.every((__key__) => {
            let flag = !!this.getValue(__key__);
            const disabled = Panel.$data.contentConfigInitDisabledKeys.includes(__key__);
            if (disabled) {
              flag = false;
              log.warn(`.execMenu${once ? "Once" : ""} ${__key__} 被禁用`);
            }
            isReverse && (flag = !flag);
            return flag;
          });
          return execFlag;
        },
        once
      );
    },
    async execMenuOnce(key, callback, isReverse = false, listenUrlChange = false) {
      const result = await this.execMenu(key, callback, isReverse, true);
      if (listenUrlChange) {
        if (result) {
          const urlChangeEvent = () => {
            result.reload();
          };
          this.removeUrlChangeWithExecMenuOnceListener(key);
          this.addUrlChangeWithExecMenuOnceListener(key, urlChangeEvent);
        }
      }
      return result;
    },
    deleteExecMenuOnce(key) {
      key = this.transformKey(key);
      this.$data.onceExecMenuData.delete(key);
      this.$data.urlChangeReloadMenuExecOnce.delete(key);
      const flag = PopsPanelStorageApi.removeValueChangeListener(key);
      return flag;
    },
    onceExec(key, callback) {
      key = this.transformKey(key);
      if (typeof key !== "string") {
        throw new TypeError("key 必须是字符串");
      }
      if (this.$data.onceExecData.has(key)) {
        return;
      }
      callback();
      this.$data.onceExecData.set(key, 1);
    },
    deleteOnceExec(key) {
      key = this.transformKey(key);
      this.$data.onceExecData.delete(key);
    },
    addUrlChangeWithExecMenuOnceListener(key, callback) {
      key = this.transformKey(key);
      this.$data.urlChangeReloadMenuExecOnce.set(key, callback);
    },
    removeUrlChangeWithExecMenuOnceListener(key) {
      key = this.transformKey(key);
      this.$data.urlChangeReloadMenuExecOnce.delete(key);
    },
    hasUrlChangeWithExecMenuOnceListener(key) {
      key = this.transformKey(key);
      return this.$data.urlChangeReloadMenuExecOnce.has(key);
    },
    async emitUrlChangeWithExecMenuOnceEvent(config) {
      const values = this.$data.urlChangeReloadMenuExecOnce.values();
      for (const callback of values) {
        await callback(config);
      }
    },
    showPanel(
      content,
      title = `${SCRIPT_NAME}-设置`,
      preventDefaultContentConfig = false,
      preventRegisterSearchPlugin = false
    ) {
      this.$data.$panel = null;
      this.$data.panelContent = [];
      let checkHasBottomVersionContentConfig =
        content.findIndex((it) => {
          let isBottom = typeof it.isBottom === "function" ? it.isBottom() : Boolean(it.isBottom);
          return isBottom && it.id === "script-version";
        }) !== -1;
      if (!preventDefaultContentConfig && !checkHasBottomVersionContentConfig) {
        content.push(...PanelContent.getDefaultBottomContentConfig());
      }
      let $panel = __pops__.panel({
        ...{
          title: {
            text: title,
            position: "center",
            html: false,
            style: "",
          },
          content,
          btn: {
            close: {
              enable: true,
              callback: (details, event) => {
                details.close();
                this.$data.$panel = null;
              },
            },
          },
          mask: {
            enable: true,
            clickEvent: {
              toClose: true,
              toHide: false,
            },
            clickCallBack: (originalRun, config) => {
              originalRun();
              this.$data.$panel = null;
            },
          },
          width: PanelUISize.setting.width,
          height: PanelUISize.setting.height,
          drag: true,
          only: true,
        },
        ...this.$data.panelConfig,
      });
      this.$data.$panel = $panel;
      this.$data.panelContent = content;
      if (!preventRegisterSearchPlugin) {
        this.registerConfigSearch({ $panel, content });
      }
    },
    registerConfigSearch(config) {
      const { $panel, content } = config;
      const asyncQueryProperty = async (target, handler) => {
        if (target == null) {
          return;
        }
        const handleResult = await handler(target);
        if (handleResult && typeof handleResult.isFind === "boolean" && handleResult.isFind) {
          return handleResult.data;
        }
        return await asyncQueryProperty(handleResult.data, handler);
      };
      const scrollToElementAndListen = ($el, callback) => {
        const observer = new IntersectionObserver(
          (entries) => {
            entries.forEach((entry) => {
              if (entry.isIntersecting) {
                callback?.();
                observer.disconnect();
              }
            });
          },
          {
            root: null,
            threshold: 1,
          }
        );
        observer.observe($el);
        $el.scrollIntoView({ behavior: "smooth", block: "center" });
      };
      const addFlashingClass = ($el) => {
        const flashingClassName = "pops-flashing";
        domUtils.onAnimationend($el, () => {
          $el.classList.remove(flashingClassName);
        });
        $el.classList.add(flashingClassName);
      };
      const dbclick_callback = (evt) => {
        if (evt.type === "dblclick" && isMobileTouch) {
          return;
        }
        domUtils.preventEvent(evt);
        clickElement = null;
        const $alert = __pops__.alert({
          title: {
            text: "搜索配置",
            position: "center",
          },
          content: {
            text: `
						<div class="search-wrapper">
							<input class="search-config-text" name="search-config" type="text" placeholder="请输入需要搜素的配置名称">
						</div>
						<div class="search-result-wrapper"></div>
					`,
            html: true,
          },
          btn: {
            ok: { enable: false },
          },
          mask: {
            clickEvent: {
              toClose: true,
            },
          },
          width: PanelUISize.settingMiddle.width,
          height: "auto",
          drag: true,
          style: `
					${__pops__.config.cssText.panelCSS}

					.search-wrapper{
						border-bottom: 1px solid rgb(235, 238, 245, 1);
					}
					.pops-content:has(.search-result-wrapper:empty) .search-wrapper{
						border-bottom: 0;
					}
					.search-config-text{
						width: 100%;
						border: 0;
						height: 32px;
						padding: 0px 10px;
						outline: none;
					}
					.search-result-wrapper{
						max-height: 400px;
						overflow: auto;
					}
					.search-result-item{
						cursor: pointer;
						padding: 5px 10px;
						display: flex;
						flex-direction: column;
					}
					.search-result-item:hover{
						background-color: #D8F1FD;
					}
					.search-result-item-path{
						display: flex;
    					align-items: center;
					}
					.search-result-item-description{
						font-size: 0.8em;
						color: #6c6c6c;
					}
					${config.searchDialogStyle ?? ""}
				`,
        });
        $alert.$shadowRoot.querySelector(".search-wrapper");
        const $searchInput = $alert.$shadowRoot.querySelector(".search-config-text");
        const $searchResultWrapper = $alert.$shadowRoot.querySelector(".search-result-wrapper");
        $searchInput.focus();
        const clearSearchResult = () => {
          domUtils.empty($searchResultWrapper);
        };
        const createSearchResultItem = (pathInfo) => {
          const searchPath = utils.queryProperty(pathInfo, (target) => {
            if (target?.next) {
              return {
                isFind: false,
                data: target.next,
              };
            } else {
              return {
                isFind: true,
                data: target,
              };
            }
          });
          const $item = domUtils.createElement("div", {
            className: "search-result-item",
            innerHTML: `
							<div class="search-result-item-path">${searchPath.matchedData?.path}</div>
							<div class="search-result-item-description">${searchPath.matchedData?.description ?? ""}</div>
						`,
          });
          const panelHandlerComponents = __pops__.config.PanelHandlerComponents();
          domUtils.on($item, "click", (clickItemEvent) => {
            const $asideItems2 = $panel.$shadowRoot.querySelectorAll(
              "aside.pops-panel-aside .pops-panel-aside-top-container li"
            );
            const $targetAsideItem = $asideItems2[pathInfo.index];
            if (!$targetAsideItem) {
              Qmsg.error(`左侧项下标${pathInfo.index}不存在`);
              return;
            }
            $targetAsideItem.scrollIntoView({
              behavior: "smooth",
              block: "center",
            });
            $targetAsideItem.click();
            asyncQueryProperty(pathInfo.next, async (target) => {
              if (target?.next) {
                const $findDeepMenu = await domUtils.waitNode(() => {
                  return Array.from($panel.$shadowRoot.querySelectorAll(".pops-panel-deepMenu-nav-item")).find(
                    ($deepMenu) => {
                      const viewConfig = Reflect.get($deepMenu, panelHandlerComponents.$data.nodeStoreConfigKey);
                      return typeof viewConfig === "object" && viewConfig != null && viewConfig.text === target.name;
                    }
                  );
                }, 2500);
                if ($findDeepMenu) {
                  $findDeepMenu.click();
                } else {
                  Qmsg.error("未找到对应的二级菜单");
                  return {
                    isFind: true,
                    data: target,
                  };
                }
                return {
                  isFind: false,
                  data: target.next,
                };
              } else {
                const $findTargetMenu = await domUtils.waitNode(() => {
                  return Array.from($panel.$shadowRoot.querySelectorAll(`li:not(.pops-panel-deepMenu-nav-item)`)).find(
                    ($menuItem) => {
                      const viewConfig = Reflect.get($menuItem, panelHandlerComponents.$data.nodeStoreConfigKey);
                      return viewConfig === target.matchedData?.formConfig;
                    }
                  );
                }, 2500);
                if ($findTargetMenu) {
                  scrollToElementAndListen($findTargetMenu);
                  const $fold = $findTargetMenu.closest(`.pops-panel-forms-fold[data-fold-enable]`);
                  if ($fold) {
                    const $foldWrapper = $fold.querySelector(".pops-panel-forms-fold-container");
                    $foldWrapper.click();
                    await utils.sleep(500);
                  }
                  scrollToElementAndListen($findTargetMenu, () => {
                    addFlashingClass($findTargetMenu);
                  });
                } else {
                  Qmsg.error("未找到对应的菜单项");
                }
                return {
                  isFind: true,
                  data: target,
                };
              }
            });
          });
          return $item;
        };
        const execSearch = (searchText) => {
          const searchTextRegExp = new RegExp(searchText, "i");
          const searchConfigResult = [];
          const loopContentConfig = (configList, path) => {
            for (let index = 0; index < configList.length; index++) {
              const configItem = configList[index];
              const childViewConfig = configItem.views;
              if (childViewConfig && Array.isArray(childViewConfig)) {
                const deepMenuPath = utils.deepClone(path);
                if (configItem.type === "deepMenu") {
                  const deepNext = utils.queryProperty(deepMenuPath, (target) => {
                    if (target?.next) {
                      return {
                        isFind: false,
                        data: target.next,
                      };
                    } else {
                      return {
                        isFind: true,
                        data: target,
                      };
                    }
                  });
                  deepNext.next = {
                    name: configItem.text,
                  };
                }
                loopContentConfig(childViewConfig, deepMenuPath);
              } else {
                let text;
                let description;
                if (configItem.type === "own") {
                  const searchConfig = Reflect.get(configItem.attributes || {}, ATTRIBUTE_PLUGIN_SEARCH_CONFIG);
                  if (searchConfig) {
                    if (typeof searchConfig.text === "string") {
                      text = searchConfig.text;
                    }
                    if (typeof searchConfig.desc === "string") {
                      description = searchConfig.desc;
                    }
                  }
                } else {
                  text = configItem.text;
                  description = Reflect.get(configItem, "description");
                }
                const delayMatchedTextList = [text, description];
                const matchedIndex = delayMatchedTextList.findIndex((configText) => {
                  if (typeof configText !== "string") {
                    return;
                  }
                  return configText.match(searchTextRegExp);
                });
                if (matchedIndex !== -1) {
                  const matchedPath = utils.deepClone(path);
                  const deepNext = utils.queryProperty(matchedPath, (target) => {
                    if (target?.next) {
                      return {
                        isFind: false,
                        data: target.next,
                      };
                    } else {
                      return {
                        isFind: true,
                        data: target,
                      };
                    }
                  });
                  deepNext.next = {
                    name: text,
                    matchedData: {
                      path: "",
                      formConfig: configItem,
                      matchedText: delayMatchedTextList[matchedIndex],
                      description,
                    },
                  };
                  const pathList = [];
                  utils.queryProperty(matchedPath, (target) => {
                    const name = target?.name;
                    if (typeof name === "string" && name.trim() !== "") {
                      pathList.push(name);
                    }
                    if (target?.next) {
                      return {
                        isFind: false,
                        data: target.next,
                      };
                    } else {
                      return {
                        isFind: true,
                        data: target,
                      };
                    }
                  });
                  const pathStr = pathList.join(CommonUtil.escapeHtml(" - "));
                  deepNext.next.matchedData.path = pathStr;
                  searchConfigResult.push(matchedPath);
                }
              }
            }
          };
          for (let index = 0; index < content.length; index++) {
            const leftContentConfigItem = content[index];
            if (!leftContentConfigItem.views) {
              continue;
            }
            if (leftContentConfigItem.isBottom && leftContentConfigItem.id === "script-version") {
              continue;
            }
            const rightContentConfigList = leftContentConfigItem.views;
            if (rightContentConfigList && Array.isArray(rightContentConfigList)) {
              let text = leftContentConfigItem.title;
              if (typeof text === "function") {
                text = text();
              }
              loopContentConfig(rightContentConfigList, {
                index,
                name: text,
              });
            }
          }
          const fragment = document.createDocumentFragment();
          for (const pathInfo of searchConfigResult) {
            let $resultItem = createSearchResultItem(pathInfo);
            fragment.appendChild($resultItem);
          }
          clearSearchResult();
          $searchResultWrapper.append(fragment);
        };
        domUtils.on(
          $searchInput,
          "input",
          utils.debounce((evt2) => {
            domUtils.preventEvent(evt2);
            let searchText = domUtils.val($searchInput).trim();
            if (searchText === "") {
              clearSearchResult();
              return;
            }
            execSearch(searchText);
          }, 200)
        );
      };
      const $asideItems = $panel.$shadowRoot.querySelectorAll(
        `aside.pops-panel-aside .pops-panel-aside-item:not(#script-version)`
      );
      $asideItems.forEach(($asideItem) => {
        domUtils.on($asideItem, "dblclick", dbclick_callback);
      });
      let clickElement = null;
      let isDoubleClick = false;
      let timer = void 0;
      let isMobileTouch = false;
      domUtils.on(
        $panel.$shadowRoot,
        "touchend",
        `aside.pops-panel-aside .pops-panel-aside-item:not(#script-version)`,
        (evt, selectorTarget) => {
          isMobileTouch = true;
          clearTimeout(timer);
          timer = void 0;
          if (isDoubleClick && clickElement === selectorTarget) {
            isDoubleClick = false;
            clickElement = null;
            dbclick_callback(evt);
          } else {
            timer = setTimeout(() => {
              isDoubleClick = false;
            }, 200);
            isDoubleClick = true;
            clickElement = selectorTarget;
          }
        },
        {
          capture: true,
        }
      );
      $panel.$shadowRoot.appendChild(
        domUtils.createElement("style", {
          type: "text/css",
          textContent: `
					.pops-flashing{
						animation: double-blink 1.5s ease-in-out;
					}
					@keyframes double-blink {
						 0% {
							background-color: initial;
						}
						25% {
							background-color: yellow;
						}
						50% {
							background-color: initial;
						}
						75% {
							background-color: yellow;
						}
						100% {
							background-color: initial;
						}
					}
				`,
        })
      );
    },
    transformKey(key) {
      if (Array.isArray(key)) {
        const keyArray = key.sort();
        return JSON.stringify(keyArray);
      } else {
        return key;
      }
    },
  };
  const MTIdentifyLinks = () => {
    const HANDLER_CLASS_NAME = "texttolink";
    const url_regexp =
      /((https?:\/\/|www\.)[\x21-\x7e]+[\w\/]|(\w[\w._-]+\.(com|cn|org|net|info|tv|cc))(\/[\x21-\x7e]*[\w\/])?|ed2k:\/\/[\x21-\x7e]+\|\/|thunder:\/\/[\x21-\x7e]+=)/gi;
    const handleClearLink = function (event) {
      let targetElement = event.originalTarget ?? event.target;
      let url;
      if (
        null != targetElement &&
        "a" === targetElement.localName &&
        -1 !== targetElement.className.indexOf(HANDLER_CLASS_NAME) &&
        ((url = targetElement.getAttribute("href")),
        typeof url === "string" &&
          0 !== url.indexOf("http") &&
          0 !== url.indexOf("ed2k://") &&
          0 !== url.indexOf("thunder://"))
      ) {
        return targetElement.setAttribute("href", "http://" + targetElement);
      }
    };
    const setLink = function (textNode) {
      if (typeof textNode != "object" || textNode == null) {
        return;
      }
      const textContent = textNode?.textContent;
      const $parent = textNode?.parentNode;
      if ($parent == null) {
        return;
      }
      if (
        -1 === $parent?.className?.indexOf?.(HANDLER_CLASS_NAME) &&
        "#cdata-section" !== textNode.nodeName &&
        typeof textContent === "string"
      ) {
        const modifiedContent = textContent.replace(
          url_regexp,
          `<a href="$1" target="_blank" class="${HANDLER_CLASS_NAME}">$1</a>`
        );
        if (textContent.length !== modifiedContent.length) {
          const spanElement = document.createElement("span");
          domUtils.html(spanElement, modifiedContent);
          const $url = spanElement.querySelector("a");
          const url = $url.href;
          console.log(`识别: ${url}`);
          const isSpanParent = $parent.nodeName.toLowerCase() === "span";
          if (isSpanParent) {
            return $parent.replaceChild($url, textNode);
          } else {
            return $parent.replaceChild(spanElement, textNode);
          }
        }
      }
    };
    const excludedTags =
      "a svg canvas applet input button area pre embed frame frameset head iframe img option map meta noscript object script style textarea code".split(
        " "
      );
    const xpath = `//text()[not(ancestor::${excludedTags.join(") and not(ancestor::")})]`;
    const filter = new RegExp(`^(${excludedTags.join("|")})$`, "i");
    const processLinksInBatches = function (textNodesSnapshot, startIndex) {
      let currentIndex, endIndex;
      if (startIndex + 1e4 < textNodesSnapshot.snapshotLength) {
        let start = (currentIndex = startIndex);
        for (
          endIndex = startIndex + 1e4;
          startIndex <= endIndex ? currentIndex <= endIndex : currentIndex >= endIndex;
          start = startIndex <= endIndex ? ++currentIndex : --currentIndex
        ) {
          setLink(textNodesSnapshot.snapshotItem(start));
        }
        setTimeout(function () {
          return processLinksInBatches(textNodesSnapshot, startIndex + 1e4);
        }, 15);
      } else {
        let start;
        for (
          start = currentIndex = startIndex, endIndex = textNodesSnapshot.snapshotLength;
          startIndex <= endIndex ? currentIndex <= endIndex : currentIndex >= endIndex;
          start = startIndex <= endIndex ? ++currentIndex : --currentIndex
        ) {
          setLink(textNodesSnapshot.snapshotItem(start));
        }
      }
    };
    const linkifyText = function (element) {
      const textNodesSnapshot = document.evaluate(xpath, element, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
      return processLinksInBatches(textNodesSnapshot, 0);
    };
    const observePageChanges = function (rootElement) {
      for (
        const treeWalker = document.createTreeWalker(rootElement, NodeFilter.SHOW_TEXT, {
          acceptNode: function (node) {
            const localName = node?.parentNode?.localName;
            if (!filter.test(localName)) {
              return NodeFilter.FILTER_ACCEPT;
            } else {
              return NodeFilter.FILTER_SKIP;
            }
          },
        });
        treeWalker.nextNode();

      ) {
        setLink(treeWalker.currentNode);
      }
    };
    let lockFn = new utils.LockFunction((mutations) => {
      for (const mutation of mutations) {
        if ("childList" === mutation.type) {
          const addedNodes = mutation.addedNodes;
          for (let nodeIndex = 0; nodeIndex < addedNodes.length; nodeIndex++) {
            const node = addedNodes[nodeIndex];
            observePageChanges(node);
          }
        }
      }
    });
    const initLinkProcessing = function () {
      linkifyText(document.body);
      const mutationObserver = utils.mutationObserver(document.body, {
        config: {
          subtree: true,
          childList: true,
        },
        callback: (mutations) => {
          lockFn.run(mutations);
        },
      });
      return mutationObserver;
    };
    const clearLinkHelper = function (linkElement) {
      const url = linkElement.getAttribute("href");
      if (
        typeof url === "string" &&
        0 !== url.indexOf("http") &&
        0 !== url.indexOf("ed2k://") &&
        0 !== url.indexOf("thunder://")
      ) {
        return linkElement.setAttribute("href", "http://" + url);
      }
    };
    const clearAllLinks = function () {
      const linkElements = Array.from(document.getElementsByClassName(HANDLER_CLASS_NAME));
      for (const $link of linkElements) {
        clearLinkHelper($link);
      }
    };
    document.addEventListener("mouseover", handleClearLink);
    setTimeout(clearAllLinks, 1500);
    setTimeout(initLinkProcessing, 100);
  };
  {
    CommonUtil.setGMResourceCSS(GM_RESOURCE_MAPPING.Viewer);
  }
  {
    CommonUtil.setGMResourceCSS(GM_RESOURCE_MAPPING.Hljs);
  }
  __pops__.GlobalConfig.setGlobalConfig({
    mask: {
      enable: true,
    },
    drag: true,
  });
  const MTRegExp = {
    formhash: /formhash=([0-9a-zA-Z]+)/,
    uid: /uid(=|-)(\d+)/,
    fontSpecial: /<font.*?>|<\/font>|<strike>|<strong>|<i>|<u>|align=".*?"|<br>[\s]*<br>[\s]*<br>/g,
  };
  const MTUtils = {
    getAvatar: (uid, size = "middle") => {
      return `/uc_server/avatar.php?uid=${uid}&size=${size}&ts=1`;
    },
    getCurrentUID() {
      let discuz_uid = _unsafeWindow.discuz_uid;
      if (typeof discuz_uid === "string") {
        return discuz_uid;
      }
      let $exit = $('.sidenv_exit a[href*="uid-"]') || $('#comiis_key a[href*="uid-"]');
      if ($exit) {
        let uidMatch = $exit.href.match(/uid=([0-9]+)/);
        if (uidMatch) {
          return uidMatch[uidMatch.length - 1];
        }
      }
    },
    async getFormHash() {
      let $inputFormHashList = Array.from((top || globalThis).document.querySelectorAll("input[name=formhash]"));
      for (let index = 0; index < $inputFormHashList.length; index++) {
        const $input = $inputFormHashList[index];
        let formHash = $input.value;
        if (formHash) {
          return formHash;
        }
      }
      let $anchorFormHashList = Array.from((top || globalThis).document.querySelectorAll('a[href*="formhash="]'));
      for (let index = 0; index < $anchorFormHashList.length; index++) {
        const $anchorFormHash = $anchorFormHashList[index];
        let anchorFormHashMatch = $anchorFormHash.href.match(MTRegExp.formhash);
        if (anchorFormHashMatch) {
          let formHash = anchorFormHashMatch[anchorFormHashMatch.length - 1];
          if (formHash) {
            return formHash;
          }
        }
      }
      let homeResponse = await httpx.get("/home.php?mod=spacecp", {
        fetch: true,
        allowInterceptConfig: false,
      });
      if (homeResponse.status) {
        let homeText = homeResponse.data.responseText;
        let homeDoc = domUtils.toElement(homeText, true, true);
        let $formhash = homeDoc.querySelector("input[name=formhash]");
        if ($formhash) {
          let formHash = $formhash.value;
          if (utils.isNotNull(formHash)) {
            return formHash;
          }
        }
      } else {
        log.error("请求个人主页获取formhash失败", homeResponse);
      }
    },
    envIsMobile() {
      return (_unsafeWindow.STYLEID || window.STYLEID || (typeof STYLEID !== "undefined" && STYLEID)) === "3";
    },
    getThreadId: (url) => {
      let urlMatch = url.match(/thread-([\d]+)-|&tid=([\d]+)/i);
      if (urlMatch) {
        let forumIdList = urlMatch.filter(Boolean);
        let forumId = forumIdList[forumIdList.length - 1];
        return forumId;
      }
    },
    getForumId(url) {
      let urlMatch = url.match(/&fid=([\d]+)/i);
      if (urlMatch) {
        return urlMatch[urlMatch.length - 1];
      }
    },
    getPostId(url) {
      let urlMatch = url.match(/&pid=([\d]+)/i);
      if (urlMatch) {
        return urlMatch[urlMatch.length - 1];
      }
    },
    getRepquote(url) {
      let urlMatch = url.match(/&repquote=([\d]+)/i);
      if (urlMatch) {
        return urlMatch[urlMatch.length - 1];
      }
    },
  };
  const MTAutoSignIn = {
    $key: {
      sign: "mt-sign-time",
    },
    init() {
      this.sign();
    },
    checkSignInfo() {
      let signInfo = this.getSignInfo();
      let findValue = signInfo.find((it) => {
        return it.hostName === window.location.hostname;
      });
      if (findValue) {
        if (utils.formatTime(Date.now(), "yyyyMMdd") !== utils.formatTime(findValue.time, "yyyyMMdd")) {
          return false;
        }
        return true;
      }
      return false;
    },
    setSignInfo() {
      let signInfo = {
        hostName: window.location.hostname,
        time: Date.now(),
      };
      let localSignInfo = this.getSignInfo();
      let findIndex = localSignInfo.findIndex((it) => {
        return it.hostName === signInfo.hostName;
      });
      if (findIndex !== -1) {
        localSignInfo.splice(findIndex, 1);
      }
      localSignInfo.push(signInfo);
      _GM_setValue(this.$key.sign, localSignInfo);
    },
    getSignInfo() {
      let localSignInfo = _GM_getValue(this.$key.sign, []);
      if (!Array.isArray(localSignInfo)) {
        this.clearSignInfo();
        return [];
      }
      return localSignInfo;
    },
    getHostNameSignInfo(hostName = window.location.hostname) {
      let localSignInfo = this.getSignInfo();
      return localSignInfo.find((it) => {
        return it.hostName === hostName;
      });
    },
    clearSignInfo(hostName) {
      if (typeof hostName === "string") {
        let signInfo = this.getSignInfo();
        let findIndex = signInfo.findIndex((it) => {
          return it.hostName === hostName;
        });
        if (findIndex !== -1) {
          signInfo.splice(findIndex, 1);
        }
        _GM_setValue(this.$key.sign, signInfo);
      } else {
        _GM_deleteValue(this.$key.sign);
      }
    },
    checkLogin() {
      if (MTUtils.envIsMobile()) {
        let mobile_login_exitBtn = $("a[href*='member.php?mod=logging&action=logout']");
        return Boolean(mobile_login_exitBtn);
      } else {
        let pc_login = $("#comiis_key");
        return Boolean(pc_login);
      }
    },
    async sign() {
      let formHash = await MTUtils.getFormHash();
      if (formHash == null) {
        if ($("#comiis_picshowbox")) {
          log.info("当前为评论区的看图模式 ");
          return;
        }
        log.error("自动签到:获取账号formhash失败");
        this.clearSignInfo(window.location.hostname);
        Qmsg.error({
          content: "自动签到:获取账号formhash失败",
        });
        return;
      }
      if (this.checkSignInfo()) {
        log.info("今日已签到");
        return;
      }
      let useFetch = Boolean(Panel.getValue("mt-auto-sign-useFetch"));
      let userAgent = utils.getRandomPCUA();
      let signSuccessCallBack = () => {
        this.setSignInfo();
      };
      let signFailedCallBack = () => {
        this.clearSignInfo(window.location.hostname);
      };
      let unknownSignContentCallback = (content) => {
        let $alert = pops.alert({
          title: {
            text: "未知签到内容",
            position: "center",
          },
          content: {
            text: "",
            html: false,
          },
          width: "88vw",
          height: "300px",
        });
        let $content = $alert.$shadowRoot.querySelector(".pops-alert-content");
        $content.innerText = content;
      };
      let sign_plugin = [
        {
          checkPluginEnableUrl: "/plugin.php?id=k_misign:sign",
          async sign() {
            let searchParamsData = {
              operation: "qiandao",
              format: "button",
              formhash: formHash,
              inajax: 1,
              ajaxtarget: "midaben_sign",
            };
            let response = await httpx.get(`/k_misign-sign.html?${utils.toSearchParamsStr(searchParamsData)}`, {
              fetch: useFetch,
              headers: {
                "User-Agent": userAgent,
              },
              allowInterceptConfig: false,
            });
            if (!response.status) {
              Qmsg.error("签到:网络异常,请求失败", {
                consoleLogContent: true,
              });
              return;
            }
            signSuccessCallBack();
            log.info("签到信息:", response);
            let responseText = response.data.responseText;
            let CDATA = utils.parseCDATA(responseText);
            let CDATAElement = domUtils.toElement(`<div>${CDATA}</div>`, true, false);
            let content = domUtils.text(CDATAElement);
            if (content.includes("需要先登录")) {
              Qmsg.error("签到:请先登录账号", {
                timeout: 3e3,
                consoleLogContent: true,
              });
              signFailedCallBack();
              return;
            } else if (
              content.includes("请稍后再试") ||
              content.includes("您已经被列入黑名单") ||
              content.includes("绑定手机号后才可以签到") ||
              content.includes("您所在用户组不允许使用")
            ) {
              Qmsg.error("签到:" + content, {
                timeout: 5e3,
              });
              return;
            } else if (content.includes("今日已签") || content.includes("今日已经签到")) {
              Qmsg.info("签到:" + content);
              return;
            } else if (responseText.includes("您当前的访问请求当中含有非法字符,已经被系统拒绝")) {
              Qmsg.error("签到: 您当前的访问请求当中含有非法字符,已经被系统拒绝", {
                timeout: 6e3,
              });
              return;
            } else if (useFetch && "location" in utils.toJSON(responseText)) {
              Qmsg.success("签到: 签到成功");
              return;
            }
            let signIn_con = CDATAElement.querySelector(".con");
            let signIn_line = CDATAElement.querySelector(".line");
            if (signIn_con && signIn_line) {
              let conMatch = domUtils.text(signIn_con).match(/([0-9]+)金币/);
              let lineMatch = domUtils.text(signIn_line).match(/([0-9]+)/);
              let con = conMatch[conMatch.length - 1];
              let line = lineMatch[lineMatch.length - 1];
              log.success(`金币${con},排名${line}`);
              Qmsg.info(
                `
							<div style="display: flex;${!MTUtils.envIsMobile() ? "padding: 20px;" : ""}">
								<div style="align-self: center;margin-right: 20px;">签到</div>
								<div>排名 ${line}<br>金币 ${con}</div>
							</div>`,
                {
                  timeout: 4e3,
                  isHTML: true,
                }
              );
              return;
            }
            unknownSignContentCallback(responseText);
          },
        },
        {
          checkPluginEnableUrl: "/plugin.php?id=dsu_paulsign:sign",
          async sign() {
            let searchParamsData = {
              id: "dsu_paulsign:sign",
              operation: "qiandao",
              infloat: 1,
              inajax: 1,
            };
            let response = await httpx.post(`/plugin.php?${utils.toSearchParamsStr(searchParamsData)}`, {
              data: {
                formhash: formHash,
                qdxq: "kx",
                qdmode: 3,
                todaysay: "",
                fastreply: 0,
              },
              processData: true,
              fetch: useFetch,
              headers: {
                "User-Agent": userAgent,
                "Content-Type": "application/x-www-form-urlencoded",
              },
              allowInterceptConfig: false,
            });
            if (!response.status) {
              Qmsg.error("签到:网络异常,请求失败", {
                consoleLogContent: true,
              });
              return;
            }
            signSuccessCallBack();
            log.info("签到信息:", response);
            let responseText = response.data.responseText;
            if (responseText.includes("签到成功")) {
              Qmsg.success("签到:签到成功");
              return;
            }
            if (responseText.includes("今日已经签到")) {
              Qmsg.info("签到:您今日已经签到,请明天再来!");
              return;
            }
            unknownSignContentCallback(responseText);
          },
        },
      ];
      for (let index = 0; index < sign_plugin.length; index++) {
        const signPluginItem = sign_plugin[index];
        let checkResponse = await httpx.get(signPluginItem.checkPluginEnableUrl, {
          fetch: useFetch,
          headers: {
            "User-Agent": utils.getRandomPCUA(),
          },
          allowInterceptConfig: false,
        });
        if (!checkResponse.status) {
          log.error("签到:检查签到插件是否启用的请求失败", checkResponse);
          continue;
        }
        let pluginDoc = domUtils.toElement(checkResponse.data.responseText, true, true);
        if (pluginDoc.querySelector("#messagetext") || checkResponse.data.responseText.includes("插件不存在或已关闭")) {
          log.error(`插件:${signPluginItem.checkPluginEnableUrl} 未启用或不存在`);
          continue;
        }
        await signPluginItem.sign();
        break;
      }
    },
  };
  const MTRouter = {
    isKMiSign() {
      return window.location.pathname.startsWith("/k_misign-sign.html");
    },
    isPost() {
      const searchParams = new URLSearchParams(window.location.search);
      return (
        window.location.pathname.startsWith("/thread-") ||
        (window.location.pathname.startsWith("/forum.php") && searchParams.has("mod", "viewthread"))
      );
    },
    isPage() {
      return Boolean(window.location.pathname.match(/^\/page-([0-9]+).html/g));
    },
    isGuide() {
      const searchParams = new URLSearchParams(window.location.search);
      return window.location.pathname.startsWith("/forum.php") && searchParams.has("mod", "guide");
    },
    isPlate() {
      return Boolean(window.location.pathname.match(/\/forum-[0-9]{1,2}-[0-9]{1,2}.html/g));
    },
    isSearch() {
      return window.location.pathname.startsWith("/search.php");
    },
    isSpace() {
      const searchParams = new URLSearchParams(window.location.search);
      return window.location.pathname.startsWith("/home.php") && searchParams.has("mod", "space");
    },
    isMySpace() {
      const searchParams = new URLSearchParams(window.location.search);
      return (
        window.location.pathname.startsWith("/home.php") &&
        searchParams.has("mod", "space") &&
        searchParams.has("do", "profile") &&
        searchParams.has("mycenter")
      );
    },
    isSpaceWithAt() {
      return window.location.pathname.startsWith("/space-uid-");
    },
    isForumList() {
      const searchParams = new URLSearchParams(window.location.search);
      return window.location.pathname.startsWith("/forum.php") && searchParams.has("forumlist");
    },
    isMessage() {
      const searchParams = new URLSearchParams(window.location.search);
      return (
        window.location.pathname.startsWith("/home.php") &&
        searchParams.has("mod", "space") &&
        searchParams.has("do", "notice")
      );
    },
    isMessageList() {
      const searchParams = new URLSearchParams(window.location.search);
      return (
        window.location.pathname.startsWith("/home.php") &&
        searchParams.has("mod", "space") &&
        searchParams.has("do", "pm")
      );
    },
    isPointsMall() {
      const searchParams = new URLSearchParams(window.location.search);
      return (
        window.location.pathname.startsWith("/keke_integralmall-keke_integralmall.html") ||
        (window.location.pathname.startsWith("/plugin.php") && searchParams.has("id", "keke_integralmal"))
      );
    },
    isPostPublish() {
      const searchParams = new URLSearchParams(window.location.search);
      return window.location.pathname.startsWith("/forum.php") && searchParams.has("mod", "post");
    },
    isPostPublish_voting() {
      const searchParams = new URLSearchParams(window.location.search);
      return (
        (window.location.pathname.startsWith("/forum.php") && searchParams.has("special", "1")) ||
        searchParams.has("fid", "42")
      );
    },
    isPostPublish_edit() {
      const searchParams = new URLSearchParams(window.location.search);
      return this.isPostPublish() && searchParams.has("action", "edit");
    },
    isPostPublish_newthread() {
      const searchParams = new URLSearchParams(window.location.search);
      return this.isPostPublish() && searchParams.has("action", "newthread");
    },
    isPostPublish_reply() {
      const searchParams = new URLSearchParams(window.location.search);
      return this.isPostPublish() && searchParams.has("action", "reply");
    },
  };
  const MTForumPostRightToolBar = {
    init() {
      domUtils.onReady(() => {
        Panel.execMenuOnce("mt-forum-post-quickCollentBtn", () => {
          this.quickCollentBtn();
        });
        Panel.execMenuOnce("mt-forum-post-quickReplyOptimization", () => {
          this.quickReplyOptimization();
        });
      });
    },
    quickCollentBtn() {
      log.info(`【快捷收藏】`);
      domUtils.waitNode("#scrolltop", 1e4).then(async ($scrollTop) => {
        if (!$scrollTop) {
          return;
        }
        let formhash = await MTUtils.getFormHash();
        let threadId = MTUtils.getThreadId(window.location.href);
        let collectUrl = `/home.php?${utils.toSearchParamsStr({
          mod: "spacecp",
          ac: "favorite",
          type: "thread",
          id: threadId,
          formhash,
          infloat: "yes",
          handlekey: "k_favorite",
          inajax: 1,
          ajaxtarget: "fwin_content_k_favorite",
        })}`;
        let $collect = domUtils.createElement("span", {
          innerHTML: `
        <a href="${collectUrl}" 
          id="k_favorite"
          onclick="showWindow(this.id, this.href, 'get', 0);"
          onmouseover="this.title = $('favoritenumber').innerHTML + ' 人收藏'">
          <img src="https://s1.ax1x.com/2020/04/29/JTk3lD.gif"
              height="26" 
              width="26" 
              style="position:absolute;top:10px;left:11px">
        </a>
        `,
        });
        domUtils.prepend($scrollTop, $collect);
      });
    },
    quickReplyOptimization() {
      domUtils.waitNode('#scrolltop a[title="快速回复"]', 1e4).then(($ele) => {
        if (!$ele) {
          return;
        }
        log.info(`快捷回复优化`);
        domUtils.on($ele, "click", function () {
          _unsafeWindow.showWindow("reply", $ele.href);
          log.info(`等待弹窗出现`);
          domUtils.waitNode("#moreconf", 1e4).then(($moreconf) => {
            if (!$moreconf) {
              return;
            }
            log.success(`弹出出现,添加按钮`);
            let $oneKeySpace = domUtils.createElement(
              "button",
              {
                innerText: "一键空格",
                type: "button",
                id: "insertspace2",
              },
              {
                style: "float: left;",
              }
            );
            domUtils.on($oneKeySpace, "click", (event) => {
              domUtils.preventEvent(event);
              domUtils.val($("#postmessage"), domUtils.val($("#postmessage")) + "           ");
            });
            domUtils.append($moreconf, $oneKeySpace);
          });
        });
      });
    },
  };
  const beautifyCss =
    ".pls .avatar img,.avtm img{border-radius:10%}.pls .avatar img{--avatar-size: 90px;width:var(--avatar-size);height:var(--avatar-size)}";
  importCSS(beautifyCss);
  const MTForumPost = {
    $flag: {
      isSetHljsCSS: false,
    },
    init() {
      MTForumPostRightToolBar.init();
      Panel.execMenuOnce("mt-forum-post-autoExpandContent", () => {
        return this.autoExpandContent();
      });
      Panel.execMenuOnce("mt-forum-post-repairImageWidth", () => {
        return this.repairImageWidth();
      });
      Panel.execMenuOnce("mt-forum-post-hideBottomInfoBlock", () => {
        return this.hideBottomInfoBlock();
      });
      domUtils.onReady(() => {
        Panel.execMenu("mt-forum-post-removeFontStyle", () => {
          this.removeFontStyle();
        });
        Panel.execMenu("mt-forum-post-removeCommentFontStyle", () => {
          this.removeCommentFontStyle();
        });
        Panel.execMenuOnce("mt-forum-post-loadNextPageComment", () => {
          return this.loadNextPageComment();
        });
        Panel.execMenuOnce("mt-forum-post-codeQuoteOptimization", () => {
          return this.codeQuoteOptimization();
        });
        Panel.execMenuOnce("mt-forum-post-optimizationImagePreview", () => {
          return this.optimizationImagePreview();
        });
        Panel.execMenuOnce("mt-forum-post-interceptionAttachment", () => {
          return this.setAttachmentsClickTip();
        });
        Panel.execMenu("mt-forum-post-detectingUserOnlineStatus", () => {
          this.detectingUserOnlineStatus();
        });
        Panel.execMenu("mt-forum-post-showUserLevel", () => {
          this.showUserLevel();
        });
      });
    },
    autoExpandContent() {
      log.info(`自动展开帖子内容`);
      return [
        addStyle(
          `
				div.comiis_message.bg_f.view_one.b_b.cl.message>div.comiis_messages.comiis_aimg_show.cl{
					max-height:inherit!important;
					overflow-y:inherit!important;
					position:inherit!important
				}
        	`
        ),
        CommonUtil.addBlockCSS(".comiis_lookfulltext_bg", ".comiis_lookfulltext_key"),
      ];
    },
    repairImageWidth() {
      log.info(`修复图片宽度`);
      return addStyle(
        `
        .comiis_messages img{
            max-width: 100% !important;
        }`
      );
    },
    removeFontStyle() {
      let $messageTable = $(".comiis_a.comiis_message_table");
      if (!$messageTable) {
        return;
      }
      log.info(`移除帖子字体效果`);
      domUtils.html($messageTable, domUtils.html($messageTable).replace(MTRegExp.fontSpecial, ""));
    },
    removeCommentFontStyle() {
      log.info(`移除评论区的字体效果`);
      let $fontList = $$("font");
      let $postForumMainContent = domUtils.html($(".comiis_postlist .comiis_postli")) || "";
      if ($postForumMainContent !== "") {
        $fontList.forEach(($font) => {
          if (!$postForumMainContent.includes($font.innerHTML)) {
            $font.removeAttribute("color");
            $font.removeAttribute("style");
            $font.removeAttribute("size");
          }
        });
        $$(".comiis_message.message").forEach(($message) => {
          if ($postForumMainContent.includes($message.innerHTML)) {
            domUtils.html($message, domUtils.html($message).replace(MTRegExp.fontSpecial, ""));
            let $next = domUtils.next($message);
            if ($next && $next.localName === "strike") {
              $next.outerHTML = $next.outerHTML.replace(/^<strike>(\n|)/g, "").replace(/<\/strike>$/g, "");
            }
          }
        });
      }
      $$(".comiis_postli.comiis_list_readimgs.nfqsqi").forEach((item) => {
        let $parent = item.parentElement;
        if ($parent && $parent.localName === "strike") {
          $parent.outerHTML = $parent.outerHTML.replace(/^<strike>(\n|)/g, "").replace(/<\/strike>$/g, "");
        }
      });
    },
    loadNextPageComment() {
      log.info(`自动加载下一页评论`);
      if (document.title.includes("提示信息 - MT论坛")) {
        return;
      }
      if ($$(".pgbtn").length == 0) {
        log.warn("没有找到下一页按钮");
        return;
      }
      const getPageInfo = async function (url) {
        let response = await httpx.get(url, {
          fetch: true,
          allowInterceptConfig: false,
        });
        if (!response.status) {
          Qmsg.error("网络异常,请求下一页失败");
          return;
        }
        const pageHTML = utils.parseFromString(response.data.responseText);
        const nextPageBtn = pageHTML.querySelector(".pgbtn a");
        pageHTML.querySelector("#postlistreply")?.remove();
        pageHTML.querySelector(".bm_h.comiis_snvbt")?.remove();
        return {
          url: nextPageBtn ? nextPageBtn.getAttribute("href") : null,
          postlist: pageHTML.querySelector("#postlist"),
          pgbtn: pageHTML.querySelector(".pgbtn"),
          pgs: pageHTML.querySelector(".pgs.mtm"),
        };
      };
      const scrollEvent = async function () {
        const nextURL = $(".pgbtn a").getAttribute("href");
        if (nextURL) {
          let pageInfo = await getPageInfo(nextURL);
          if (pageInfo) {
            if (pageInfo["postlist"]?.querySelector(".comiis_vrx")?.querySelector(".km1")) {
              Object.keys(pageInfo).forEach((it) => {
                pageInfo[it] = null;
              });
              log.warn(`检测到请求的本页内容中存在【楼主】标识,判断为重复页请求`);
            }
            if (!pageInfo["url"] || pageInfo["url"] == nextURL) {
              log.error("最后一页,取消监听");
              domUtils.off(document, ["scroll", "wheel"], lockFn.run);
              domUtils.remove(".pgbtn");
            }
            if (pageInfo["postlist"]) {
              domUtils.append("#postlist", domUtils.html(pageInfo["postlist"]));
            }
            if (pageInfo["pgbtn"]) {
              domUtils.html(".pgbtn", domUtils.html(pageInfo["pgbtn"]));
            }
            if (pageInfo["pgs"]) {
              domUtils.html(".pgs.mtm", domUtils.html(pageInfo["pgs"]));
            }
            MTForumPost.init();
          }
        } else {
          log.error("获取下一页元素失败");
        }
      };
      let lockFn = new utils.LockFunction(async () => {
        if (utils.isNearBottom()) {
          await scrollEvent();
        }
      });
      const listener = domUtils.on(document, ["scroll", "wheel"], lockFn.run);
      return [
        () => {
          listener.off();
        },
      ];
    },
    codeQuoteOptimization() {
      log.info(`代码块优化`);
      function hljs_smali(hljs2) {
        const smali_instr_low_prio = [
          "add",
          "and",
          "cmp",
          "cmpg",
          "cmpl",
          "const",
          "div",
          "double",
          "float",
          "goto",
          "if",
          "int",
          "long",
          "move",
          "mul",
          "neg",
          "new",
          "nop",
          "not",
          "or",
          "rem",
          "return",
          "shl",
          "shr",
          "sput",
          "sub",
          "throw",
          "ushr",
          "xor",
        ];
        const smali_instr_high_prio = [
          "aget",
          "aput",
          "array",
          "check",
          "execute",
          "fill",
          "filled",
          "goto/16",
          "goto/32",
          "iget",
          "instance",
          "invoke",
          "iput",
          "monitor",
          "packed",
          "sget",
          "sparse",
        ];
        const smali_keywords = [
          "transient",
          "constructor",
          "abstract",
          "final",
          "synthetic",
          "public",
          "private",
          "protected",
          "static",
          "bridge",
          "system",
          "interface",
          "enum",
          "annotation",
          "volatile",
          "native",
          "strictfp",
          "synchronized",
        ];
        const smali_types = [
          "void",
          "boolean",
          "byte",
          "short",
          "char",
          "int",
          "long",
          "float",
          "double",
          "boolean\\[",
          "byte\\[",
          "short\\[",
          "char\\[",
          "int\\[",
          "long\\[",
          "float\\[",
          "double\\[",
        ];
        return {
          aliases: ["smali"],
          keywords: {
            keyword: smali_keywords.join(" "),
            built_in: smali_instr_low_prio.concat(smali_instr_high_prio).join(" "),
            type: smali_types.join(" "),
          },
          contains: [
            {
              className: "string",
              begin: '"',
              end: '"',
              relevance: 0,
              contains: [
                hljs2.BACKSLASH_ESCAPE,
                {
                  className: "char.escape",
                  begin: /\\[nrtbf]/,
                  relevance: 0,
                },
              ],
            },
            {
              className: "string",
              begin: "'",
              end: "'",
              relevance: 0,
            },
            hljs2.COMMENT("#", "$", {
              relevance: 0,
            }),
            {
              className: "keyword",
              variants: [
                { begin: "\\s*\\.end\\s[a-zA-Z0-9]*" },
                { begin: "^[ ]*\\.[a-zA-Z]*", relevance: 0 },
                { begin: "\\s:[a-zA-Z_0-9]*", relevance: 0 },
                { begin: "\\s(" + smali_keywords.join("|") + ")" },
              ],
            },
            {
              className: "built_in",
              variants: [
                {
                  begin: "\\s(" + smali_instr_low_prio.join("|") + ")\\s",
                },
                {
                  begin: "\\s(" + smali_instr_low_prio.join("|") + ")((\\-|/)[a-zA-Z0-9]+)+\\s",
                  relevance: 10,
                },
                {
                  begin: "\\s(" + smali_instr_high_prio.join("|") + ")((\\-|/)[a-zA-Z0-9]+)*\\s",
                  relevance: 10,
                },
              ],
            },
            {
              className: "class",
              begin: "L[^(;:\n]*;",
              relevance: 0,
            },
            {
              className: "function",
              begin: "\\s*[a-zA-Z_<][a-zA-Z0-9_<>]*\\s*\\(",
              end: "\\s*\\)",
              excludeBegin: true,
              excludeEnd: true,
              relevance: 0,
              contains: [
                {
                  className: "params",
                  begin: "\\S",
                  endsWithParent: true,
                  relevance: 0,
                },
              ],
            },
            {
              className: "variable",
              begin: "[vp][0-9]+",
              relevance: 0,
            },
            {
              className: "number",
              variants: [
                { begin: "\\b-?0[xX][0-9a-fA-F]+[lL]?" },
                { begin: "\\b-?0[0-7]+[lL]?" },
                { begin: "\\b-?[0-9]+[lLfF]?" },
              ],
              relevance: 0,
            },
            {
              className: "property",
              begin: "\\s*[a-zA-Z_<][a-zA-Z0-9_<>]*\\s*->\\s*[a-zA-Z_<][a-zA-Z0-9_<>]*",
              relevance: 0,
            },
          ],
        };
      }
      hljs.registerLanguage("smali", hljs_smali);
      let lockFn = new utils.LockFunction(
        () => {
          function setElementHighlight($el, language = "java") {
            if (!$el.oldValue) {
              $el.oldValue = $el.textContent;
            }
            domUtils.html($el, hljs.highlight($el.oldValue, { language }).value.replace(/\\n$/gi, ""));
          }
          $$("em[onclick^=copycode]").forEach((coypCodeElement) => {
            if (
              coypCodeElement.nextElementSibling &&
              typeof coypCodeElement.nextElementSibling.className === "string" &&
              coypCodeElement.nextElementSibling.className == "code-select-language"
            ) {
              return;
            }
            const codeText = domUtils.text(coypCodeElement.parentElement.querySelector("div[id^=code]"));
            let codeLanguage = hljs.highlightAuto(codeText).language;
            if (codeText.trim().startsWith("invoke-")) {
              codeLanguage = "smali";
            }
            if (
              codeLanguage &&
              !["bash", "css", "javascript", "json", "java", "kotlin", "python", "smali", "typescript"].includes(
                codeLanguage
              )
            ) {
              codeLanguage = "plaintext";
            }
            const $select = domUtils.createElement("select", {
              className: "code-select-language",
            });
            let selectLanguageList = hljs.listLanguages().sort();
            selectLanguageList = selectLanguageList.concat("自动检测");
            let selectInnerHTML = "";
            selectLanguageList.forEach((languageName) => {
              if (languageName.startsWith("自动检测")) {
                selectInnerHTML += `<option data-value="${codeLanguage}" selected="selected">${languageName}(${codeLanguage})</option>`;
              } else {
                selectInnerHTML += `<option data-value="${languageName}">${languageName}</option>`;
              }
            });
            domUtils.html($select, selectInnerHTML);
            domUtils.on($select, "change", () => {
              let changeCodeLanguage = $select.selectedOptions[0].getAttribute("data-value");
              log.info("切换代码块语言: ", changeCodeLanguage);
              domUtils
                .parent($select)
                .querySelectorAll("li")
                .forEach((liElement) => {
                  setElementHighlight(liElement, changeCodeLanguage);
                });
            });
            domUtils.preventEvent($select, "click");
            domUtils.preventEvent(coypCodeElement, "click");
            coypCodeElement.insertAdjacentElement("afterend", $select);
            domUtils.emit($select, "change");
          });
          let blockcodeElementList = $$(".blockcode");
          blockcodeElementList.forEach((ele) => (ele.className = "hljs"));
        },
        this,
        500
      );
      const observer = utils.mutationObserver(document, {
        config: {
          subtree: true,
          childList: true,
        },
        callback: () => {
          lockFn.run();
        },
      });
      return [
        addStyle(
          `
			.hljs{text-align:left}
			.hljs ol{margin:0 0 0 10px;padding:10px 10px}
			.hljs li{padding-left:10px;list-style-type:decimal-leading-zero;font-family:Monaco,Consolas,'Lucida Console','Courier New',serif;font-size:12px;line-height:1.8em}
			.hljs li:hover{background:#2c313c}
			.hljs li::marker{unicode-bidi:isolate;font-variant-numeric:tabular-nums;text-transform:none;text-indent:0!important;text-align:start!important;text-align-last:start!important}
			.hljs em[onclick^=copycode]{color:#fff;background:#246fff;margin:5px 10px;border-radius:3px;padding:0 5px;cursor:pointer;height:32px;line-height:32px;display:inline-flex}
			.hljs .code-select-language{height:32px;line-height:32px;font-size:14px;border:1px solid #5c5c5c;border-radius:5px;text-align:center;outline:0}
		`
        ),
        () => {
          observer.disconnect();
        },
      ];
    },
    optimizationImagePreview() {
      log.info(`图片查看优化`);
      const blackListNoViewIMG = [
        {
          hostName: "avatar-bbs.mt2.cn",
          pathName: "*",
        },
        {
          hostName: "cdn-bbs.mt2.cn",
          pathName: "^(/static(/|//)image|/template)",
        },
        {
          hostName: window.location.hostname,
          pathName: "^(/static(/|//)image|/template)",
        },
        {
          hostName: window.location.hostname,
          pathName: "/uc_server/avatar.php",
        },
      ];
      function viewerViewImage(imgList = [], index = 0) {
        let viewerULNodeHTML = "";
        imgList.forEach((item) => {
          viewerULNodeHTML += `<li><img data-src="${item}"></li>`;
        });
        let viewerULNode = domUtils.createElement("ul", {
          innerHTML: viewerULNodeHTML,
        });
        let viewer = new Viewer(viewerULNode, {
          inline: false,
          url: "data-src",
          zIndex: utils.getMaxZIndex() + 100,
          hidden: () => {
            viewer.destroy();
          },
        });
        viewer.view(index);
        viewer.zoomTo(1);
        viewer.show();
      }
      function handleImageClick() {
        $$("#postlist .comiis_vrx:not([data-isHandlingViewIMG])").forEach((item) => {
          item.setAttribute("data-isHandlingViewIMG", "true");
          let totalImageList = [];
          item.querySelectorAll("img").forEach(($img) => {
            let currentImageUrl = $img.getAttribute("file") || $img.src;
            if (utils.isNull(currentImageUrl)) {
              return;
            }
            let imageUrlHostName = new URL(currentImageUrl).hostname;
            let imageUrlPathName = new URL(currentImageUrl).pathname;
            let $parent = $img.parentElement;
            if ($parent.nodeName.toLowerCase() === "a" && $parent.getAttribute("href") === currentImageUrl) {
              $parent.setAttribute("href", "javascript:;");
              $parent.removeAttribute("target");
            }
            let isInBlackList = false;
            for (let item2 of blackListNoViewIMG) {
              if (imageUrlHostName.indexOf(item2["hostName"]) != -1 && imageUrlPathName.match(item2["pathName"])) {
                isInBlackList = true;
                break;
              }
            }
            if (isInBlackList) {
              return;
            }
            totalImageList.push(currentImageUrl);
            $img.removeAttribute("onclick");
            $img.setAttribute("onclick", "");
            domUtils.on(
              $img,
              "click",
              function (event) {
                domUtils.preventEvent(event);
                log.info("点击图片", $img);
                let viewImageIndex = totalImageList.findIndex((imgUrl) => {
                  return imgUrl == currentImageUrl;
                });
                viewerViewImage(totalImageList, viewImageIndex);
              },
              { capture: true }
            );
          });
        });
      }
      let lockFn = new utils.LockFunction(() => {
        handleImageClick();
      });
      const observer = utils.mutationObserver(document, {
        config: {
          subtree: true,
          childList: true,
        },
        immediate: true,
        callback: () => {
          lockFn.run();
        },
      });
      return [
        () => {
          observer.disconnect();
        },
      ];
    },
    setAttachmentsClickTip() {
      log.info(`附件点击提醒`);
      function handleClick(item) {
        if (item.hasAttribute("href")) {
          let attachmentId = item.hasAttribute("id") ? item.id : item.parentElement.id;
          let attachmentURL = item.getAttribute("href");
          let attachmentName = item.innerText;
          let $attachmentMenu = $(`#${attachmentId}_menu`);
          if ($attachmentMenu.innerText.indexOf("金币") === -1) {
            return;
          }
          console.log("发现附件", item);
          console.log("该附件是金币附件,拦截!");
          item.setAttribute("data-href", attachmentURL);
          item.style.setProperty("cursor", "pointer");
          item.removeAttribute("href");
          item.innerText = "【已拦截】" + attachmentName;
          item.onclick = function () {
            __pops__.confirm({
              title: {
                text: "提示",
                position: "center",
              },
              content: {
                text: `<br />确定花费2金币下载附件 <a style="color: #507daf !important;">${attachmentName}</a> ?<br /><br />`,
                html: true,
              },
              btn: {
                ok: {
                  callback: (details) => {
                    window.open(attachmentURL, "_blank");
                    details.close();
                  },
                },
              },
              width: "400px",
              height: "200px",
            });
          };
        }
      }
      const observer = utils.mutationObserver(document.documentElement, {
        callback: () => {
          $$(".attnm a").forEach((item) => {
            handleClick(item);
          });
          $$(".comiis_attach a").forEach((item) => {
            handleClick(item);
          });
          $$("span[id*=attach_] a").forEach((item) => {
            handleClick(item);
          });
        },
        immediate: true,
        config: { childList: true, subtree: true },
      });
      return [
        () => {
          observer.disconnect();
        },
      ];
    },
    async detectingUserOnlineStatus() {
      log.info(`探测用户在线状态`);
      Panel.onceExec("mt-forum-post-detectingUserOnlineStatus", () => {
        addStyle(
          `
				.gm-user-status-icon{
					border: 0 !important;
					float: right !important;
					display: block !important;
					width: 40px !important;
					height: 40px !important;
				}
			`
        );
      });
      function getStatusIcon(isOffLine) {
        return domUtils.createElement("img", {
          className: "gm-user-status-icon",
          smilied: isOffLine ? "1353" : "1384",
          loading: "lazy",
          src: isOffLine
            ? "data:image/png;base64,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"
            : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAAXNSR0IArs4c6QAAE5dJREFUeF7tmwl0VdW5x393zs1NbnIzEzOThARBEQQcQeoDq6sOtGLB6qtYsKtQYlV8jlVRqnb5pA6VFsGKtSpaKtJS7cMBwVqUSVQkZICMZE5uppubO7+3z5Dc3NxMEOtbq91rnZXknH3O2f//9/++/e1vn2j4F2+af3H8/JuAfyvg62dA+/mLXJgUz2zgXL+PPI2GRK2OWA1Ei9cHoMvvoz0QoFmroww40NTKp2cv5WPA/3UO8WtxgX+sw5w5kau1Gq7RaLjCZJ0crYudgd46iYioVDCloNFbQWeRsfkcBLyd4Gqgt7sOb2cJvvaDuDqPdgUCvO0P8FbVcbZfcDvO8SZjXAn48lWS46NYRYAfR6YsSDClLiAifqY8Zr8dfB4IuORD6wG/T76m1YHfABqTfOgMoLVJl3pb9+Oq20lPw84WNGxo7ebZqdfTOF5EjAsBwuJZudyn1VAUlbM82pS2GL3eBZ42CHT0j1UAHamppAR8oNGBJgYMcXi9Jly1W+g+sbHLH+CZynJ+MR6KOF0CtNVvcqVey7NR2Temm7NuQk8b+OqhD4BOtrDaNPqhKQh4+68JIsQz1EOQoU/DSxzOys10V7xc4/WzKuO7/OV04sQpEyCsnpjKM/EZc5aZMxcREZUCnioZgGQ55VDBDwc8lBKViFAS/ApBxjR6HXacVX+ktXrPpuY6ik5VDadCgPbQJtKT43kzOufG6VHZS9D0FMs+rdWfPniVjOFIEERo9QQizqK74jW6Trx8qLGV705fRs1Y1TBWArRfvEp+QiQ7rXnL0yOTzkfjqZaB9x1GmYRTsfxISvC7QYAPOgKmHHqa9tJZtrGmpYcFZ11P6VhIGAsBMngLH0Xnr0yIsuWA1y4D10eEt/5YZD9UZBBKCOcK3t5+IoxRdNvr6Sp9rqXFwcVjIWG0BEiyT0ngo+hJK9OjYhJBDEAFrtXT0uhk1zufUHzwOPamVgmOLSmeaXOmseCauUREm0eK/wOu93Y52fnWbg7vOTzgeYUzJjLv8vNISDTIBIhxiECpM9HdZaer5LmahhYuHq07jIYA7T/WYcrM5u8x+cunW6Lj+16oyv6zT4/z+6fewux3YzbpMWgCEhhPQIPT5cUQa6PolyuJT00cFQmtdc08c9dzeNrtYZ/n1Br5z1uv5JxZOTIJPpFbeEGjx9HdTkfpxkNVFVx0we24RnKHURFQtoUNiXlLlsUkZoJfJDGmPp+vKa/l6Xu2YEVLlFXHxFkFRFgziYi00NvjoK22mrJ9R4gtyKHoVz8dFQHP3PZr2o+dIG/WFFLzC4kwR9Hr7Ka5oZGGI5/T1tBBJ35ufWwx6Tkpiiu45J9aPR2tDTSXvbYpbzE/Pl0CtMWvsjA5a85WW9oF4HUowPsJePHxbdR+XMaCVcuZsfAq9CYlvQ2CuvvFjezcuIVffPj0qAi475JbuapoGbMXLxnc3+/lwF//wjuPP0vahXks/a8rBxIg1GCMwX7yUxor91xbeD3bhiNhOAVo33iU+Jl5HEmcvDzJYtRIfibLvp+AhxetY/qll/Gde++QBxvoAr8nKPsTKW60fF7NE0aiwZDZf494VsCt5BdihrFKY9jx6JMcev9/eOD1osEE+D04vHqaj25s2l/GlOvuRQSlsIuqYQkofY1HE3KvvstmjQOtISwBWKeBPgVcNeBvkgcqpsDgGUCbIPdxHxkJunzdOAW8DeBvUUgNmQl0iRCRK/dpPxCWAPxu7N3dtJRv/2X+Eu4dKwGS9c/OpjZ/+lKjDGoIAmyXgK8dXBUDs7/xmAKDk6LgqVDI3DQRjInQ+t6QBIjbSw+/4v68grShVDCUArTC+kk5C+6KsSaC1igTICyri5Ct2+cOShIk/g5Of79uAoITInUW8IncwCe7oEiaAj46utpoOrFzSBWEI0B781VYfn4j5VmFi5LQCfBhCJAWJ0oCpGaBUgYo+iqLn/EgITglVkANyAbVPED0CyXAJzJHN5Ul25seeZnc3/0ZR6grhCVg3wtcm5lV+HpS8hRkArSgNff7tqQCAVaxfkgm2OtwU1pcQ2XZSdpbOmhr6qCzpQ27vQd3rwu3R84TXE4nAT9EWOQkyWjQYIwwYbNFYk2IIy4phtiEGLLyziAvLxGz1SLnIGoCpKpAnBPg1azR7wS/HwQBAR9NTcVUVRZ/f9aP2DoSAVpAV/wHtibnzLnKZk1WZG8AlJRXWDVkJhB/f/V5DZ99WMLBg6U01bfhD4BWA9bEVBJSs4iNSyQmJZOkxAQsMXKxI7Q5OuzSqabmFjoaqqivPk5H4wm6u3qk8ympcRSelcHMi/I559wM+XaJBCUHEAQIRSDUoBRc/G5cjnoqju/7c+ENXCvqT8EkhCpAkv9dS2jJL7zCKPm7UECftEPigEbHR7tKefOVT2ioa5NjpYY+8Nc9sgWr1YrNZiM5OZm4uDhMJtOIM0F3VxetbUIxdhobG/j9nQv7nimIFS0uzsI1S2Yz//JJ8okw/q8qAK+T0pKd7l++RkKoGwwiQBQwE5Iz9qSmndMf1ELjgEZPc3Mvv1m3i5KjtUMCGk8ChnpJWno8P737ctLPEGuDoACoyF92GQ91dUdoaayeE1poDSZAkv+e9dwzOTd3TXxSgSx/NaiJOp1wA62Bmno/j9+/jXa7iCn9Tavpf5zXH2Dx2vFRwObVC9ELaSnNH1BkoPwdadKx+oH5TJokXGug/OW6o5/WplKOlpc/OGcFjwW7wSACyrawPmHC5GWxMVny1CfkH+QGHd29PLT6bzS19Bdog4FrBI3iDb4A85YUMfG8b4d1AZfLhcetZHhAVLRUIZdasAvs+2AHuzf/Ap1OHqoImuGIiI7QsfbJb5OQGCEHSlUB0pTopb2rlpb6o2J9sGI4AkxfvsQHefmzzjOZE4RHB4EXRBh48bkveG9XCcGgxYAE8CAj4fNBjxeiE9MwR1lxdndKR09357AxIDLKKvUXh2hNFUeJFGlHUFlRjQOhZEyZmsQ991/QXz8QJIgM2O/F5WqnrHTfJ1N/yLfEBKQGwlAFmL54ifLJky5M1RktSrTvV0FLi4fbi97us4Jq7WDgOsUNfIEALk8At380C86hOTFqA5gMGoKf268A+TeVCOEaax+dS3aWOl3K1pcU6XZwtOTjurN+SO5QBAgnNx95mbozCy+xyL4vKrj9Ktj+x1q2bjssWVttKnh1gMFQBAmqtUL7DwU5uL8AJiw/1LPDEfGtS/JZunyi7AKK9eVA6OarYx85ptxIKkgbLNKKLdg8EgElr9Gcn3+pUfJ90aQ5X1bBk0+UcPjwiQFyDx6cNlgKwwr99C76g1gSJIsmTgnCcrLjWfPIDCUdVqrISmm9tOxD96QliKrMCATkXSIToGZ7QgVaHbet3o+9WU5WVOD/LNBDKkYhQyXCoNOycdO8gdZXCBiVAoQLFORdaNEZIuR3BpGwsmgvjq4eCXwocCVIn55px3C3b+BMiKoKQcTGDRdjEN4rgEtBwofP6+FY2ccju8AXL1Gcnz8r1WSI7E+EFFdYWfQpvd3OPvD/bNBD8aOSoZLw299e1E+AYn2X10Vp6T4RBAuHdYH9G3l3UsHUWdERsQM3Of7vrrvu/4qO5va+ceiDguEYjDfuXb0htZ7fbpyrFEqVrTWgq7edkmNf7pu5nPnDEvD+02w8uzD3unjbBJkA1Q1EEHzqJGXFldIpFbxYKH7TTSz8RBNEJKfaWPPgZLkeoMhf/Gi11/N5cfkbl97K8mEJ2LOen03MyliTKirAKnjl59Y/m/nwb7uk0wL4/ycXUEk464LZ3PIDhRE1BgB1zVUcr6wWqfBTQxEgbGl64R7mz5lh256bOaXfsIoSDlTMZvN//xqDIoxw8/M3oQZ1BvD4YNFNi5k783h/AJTkCuXHj7DnoP3qHz3Gu8NmgmYzcR89R+m0aedH6nxBW9kaHa1Rl7Fm6VrJ8ip4nTYkHH8DDPj8GgQJgoCHNq0mofeD/lHowRfwcvjw3p6LV5LvdIr9+6FTYWHbmHd/xSvnTp+8INYaLy2u+lr8NJ5/9iuOfboXMd+Kpvz4BmDLr/Qpavf4/JyRm8Mda6+ERvFpkWx50do7Wzlw6OjO+bfxA0B8sdFXFBm0GhTZ4Po7uH7++bbf5E5U3EAlQWfmWMflPH/fvRIBKvjRzAYGrQZPaF48DG2j6a9Gf0GCIOD624o4t6AMepv7wKOD8tIjvLvX/pMVT/Kq4v9hCZBim1iZms1Ef/gMxTNmnB+tUwubalaZtZRn736Gk6VlEgHDgU/xGpjlm0CaLxqT4il2rYsybQeHzC04gwgxazVMdyaQ54/B5perRi4N1Oq62Kerp0EftNkSRJwgQRBgSZ3AAxsegrINA8D7vF4OHtzbdUkRhU4nXWK1PWxJTARCwLLjCdacc2bGitS0TFkwogkSYgs50XoOG+5c3UeAsFZom+VMYHZEDnqbDW1QGczvcuG122mrr8fhFWORm0UfRdyECWH79zY3c9BbzT6zslGi3CMUpRJww333M7WgCewH5KtKoK6rreKzr6rXf+dOHgSpKjxgw3RQSUy51TxvJumP38JeSQV6xZkEEYKE/CK2rnuJQx/ukhQgEaAs2MXOcI7TwrfIQxcVNaTIfd3d1NdX4HR4MVv0TJiQPWL/DyijJEIukIqCg0pA1vTZLF+zGs3xx/qAS10U69/9POfv2i99PSIWQcMWRVU3ECqw7niCB/pUoEIRt0dm4U25iadXFdFRUykRYFB8wajVsaAhiQRjzDAergSnNjv1jlYmWOKJjQtfKQ5+SIu7gx1J9dIpj9cvEaCx2rhrwwtE9uyA7sMD3hlk/YcBUYkZtF0edl9AUUHUvJmkPnIzu8+aMjU+OiZ2IKDERTR1JrNh1S2SNYRGNHotc5rjSXEqC6kRKYCqjkYyY5JH0VPuUmZzSvFDCkk6HTc9/ivS0kFT/+KAZ3R1tPPFkS9bf/475u7aT53i+wOsL24YcmtMiQXW9XewUJoR8oMSI+nlZshcQU1pG5vvvk0iwWI0cEW5KKWNvnU6urFahnaV0Cd56OWtDHlJvuj+Ryg4bwqceAJ8Az8iDYr8Yns8rPVHIkCEETEjRO54nHU52WnXZWVlDxyPMQkyiqg5dpxX7vkZAa+fuZUxWLzDfAs4em7C9qwz9nAg282iex6iYPZMqNkALnl9orbKygpOVNS+8Z27ud3pRAQNEW0HWX84AsQ1KTUWAXreTJJ/fiNbJ+VmFEizQnAzZUH6j2mqOcn2tWvwVNYxrc4yahJcHjcmg7wBPVJz6L0cmqbl6vvWkF6QD/WvgGPglrvw+5Ly6mOPvMy1u/ZLn9QOivzB7xn2+wB1RhDJ0cK55Nx+HdtysjOSw5OwDK/Hy/ubNnLo7R1MqzYT7xg/JdTE9hJYdCFX/GQVkWKP8OTvwVk8gDMB/kRFdeO6N1i4bTcnlKg/KPKPlgBVBcIVzCI5WnY5hd+fz5bszIz4QSQId0i7UfoQouboUd7b/DTOz6pIbtUQ164hwidKjmNrvToPJ5N8OKeewaUrV5Ez7RwC7jY09a8Nkr0AX1FV3fr6uyze9A7FStIzLPiRXEAdreoKESIeCBK+O4/N+RMzzhhEggiM8ZdB7IXSvScOf8ahd/5K+Sd7sPZosXYFMLu1RHr0RDjU7KqflF6Ljh6DF6fRT2e0ButF05j97WvIm32e3Ml5EOq2Dwp4Anzp8eqTb+7iJgW88HuxSzo+X4kpQxTxQMxv0Qvncsaq7/G77Ky0gkGBUXQWcSH5MvkzFpE7uRyUH/qCqkOfSl+NtVbX4O7pxuWW01uT0YAxMor4jHTi0jJIPfNsJk6bTmSskkuIz2+a3h0keXGvCHgVlbXHnv0TN2/bzUlR/AkCL7oM+w8Xo921UOs+EglCCWYzMS/cycP52XHfS52QQqwtfrC+TbkE4i5GY8lX9hjG4AJ+LwFHKZr2T8ICb7e3UlffQGlF259+9AQPOJ10KBFftfyI4EfrAsGuIBlMJcHplFaO/1GQyYPZWWkp6Wnp9KXNwViFa0RMBEsuRCQT0Mah0YudJ2Wr3O8i4HWg8bdBbyP0VIKzZJDUxSNFeltTWyOs3nCsijUrnuQ9sxnnqYAfKwFqUFRJkDZSBCFxcUSt/xm3pti4ITMzLXJIIsYggNCuKvCqqtqeBjt/WPEUT7e1SfO78HN1o0P8PirLq88frQsEj0d1B2l2EF+2mM2YhBoWziXx+5dykyAiMTEuMiExmXhbbHhVjIIMAbrV3k5LcyPNzW0S8NffZ/O23TQrVheARfVTjfZjAn8qCgglQpAgJnsRHEU2IzRtjIvDuHYpc/LSWGjQc5HVGh1ps8UQaYnGbNRj1JvRm3R9xAigXpcPt9eJ0+2lx9GF3d5BZ2dXj8fL38tq2Xb/i+xpa5PAikMFrnwPEz7LGwXHp/2Pk8FqGESEGIAg45bLmVqYxbnWKLLNRnKNBpK1GuT9b6UFwO5y0+J0U97ZTUVxJQeef4cvFdCi11DAx2z14PeeiguEIzaUCBEfVNdQd/b78l1BSriHBIFVAWM243M6+ywu5k2xEFSTiNP+n8LxIkDFE44IcU0A1pnNcpnS6VTrNf00CKDqX05nH0j1E5JxB346QXA0rhW8X6QqQF0YjJQTq8U/tRQbnDKetsVDBz/eChjOPdRrI/3zYGiOPO6ggwf5v+5Gprm31vWZAAAAAElFTkSuQmCC",
        });
      }
      function setAvatarOnlineStatus($ele, isOffLine) {
        let $icon = getStatusIcon(isOffLine);
        domUtils.prepend($ele, $icon);
      }
      let $favatarList = Array.from($$(".pls.favatar:not([data-is-detectingUserOnlineStatus])"));
      for (let index = 0; index < $favatarList.length; index++) {
        const $favatar = $favatarList[index];
        let $kmfxx = $favatar.querySelector(".comiis_o.cl a.kmfxx");
        if (!$kmfxx) {
          log.error("探测用户在线状态失败,未找到发消息按钮");
          return;
        }
        $favatar.setAttribute("data-is-detectingUserOnlineStatus", "true");
        let sendMessageUrl = $kmfxx.href;
        let response = await httpx.get(sendMessageUrl, {
          fetch: true,
          allowInterceptConfig: false,
        });
        if (!response.status) {
          log.error("探测用户在线状态,中止网络请求探测");
          setAvatarOnlineStatus($favatar, true);
          return;
        }
        let doc = domUtils.toElement(response.data.responseText, true, true);
        let $flb = doc.querySelector(".flb");
        if ($flb) {
          let statusText = domUtils.text($flb)?.trim();
          let isOffLine = statusText.endsWith("……[离线]");
          setAvatarOnlineStatus($favatar, isOffLine);
        } else {
          setAvatarOnlineStatus($favatar, true);
        }
      }
    },
    showUserLevel() {
      log.info(`显示用户等级`);
      $$(".pls.favatar:not([data-show-user-level])").forEach(($userAvatar) => {
        $userAvatar.setAttribute("data-show-user-level", "true");
        let userLevel = "0级";
        let $userInfo = $userAvatar.querySelector(".tns tr");
        let $currentLevelText = $userAvatar.querySelector("p em").innerText;
        let $userLevelText = document.createElement("td");
        $userLevelText.setAttribute("style", "border-left: 1px solid #e3e3e3;");
        switch ($currentLevelText) {
          case "幼儿园":
          case "初级工程师":
            userLevel = "1级";
            break;
          case "小学生":
          case "中级工程师":
            userLevel = "2级";
            break;
          case "初中生":
          case "高级工程师":
            userLevel = "3级";
            break;
          case "高中生":
          case "专家":
            userLevel = "4级";
            break;
          case "大学生":
          case "高级专家":
            userLevel = "5级";
            break;
          case "硕士生":
          case "资深专家":
            userLevel = "6级";
            break;
          case "博士生":
          case "实习版主":
          case "版主":
          case "审核员":
          case "研究员":
            userLevel = "7级";
            break;
          case "博士后":
          case "超级版主":
          case "网站编辑":
          case "高级研究员":
          case "荣誉开发者":
            userLevel = "8级";
            break;
          case "管理员":
          case "信息监察员":
          case "资深研究员":
            userLevel = "9级";
            break;
        }
        domUtils.html($userLevelText, `<p><a class="dj">${userLevel}</a></p>Lv`);
        $userInfo.appendChild($userLevelText);
      });
    },
    hideBottomInfoBlock() {
      log.info(`隐藏底部信息块`);
      return addStyle(
        `
			.pls .favatar>*:not([id^="userinfo"]+div){
				display: none;
			}
			.pls .favatar>div[id^="userinfo"],
			.pls .favatar>div.tns{
				display: block;
			}
			.t_f{
				min-height: 100px !important;
			}
		`
      );
    },
  };
  const MTGuide = {
    init() {
      domUtils.onReady(() => {
        Panel.execMenuOnce("mt-guide-beautifyPage", () => {
          this.beautifyPage();
        });
      });
    },
    beautifyPage() {
      log.info(`页面美化`);
      addStyle(
        `
		.xst{font-size:15px}
		td.author_img{width:50px;padding:15px 0}
		td.author_img img{width:40px;height:40px;border-radius:50%}
		.list_author{margin-top:2px;color:#999;font-size:12px}
		.bankuai_tu_by a{color:#999!important}
		.bankuai_tu_by img{height:16px;margin:1px 1px 0 0;vertical-align:top}
		tbody a:hover{text-decoration:none;color:#3498db}
		.byg_th_align em+a{margin-right:5px}
	`
      );
      $$(".bm_c table tbody").forEach(($tbody) => {
        let $common = $tbody.querySelector("th.common");
        let commonHTML = domUtils.html($common);
        let forumUrl = $common.querySelectorAll("a")[0].getAttribute("href");
        let mid = null;
        let $uidAnchor = $tbody.querySelector("td.by>cite>a");
        let uid = $uidAnchor.getAttribute("href").match(/uid-(\d+)/)[1];
        let newHTML = `
			<td class="author_img">
				<a href="space-uid-${uid}.html" c="1" mid="${mid}">
					<img src="${MTUtils.getAvatar(uid, "middle")}">
				</a>
			</td>
			<th colspan="3" class="new byg_th">
				<div class="byg_th_align">
					<em>[${$tbody.querySelector("tr>td.by>a").outerHTML}]</em>
					${commonHTML}
				</div>
				<div class="list_author cl">
					<span class="z">作者:&nbsp;
						${$tbody.querySelectorAll("td.by>cite>a")[0].innerHTML}
						${$tbody.querySelectorAll("td.by>em>span")[0].innerHTML}
					</span>
					<span class="z pipe">&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;</span>
					<span class="z">最后发表:&nbsp;
						${$tbody.querySelectorAll("td.by>cite>a")[1].innerHTML}&nbsp;&nbsp;&nbsp;
						${$tbody.querySelectorAll("td.by>em>a")[0].innerHTML}
					</span>
					<span class="y bankuai_tu_by">
						<a href="${forumUrl}">
						<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAACOUlEQVRYR+1X0XETMRDdtfRP0gFUgG9O+iZUAKmApAJMBZgKMBUQKohTQcy3dHOmApIOzL/lZTbc3eh0ki/kfMkww37Zlkbv7e7bJxnhiQOfGB/+HQJlWR45594AwAkAvAWAo6B6GwBYAsBKCHGVZRl/743eCjDwbrd7T0SzCGgKYIOIi8lk8qWPyF4C1lrO9OtfAIeEuArnSimuTDSSBIqiOCMiBh8ciPghz/NF7KAogUOC16CIeJ7n+UVIokPAGHOCiNeD044cQESvtdYrf6lDwFq7BoCXIxFYa62zJIFKdJdjgHtnnvqibFXAWss9ejcygW9KqbNGGz6YtZbH5tnIBDZKqeMUAQrBieiT1noemYwfQgj2CXDO8Zw3uqkVb4yZI+LH8EylVFP55kNZllPnXLlvszFmhYiveI8/20VRzIjoM/9ORN+11mzXd2Gt7SQlhMiyLGOxty+j2OZ6dKq74Kfnikul1GkFwhXge4JjI4R4wRacGuloBVJsq0N5dqehJRPRnywQec0P1hKvNZXwF5ME/BKPKMQrpdSddjotGMOCw0RCS275QNXnmxFH8VYIMfWv6I4V+4oeoQ0tF+y0wBsdX9WH4tFywKgG6h+rVrDyD3UpRcGTFfAqMfhuqJ00Vca9T7IhbwN2RCnlrHa8xyJwyy9jIlqGD4+DEOCsAGAupbzZbrfP/UOllOu+F3CMxN4WeMb0CxFnsTfd0BHp08CcAaSUi4dkdx9yvX9M7nPIkD3/CfwGBboJMIftEqkAAAAASUVORK5CYII=" />${$tbody.querySelectorAll("td.num>a")[0].innerText}
						</a>&nbsp;
					</span>
					<span class="y bankuai_tu_by" style="margin-right: 20px">
						<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAACVElEQVRYR+1W3W3bQAwmTb83GzSdoDnr7rn2BukETSeoO0HtCdpO0GSCeoPYzzrhnA3sDZJ3yywYSIIk352sOIBRIHwTxCM/kh9/EM4seGb/8Abg/8mAc+4yz/NPAHANAFcAcNnizwYA1gCwIKKVUkq+O6UzA4XjHwBw02mtqXBLRPMuIFEAaZrOEFGcv1gQcZYkyTxkwAvAOXex2+3uEVFSfbIw83o4HE6UUo9tYwcAnHNXeZ7/9dS4/nYrtUbE5zozs/BBuPE+gnZDRAKiwY0GgCMif0LEaZIktz5HWZbdMPMvAHjn++/LRAOAtVZY/DEQxRMRjZVSohOUIoPLGAhjjCoNVACstYL8W5AsiF/bkadpOiYiHo1Gq/q7IhN/Ijh/a62n8v8ZgBhCxPvIg63Wuup7D0+kvp/r2bHWSq2DnGDmiTFmWQJYIqIMmZBUiEUhYHyjtf5QGujKKAAstdYTtNYKe4X1QUHE70mSSImi2SqjEr0sy6bM/DNmV/TPD6CI6jVK0OBJVwmYeWWMGR9LwkZ9CxIuaiTbEtF1HxISkRL9k9tQMihs7tOGzDw3xsyqNqwxNzaIHotReswgkpa+CBDwQWtd7ZiDUZznuUQTmoayTKZa6zuf8WIACfODzotpWi0l3zKSw0NARBcLMzeWESJKO7ePlDrOh7bzgxKU2rKUOjIRa2/fP6/zIIDSwmscJHXC+ZAde5IJY7/0DPuOiGYnnWR1h3Ib7vf7MTOXR2mbI3KkrBFxMRgMFr7r50UZ6Bl1b/XOEvS22PPBG4CzZ+AfrntRcuAjU2wAAAAASUVORK5CYII=" />${$tbody.querySelectorAll("td.num>em")[0].innerText}
					</span>
				</div>
			</th>
			`;
        domUtils.html($tbody, newHTML);
      });
    },
  };
  const UIButton = function (
    text,
    description,
    buttonText,
    buttonIcon,
    buttonIsRightIcon,
    buttonIconIsLoading,
    buttonType,
    clickCallBack,
    afterAddToUListCallBack,
    disable
  ) {
    const result = {
      text,
      type: "button",
      attributes: {},
      props: {},
      description,
      buttonIcon,
      buttonIsRightIcon,
      buttonIconIsLoading,
      buttonType,
      buttonText,
      callback(event) {
        if (typeof clickCallBack === "function") {
          clickCallBack(event);
        }
      },
      afterAddToUListCallBack,
    };
    Reflect.set(result.attributes, ATTRIBUTE_INIT, () => {
      result.disable = Boolean(disable);
    });
    return result;
  };
  const UIInput = function (
    text,
    key,
    defaultValue,
    description,
    changeCallback,
    placeholder = "",
    inputType = "text",
    afterAddToUListCallBack,
    valueChangeCallback
  ) {
    const result = {
      text,
      type: "input",
      inputType,
      attributes: {},
      props: {},
      description,
      placeholder,
      afterAddToUListCallBack,
      getValue() {
        const storageApiValue = this.props[PROPS_STORAGE_API];
        return storageApiValue.get(key, defaultValue);
      },
      callback(event, value) {
        const $input = event.target;
        $input.validity.valid;
        const storageApiValue = this.props[PROPS_STORAGE_API];
        storageApiValue.set(key, value);
      },
    };
    Reflect.set(result.attributes, ATTRIBUTE_KEY, key);
    Reflect.set(result.attributes, ATTRIBUTE_DEFAULT_VALUE, defaultValue);
    PanelComponents.initComponentsStorageApi("input", result, {
      get(key2, defaultValue2) {
        return Panel.getValue(key2, defaultValue2);
      },
      set(key2, value) {
        Panel.setValue(key2, value);
      },
    });
    return result;
  };
  const UIInputNumber = function (
    text,
    key,
    defaultValue,
    description,
    changeCallback,
    placeholder = "",
    afterAddToUListCallBack,
    valueChangeCallback
  ) {
    const result = {
      text,
      type: "input",
      inputType: "number",
      attributes: {},
      props: {},
      description,
      placeholder,
      afterAddToUListCallBack,
      getValue() {
        const storageApiValue = this.props[PROPS_STORAGE_API];
        return storageApiValue.get(key, defaultValue);
      },
      callback(event, value, valueAsNumber) {
        const storageApiValue = this.props[PROPS_STORAGE_API];
        storageApiValue.set(key, value);
      },
    };
    Reflect.set(result.attributes, ATTRIBUTE_KEY, key);
    Reflect.set(result.attributes, ATTRIBUTE_DEFAULT_VALUE, defaultValue);
    PanelComponents.initComponentsStorageApi("input", result, {
      get(key2, defaultValue2) {
        return Panel.getValue(key2, defaultValue2);
      },
      set(key2, value) {
        Panel.setValue(key2, value);
      },
    });
    return result;
  };
  const UIOwn = function (createLIElement, initConfig, searchConfig, attr, props, afterAddToUListCallBack) {
    const result = {
      type: "own",
      attributes: {},
      props: {},
      createLIElement,
      afterAddToUListCallBack,
    };
    {
      Reflect.set(result.attributes, ATTRIBUTE_INIT, () => false);
    }
    if (typeof searchConfig === "object" && searchConfig !== null) {
      Reflect.set(result.attributes, ATTRIBUTE_PLUGIN_SEARCH_CONFIG, searchConfig);
    }
    return result;
  };
  const UISelect = function (text, key, defaultValue, data, selectCallBack, description, valueChangeCallBack) {
    const result = {
      text,
      type: "select",
      description,
      attributes: {},
      props: {},
      getValue() {
        const storageApiValue = this.props[PROPS_STORAGE_API];
        return storageApiValue.get(key, defaultValue);
      },
      callback(isSelectedInfo) {
        if (isSelectedInfo == null) {
          return;
        }
        const value = isSelectedInfo.value;
        log.info(`选择:${isSelectedInfo.text}`);
        if (typeof selectCallBack === "function") {
          const result2 = selectCallBack(isSelectedInfo);
          if (result2) {
            return;
          }
        }
        const storageApiValue = this.props[PROPS_STORAGE_API];
        storageApiValue.set(key, value);
      },
      data,
    };
    Reflect.set(result.attributes, ATTRIBUTE_KEY, key);
    Reflect.set(result.attributes, ATTRIBUTE_DEFAULT_VALUE, defaultValue);
    PanelComponents.initComponentsStorageApi("select", result, {
      get(key2, defaultValue2) {
        return Panel.getValue(key2, defaultValue2);
      },
      set(key2, value) {
        Panel.setValue(key2, value);
      },
    });
    return result;
  };
  const UITextArea = function (
    text,
    key,
    defaultValue,
    description,
    changeCallback,
    placeholder = "",
    disabled,
    valueChangeCallBack
  ) {
    const result = {
      text,
      type: "textarea",
      attributes: {},
      props: {},
      description,
      placeholder,
      disabled,
      getValue() {
        const storageApiValue = this.props[PROPS_STORAGE_API];
        const value = storageApiValue.get(key, defaultValue);
        if (Array.isArray(value)) {
          return value.join("\n");
        }
        return value;
      },
      callback(event, value) {
        const storageApiValue = this.props[PROPS_STORAGE_API];
        storageApiValue.set(key, value);
      },
    };
    Reflect.set(result.attributes, ATTRIBUTE_KEY, key);
    Reflect.set(result.attributes, ATTRIBUTE_DEFAULT_VALUE, defaultValue);
    PanelComponents.initComponentsStorageApi("switch", result, {
      get(key2, defaultValue2) {
        return Panel.getValue(key2, defaultValue2);
      },
      set(key2, value) {
        Panel.setValue(key2, value);
      },
    });
    return result;
  };
  const PanelComponents = {
    $data: {
      __storeApiFn: null,
      get storeApiValue() {
        if (!this.__storeApiFn) {
          this.__storeApiFn = new Utils.Dictionary();
        }
        return this.__storeApiFn;
      },
    },
    getStorageApi(type) {
      if (!this.hasStorageApi(type)) {
        return;
      }
      return this.$data.storeApiValue.get(type);
    },
    hasStorageApi(type) {
      return this.$data.storeApiValue.has(type);
    },
    setStorageApi(type, storageApiValue) {
      this.$data.storeApiValue.set(type, storageApiValue);
    },
    initComponentsStorageApi(type, config, storageApiValue) {
      let propsStorageApi;
      if (this.hasStorageApi(type)) {
        propsStorageApi = this.getStorageApi(type);
      } else {
        propsStorageApi = storageApiValue;
      }
      this.setComponentsStorageApiProperty(config, propsStorageApi);
    },
    setComponentsStorageApiProperty(config, storageApiValue) {
      Reflect.set(config.props, PROPS_STORAGE_API, storageApiValue);
    },
  };
  const UISwitch = function (
    text,
    key,
    defaultValue,
    clickCallBack,
    description,
    afterAddToUListCallBack,
    disabled,
    valueChangeCallBack
  ) {
    const result = {
      text,
      type: "switch",
      description,
      disabled,
      attributes: {},
      props: {},
      getValue() {
        const storageApiValue = this.props[PROPS_STORAGE_API];
        const value = storageApiValue.get(key, defaultValue);
        return value;
      },
      callback(event, __value) {
        const value = Boolean(__value);
        log.success(`${value ? "开启" : "关闭"} ${text}`);
        const storageApiValue = this.props[PROPS_STORAGE_API];
        storageApiValue.set(key, value);
      },
      afterAddToUListCallBack,
    };
    Reflect.set(result.attributes, ATTRIBUTE_KEY, key);
    Reflect.set(result.attributes, ATTRIBUTE_DEFAULT_VALUE, defaultValue);
    PanelComponents.initComponentsStorageApi("switch", result, {
      get(key2, defaultValue2) {
        return Panel.getValue(key2, defaultValue2);
      },
      set(key2, value) {
        Panel.setValue(key2, value);
      },
    });
    return result;
  };
  class RuleEditView {
    option;
    constructor(option) {
      this.option = option;
    }
    async showView() {
      let $dialog = __pops__.confirm({
        title: {
          text: this.option.title,
          position: "center",
        },
        content: {
          text: `
                    <form class="rule-form-container" onsubmit="return false">
                        <ul class="rule-form-ulist"></ul>
                        <input type="submit" style="display: none;" />
                    </form>
                    `,
          html: true,
        },
        btn: utils.assign(
          {
            ok: {
              callback: async () => {
                await submitSaveOption();
              },
            },
          },
          this.option.btn || {},
          true
        ),
        drag: true,
        mask: {
          enable: true,
        },
        style: `
                ${__pops__.config.cssText.panelCSS}
                
                .rule-form-container {
                    
                }
                .rule-form-container li{
                    display: flex;
                    align-items: center;
                    justify-content: space-between;
                    padding: 5px 20px;
                    gap: 10px;
                }
				.rule-form-ulist-dynamic{
					--button-margin-top: 0px;
					--button-margin-right: 0px;
					--button-margin-bottom: 0px;
					--button-margin-left: 0px;
					display: flex;
					flex-direction: column;
					align-items: flex-start;
					padding: 5px 0px 5px 20px;
				}
				.rule-form-ulist-dynamic__inner{
					width: 100%;
				}
				.rule-form-ulist-dynamic__inner-container{
					display: flex;
					align-items: center;
				}
				.dynamic-forms{
					width: 100%;
				}
                .pops-panel-item-left-main-text{
                    max-width: 150px;
                }
                .pops-panel-item-right-text{
                    padding-left: 30px;
                }
                .pops-panel-item-right-text,
                .pops-panel-item-right-main-text{
                    text-overflow: ellipsis;
                    overflow: hidden;
                    white-space: nowrap;
                }
				.pops-panel-item-left-desc-text{
					line-height: normal;
					margin-top: 6px;
					font-size: 0.8em;
					color: rgb(108, 108, 108);
				}

                ${this.option?.style ?? ""}
            `,
        width:
          typeof this.option.width === "function" ? this.option.width() : window.innerWidth > 500 ? "500px" : "88vw",
        height:
          typeof this.option.height === "function" ? this.option.height() : window.innerHeight > 500 ? "500px" : "80vh",
      });
      let $form = $dialog.$shadowRoot.querySelector(".rule-form-container");
      $dialog.$shadowRoot.querySelector("input[type=submit]");
      let $ulist = $dialog.$shadowRoot.querySelector(".rule-form-ulist");
      let view = await this.option.getView(await this.option.data());
      $ulist.appendChild(view);
      const submitSaveOption = async () => {
        let result = await this.option.onsubmit($form, await this.option.data());
        if (!result.success) {
          return;
        }
        $dialog.close();
        await this.option.dialogCloseCallBack(true);
      };
    }
  }
  const MTCommentFilter = {
    $el: {
      isFilterElementHTML: [],
    },
    $key: {
      STORAGE_KEY: "mt-post-comment-filter-rule",
    },
    init() {
      this.registerMenu();
      if (MTRouter.isPost()) {
        let allData = this.getData();
        if (!allData.enable) {
          return;
        }
        let lockFn = new utils.LockFunction(() => {
          this.runFilter(allData);
        });
        utils.mutationObserver(document, {
          config: {
            subtree: true,
            childList: true,
          },
          callback: () => {
            lockFn.run();
          },
        });
      }
    },
    registerMenu() {
      MenuRegister.add({
        key: "comment-filter",
        text: "⚙ 评论过滤器",
        autoReload: false,
        isStoreValue: false,
        showText(text) {
          return text;
        },
        callback: () => {
          this.showView();
        },
      });
    },
    runFilter(filterData) {
      let isBlackListUser = function (postForumInfo) {
        for (const userName of filterData["userBlackList"]) {
          if (userName == postForumInfo.userName || userName == postForumInfo.userUID) {
            log.success("评论过滤器:黑名单用户", postForumInfo);
            return true;
          }
        }
        return false;
      };
      let isWhiteListUser = function (postForumInfo) {
        for (const userName of filterData["userWhiteList"]) {
          if (userName === postForumInfo.userName || userName === postForumInfo.userUID) {
            log.success("评论过滤器:白名单用户", postForumInfo);
            return true;
          }
        }
        return false;
      };
      $$(".comiis_vrx").forEach((item) => {
        if (item.querySelector(".plc .pti .authi .show")) {
          return;
        }
        let $name = item.querySelector(".pls .authi a");
        let postForumInfo = {
          userName: $name?.innerText || "",
          userUID: $name?.href?.match(MTRegExp.uid)?.[2]?.trim() || "",
          content: item.querySelector(".plc td.t_f")?.innerText?.trim() || "",
          isAuthor: false,
        };
        if (isWhiteListUser(postForumInfo)) {
          return;
        }
        if (filterData["replyFlag"] && item.querySelector(".quote")) {
          let comiis_quote_Element = item.querySelector(".quote");
          this.$el.isFilterElementHTML.push(comiis_quote_Element.outerHTML);
          comiis_quote_Element.remove();
        }
        if (postForumInfo.isAuthor && !filterData["avatarFlag"]) {
          return;
        }
        if (isBlackListUser(postForumInfo)) {
          this.$el.isFilterElementHTML.push(item.outerHTML);
          item.remove();
          return;
        }
        if (typeof filterData["minLength"] === "number" && filterData["minLength"] > postForumInfo.content.length) {
          return;
        }
        if (
          typeof filterData["keywordLength"] === "number" &&
          filterData["keywordLength"] < postForumInfo.content.length
        ) {
          return;
        }
        for (const keywordItem of filterData["keywords"]) {
          if (typeof keywordItem !== "string") {
            continue;
          }
          let keywordPattern = new RegExp(keywordItem);
          if (postForumInfo.content.match(keywordPattern)) {
            console.log("评论过滤器:", postForumInfo);
            this.$el.isFilterElementHTML.push(item.outerHTML);
            item.remove();
            return;
          }
        }
      });
    },
    showView() {
      const that = this;
      function generateStorageApi(data) {
        return {
          get(key, defaultValue) {
            let localData = that.getData();
            let value = Reflect.get(localData, key, defaultValue);
            if (key === "keywords" || key === "userWhiteList" || key === "userBlackList") {
              value = value.join("\n");
            }
            return value;
          },
          set(key, value) {
            if (key === "keywords" || key === "userWhiteList" || key === "userBlackList") {
              value = value.split("\n").filter((item) => item.trim() != "");
            }
            Reflect.set(data, key, value);
            that.setData(data);
          },
        };
      }
      let panelHandlerComponents = __pops__.config.PanelHandlerComponents();
      let view = new RuleEditView({
        title: "评论过滤器",
        data: () => {
          return this.getData();
        },
        getView: (data) => {
          let $fragment = document.createDocumentFragment();
          let enable_template = UISwitch("启用", "enable", true);
          Reflect.set(enable_template.props, PROPS_STORAGE_API, generateStorageApi(data));
          let $enable = panelHandlerComponents.createSectionContainerItem_switch(enable_template).$el;
          let replyFlag_template = UISwitch("处理回复引用", "replyFlag", false, void 0, "移除引用");
          Reflect.set(replyFlag_template.props, PROPS_STORAGE_API, generateStorageApi(data));
          let $replyFlag = panelHandlerComponents.createSectionContainerItem_switch(replyFlag_template).$el;
          let avatarFlag_template = UISwitch("处理作者评论", "avatarFlag", false);
          Reflect.set(avatarFlag_template.props, PROPS_STORAGE_API, generateStorageApi(data));
          let $avatarFlag = panelHandlerComponents.createSectionContainerItem_switch(avatarFlag_template).$el;
          let viewthreadFlag_template = UISwitch(
            '处理从"搜索页面"或"我的帖子提醒页面"进入的网站',
            "viewthreadFlag",
            false
          );
          Reflect.set(viewthreadFlag_template.props, PROPS_STORAGE_API, generateStorageApi(data));
          let $viewthreadFlag = panelHandlerComponents.createSectionContainerItem_switch(viewthreadFlag_template).$el;
          let minLength_template = UIInputNumber(
            "匹配的评论内容长度最小值",
            "minLength",
            5,
            "小于此长度的评论就算关键字匹配成功了也不会被排除"
          );
          Reflect.set(minLength_template.props, PROPS_STORAGE_API, generateStorageApi(data));
          let $minLength = panelHandlerComponents.createSectionContainerItem_input(minLength_template).$el;
          let keywordLength = UIInputNumber(
            "匹配的评论内容长度最大值",
            "keywordLength",
            8,
            "大于此长度的评论就算关键字匹配成功了也不会被排除"
          );
          Reflect.set(keywordLength.props, PROPS_STORAGE_API, generateStorageApi(data));
          let $keywordLength = panelHandlerComponents.createSectionContainerItem_input(keywordLength).$el;
          let keywords_template = UITextArea("评论关键字", "keywords", "", "多个评论关键字换行分割");
          Reflect.set(keywords_template.props, PROPS_STORAGE_API, generateStorageApi(data));
          let $keywords = panelHandlerComponents.createSectionContainerItem_textarea(keywords_template).$el;
          let userBlackList_template = UITextArea("黑名单用户", "userBlackList", "", "多个用户换行分割");
          Reflect.set(userBlackList_template.props, PROPS_STORAGE_API, generateStorageApi(data));
          let $userBlackList = panelHandlerComponents.createSectionContainerItem_textarea(userBlackList_template).$el;
          let userWhiteList_template = UITextArea("白名单用户", "userWhiteList", "", "多个用户换行分割");
          Reflect.set(userWhiteList_template.props, PROPS_STORAGE_API, generateStorageApi(data));
          let $userWhiteList = panelHandlerComponents.createSectionContainerItem_textarea(userWhiteList_template).$el;
          $fragment.append(
            $enable,
            $replyFlag,
            $avatarFlag,
            $viewthreadFlag,
            $minLength,
            $keywordLength,
            $keywords,
            $userBlackList,
            $userWhiteList
          );
          return $fragment;
        },
        btn: {
          merge: true,
          position: "space-between",
          ok: {
            enable: false,
          },
          cancel: {
            enable: true,
            text: "关闭",
          },
          other: {
            enable: true,
            text: `查看已过滤(${this.$el.isFilterElementHTML.length})`,
            type: "primary",
            callback: (details, event) => {
              __pops__.alert({
                title: {
                  text: "评论过滤器-已过滤",
                  position: "center",
                },
                content: {
                  text: `
                                ${Array.from($$('link[rel="stylesheet"]'))
                                  .map((item) => item.outerHTML)
                                  .join("\n")}

                                ${this.$el.isFilterElementHTML.join("\n")}
                                `,
                  html: true,
                },
                style: `
							.plhin{
								width: 100%;
							}
							td.plc .pi{
								height: auto;
							}
							`,
                width: "88vw",
                height: "80vh",
              });
            },
          },
        },
        dialogCloseCallBack(isSubmit) {},
        onsubmit: ($form, data) => {
          return {
            success: true,
            data,
          };
        },
        style: `
            .pops-panel-item-left-desc-text{
                line-height: normal;
                margin-top: 6px;
                font-size: 0.8em;
                color: rgb(108, 108, 108);
            }
            .pops-panel-item-left-main-text{
                max-width: unset;
            }
            .pops-panel-textarea textarea{
                height: 150px;
            }
            `,
      });
      view.showView();
    },
    getTemplateData() {
      return {
        enable: true,
        avatarFlag: false,
        replyFlag: false,
        viewthreadFlag: false,
        minLength: 5,
        keywordLength: 8,
        keywords: [],
        userBlackList: [],
        userWhiteList: [],
      };
    },
    getData() {
      return _GM_getValue(this.$key.STORAGE_KEY, this.getTemplateData());
    },
    setData(data) {
      _GM_setValue(this.$key.STORAGE_KEY, data);
    },
  };
  class RuleFilterView {
    option;
    $data = {
      isFilteredData: [],
    };
    constructor(option) {
      this.option = option;
    }
    showView() {
      let $alert = __pops__.alert({
        title: {
          text: this.option.title,
          position: "center",
        },
        content: {
          text: `
                <div class="filter-container"></div>
                `,
        },
        btn: {
          ok: {
            text: "关闭",
            type: "default",
          },
        },
        drag: true,
        mask: {
          enable: true,
        },
        width: window.innerWidth > 500 ? "350px" : "80vw",
        height: window.innerHeight > 500 ? "300px" : "70vh",
        style: `
            .filter-container{
                height: 100%;
                display: flex;
                flex-direction: column;
                gap: 20px;
            }
            .filter-container button{
                text-wrap: wrap;
                padding: 8px;
                height: auto;
                text-align: left;
            }
            `,
      });
      let $filterContainer = $alert.$shadowRoot.querySelector(".filter-container");
      let $fragment = document.createDocumentFragment();
      this.option.filterOption.forEach((filterOption) => {
        let $button = domUtils.createElement(
          "button",
          {
            innerText: filterOption.name,
          },
          {
            type: "button",
          }
        );
        let execFilterAndCloseDialog = async () => {
          this.$data.isFilteredData = [];
          let allRuleInfo = await this.option.getAllRuleInfo();
          allRuleInfo.forEach(async (ruleInfo) => {
            let filterResult = await filterOption.filterCallBack(ruleInfo.data);
            if (filterResult) {
              domUtils.show(ruleInfo.$el, false);
            } else {
              domUtils.hide(ruleInfo.$el, false);
              this.$data.isFilteredData.push(ruleInfo.data);
            }
          });
          if (typeof this.option.execFilterCallBack === "function") {
            await this.option.execFilterCallBack();
          }
          $alert.close();
        };
        domUtils.on($button, "click", async (event) => {
          domUtils.preventEvent(event);
          if (typeof filterOption.callback === "function") {
            let result = await filterOption.callback(event, execFilterAndCloseDialog);
            if (!result) {
              return;
            }
          }
          await execFilterAndCloseDialog();
        });
        $fragment.appendChild($button);
      });
      $filterContainer.appendChild($fragment);
    }
    getFilteredData() {
      return this.$data.isFilteredData;
    }
  }
  class RuleView {
    option;
    constructor(option) {
      this.option = option;
    }
    async showView(filterCallBack) {
      let $popsConfirm = __pops__.confirm({
        title: {
          text: this.option.title,
          position: "center",
        },
        content: {
          text: `
                    <div class="rule-view-container">
                    </div>
                    `,
          html: true,
        },
        btn: {
          merge: true,
          reverse: false,
          position: "space-between",
          ok: {
            enable: this.option?.bottomControls?.add?.enable || true,
            type: "primary",
            text: "添加",
            callback: async (event) => {
              this.showEditView(false, await this.option.getAddData(), $popsConfirm.$shadowRoot);
            },
          },
          close: {
            enable: true,
            callback(event) {
              $popsConfirm.close();
            },
          },
          cancel: {
            enable: this.option?.bottomControls?.filter?.enable || false,
            type: "default",
            text: "过滤",
            callback: async (details, event) => {
              if (typeof this.option?.bottomControls?.filter?.callback === "function") {
                let result = await this.option.bottomControls.filter.callback();
                if (typeof result === "boolean" && !result) {
                  return;
                }
              }
              let getAllRuleElement = () => {
                return Array.from($popsConfirm.$shadowRoot.querySelectorAll(".rule-view-container .rule-item"));
              };
              let $button = event.target.closest(".pops-confirm-btn").querySelector(".pops-confirm-btn-cancel span");
              if (domUtils.text($button).includes("取消")) {
                let cancelFilterResult = await this.option?.bottomControls?.filter?.cancelFilterCallback?.({
                  $button,
                  getAllRuleElement,
                });
                if (typeof cancelFilterResult === "boolean" && !cancelFilterResult) {
                  return;
                }
                getAllRuleElement().forEach(($el) => {
                  domUtils.show($el, false);
                });
                domUtils.text($button, "过滤");
              } else {
                let ruleFilterView = new RuleFilterView({
                  title: this.option.bottomControls?.filter?.title ?? "过滤规则",
                  filterOption: this.option.bottomControls?.filter?.option || [],
                  execFilterCallBack: async () => {
                    domUtils.text($button, "取消过滤");
                    await this.option.bottomControls?.filter?.execFilterCallBack?.();
                    const isFilteredData = ruleFilterView.getFilteredData();
                    if (isFilteredData.length) {
                      domUtils.text($button, `取消过滤(${isFilteredData.length})`);
                    }
                  },
                  getAllRuleInfo: () => {
                    return getAllRuleElement().map(($el) => {
                      return {
                        data: this.parseRuleItemElement($el).data,
                        $el,
                      };
                    });
                  },
                });
                ruleFilterView.showView();
              }
            },
          },
          other: {
            enable: this.option?.bottomControls?.clear?.enable || true,
            type: "xiaomi-primary",
            text: `清空所有(${(await this.option.data()).length})`,
            callback: (event) => {
              let $askDialog = __pops__.confirm({
                title: {
                  text: "提示",
                  position: "center",
                },
                content: {
                  text: "确定清空所有的数据?",
                  html: false,
                },
                btn: {
                  ok: {
                    enable: true,
                    callback: async (popsEvent) => {
                      log.success("清空所有");
                      if (typeof this.option?.bottomControls?.clear?.callback === "function") {
                        this.option.bottomControls.clear.callback();
                      }
                      let data = await this.option.data();
                      if (data.length) {
                        Qmsg.error("清理失败");
                        return;
                      } else {
                        Qmsg.success("清理成功");
                      }
                      await this.updateDeleteAllBtnText($popsConfirm.$shadowRoot);
                      this.clearContent($popsConfirm.$shadowRoot);
                      $askDialog.close();
                    },
                  },
                  cancel: {
                    text: "取消",
                    enable: true,
                  },
                },
                mask: { enable: true },
                width: "300px",
                height: "200px",
              });
            },
          },
        },
        mask: {
          enable: true,
        },
        width: window.innerWidth > 500 ? "500px" : "88vw",
        height: window.innerHeight > 500 ? "500px" : "80vh",
        style: `
            ${__pops__.config.cssText.panelCSS}
            
            .rule-item{
                display: flex;
                align-items: center;
                line-height: normal;
                font-size: 16px;
                padding: 4px 8px;
                gap: 8px;
            }
            .rule-name{
                flex: 1;
                white-space: nowrap;
                text-overflow: ellipsis;
                overflow: hidden;
            }
            .rule-controls{
                display: flex;
                align-items: center;
                text-overflow: ellipsis;
                overflow: hidden;
                white-space: nowrap;
                gap: 8px;
                padding: 0px;
            }
            .rule-controls-enable{
                
            }
            .rule-controls-edit{
                
            }
            .rule-controls-delete{
                
            }
            .rule-controls-edit,
            .rule-controls-delete{
                width: 16px;
                height: 16px;
                cursor: pointer;
            }
            `,
      });
      let allData = await this.option.data();
      let changeButtonText = false;
      let isFilteredDataLength = 0;
      for (let index = 0; index < allData.length; index++) {
        let item = allData[index];
        let $ruleItemList = await this.appendRuleItemElement($popsConfirm.$shadowRoot, item);
        let isNotFilterFlag = true;
        if (typeof filterCallBack === "function") {
          isNotFilterFlag = filterCallBack(item);
        } else if (typeof filterCallBack === "number" && !isNaN(filterCallBack)) {
          isNotFilterFlag =
            (await this.option.bottomControls?.filter?.option[filterCallBack]?.filterCallBack(item)) ?? isNotFilterFlag;
        }
        if (!isNotFilterFlag) {
          changeButtonText = true;
          domUtils.hide($ruleItemList, false);
          isFilteredDataLength++;
        }
      }
      if (changeButtonText) {
        let $button = $popsConfirm.$shadowRoot.querySelector(".pops-confirm-btn-cancel span");
        domUtils.text($button, `取消过滤${isFilteredDataLength ? `(${isFilteredDataLength})` : ""}`);
      }
    }
    showEditView(isEdit, editData, $parentShadowRoot, $editRuleItemElement, updateDataCallBack, submitCallBack) {
      let dialogCloseCallBack = async (isSubmit) => {
        if (isSubmit) {
          if (typeof submitCallBack === "function") {
            let newData = await this.option.getData(editData);
            submitCallBack(newData);
          }
        } else {
          if (!isEdit) {
            await this.option.deleteData(editData);
          }
          if (typeof updateDataCallBack === "function") {
            let newData = await this.option.getData(editData);
            updateDataCallBack(newData);
          }
        }
      };
      let editView = new RuleEditView({
        title: isEdit ? "编辑" : "添加",
        data: () => {
          return editData;
        },
        dialogCloseCallBack,
        getView: async (data) => {
          return await this.option.itemControls.edit.getView(data, isEdit);
        },
        btn: {
          ok: {
            enable: true,
            text: isEdit ? "修改" : "添加",
          },
          cancel: {
            callback: async (detail, event) => {
              detail.close();
              await dialogCloseCallBack(false);
            },
          },
          close: {
            callback: async (detail, event) => {
              detail.close();
              await dialogCloseCallBack(false);
            },
          },
        },
        onsubmit: async ($form, data) => {
          let result = await this.option.itemControls.edit.onsubmit($form, isEdit, data);
          if (result.success) {
            if (isEdit) {
              Qmsg.success("修改成功");
              $parentShadowRoot &&
                (await this.updateRuleItemElement(result.data, $editRuleItemElement, $parentShadowRoot));
            } else {
              $parentShadowRoot && (await this.appendRuleItemElement($parentShadowRoot, result.data));
            }
          } else {
            if (isEdit) {
              log.error("修改失败");
            }
          }
          return result;
        },
        style: this.option.itemControls.edit.style,
        width: this.option.itemControls.edit.width,
        height: this.option.itemControls.edit.height,
      });
      editView.showView();
    }
    parseViewElement($shadowRoot) {
      let $container = $shadowRoot.querySelector(".rule-view-container");
      let $deleteBtn = $shadowRoot.querySelector(".pops-confirm-btn button.pops-confirm-btn-other");
      return {
        $container,
        $deleteBtn,
      };
    }
    parseRuleItemElement($ruleElement) {
      let $enable = $ruleElement.querySelector(".rule-controls-enable");
      let $enableSwitch = $enable.querySelector(".pops-panel-switch");
      let $enableSwitchInput = $enable.querySelector(".pops-panel-switch__input");
      let $enableSwitchCore = $enable.querySelector(".pops-panel-switch__core");
      let $edit = $ruleElement.querySelector(".rule-controls-edit");
      let $delete = $ruleElement.querySelector(".rule-controls-delete");
      return {
        $enable,
        $enableSwitch,
        $enableSwitchInput,
        $enableSwitchCore,
        $edit,
        $delete,
        data: Reflect.get($ruleElement, "data-rule"),
      };
    }
    async createRuleItemElement(data, $shadowRoot) {
      let name = await this.option.getDataItemName(data);
      let $ruleItem = domUtils.createElement("div", {
        className: "rule-item",
        innerHTML: `
			<div class="rule-name">${name}</div>
			<div class="rule-controls">
				<div class="rule-controls-enable">
					<div class="pops-panel-switch">
						<input class="pops-panel-switch__input" type="checkbox">
						<span class="pops-panel-switch__core">
							<div class="pops-panel-switch__action">
							</div>
						</span>
					</div>
				</div>
				<div class="rule-controls-edit">
					${__pops__.config.iconSVG.edit}
				</div>
				<div class="rule-controls-delete">
					${__pops__.config.iconSVG.delete}
				</div>
			</div>
			`,
      });
      Reflect.set($ruleItem, "data-rule", data);
      let switchCheckedClassName = "pops-panel-switch-is-checked";
      const { $enable, $enableSwitch, $enableSwitchCore, $enableSwitchInput, $delete, $edit } =
        this.parseRuleItemElement($ruleItem);
      if (this.option.itemControls.enable.enable) {
        domUtils.on($enableSwitchCore, "click", async (event) => {
          let isChecked = false;
          if ($enableSwitch.classList.contains(switchCheckedClassName)) {
            $enableSwitch.classList.remove(switchCheckedClassName);
            isChecked = false;
          } else {
            $enableSwitch.classList.add(switchCheckedClassName);
            isChecked = true;
          }
          $enableSwitchInput.checked = isChecked;
          await this.option.itemControls.enable.callback(data, isChecked);
        });
        if (await this.option.itemControls.enable.getEnable(data)) {
          $enableSwitch.classList.add(switchCheckedClassName);
        }
      } else {
        $enable.remove();
      }
      if (this.option.itemControls.edit.enable) {
        domUtils.on($edit, "click", (event) => {
          domUtils.preventEvent(event);
          this.showEditView(true, data, $shadowRoot, $ruleItem, (newData) => {
            data = null;
            data = newData;
          });
        });
      } else {
        $edit.remove();
      }
      if (this.option.itemControls.delete.enable) {
        domUtils.on($delete, "click", (event) => {
          domUtils.preventEvent(event);
          let $askDialog = __pops__.confirm({
            title: {
              text: "提示",
              position: "center",
            },
            content: {
              text: "确定删除该条数据?",
              html: false,
            },
            btn: {
              ok: {
                enable: true,
                callback: async (popsEvent) => {
                  log.success("删除数据");
                  let flag = await this.option.itemControls.delete.deleteCallBack(data);
                  if (flag) {
                    Qmsg.success("成功删除该数据");
                    $ruleItem.remove();
                    await this.updateDeleteAllBtnText($shadowRoot);
                    $askDialog.close();
                  } else {
                    Qmsg.error("删除该数据失败");
                  }
                },
              },
              cancel: {
                text: "取消",
                enable: true,
              },
            },
            mask: {
              enable: true,
            },
            width: "300px",
            height: "200px",
          });
        });
      } else {
        $delete.remove();
      }
      return $ruleItem;
    }
    async appendRuleItemElement($shadowRoot, data) {
      let { $container } = this.parseViewElement($shadowRoot);
      let $ruleItem = [];
      let iteratorData = Array.isArray(data) ? data : [data];
      for (let index = 0; index < iteratorData.length; index++) {
        let item = iteratorData[index];
        let $item = await this.createRuleItemElement(item, $shadowRoot);
        $container.appendChild($item);
        $ruleItem.push($item);
      }
      await this.updateDeleteAllBtnText($shadowRoot);
      return $ruleItem;
    }
    async updateRuleContaienrElement($shadowRoot) {
      this.clearContent($shadowRoot);
      const { $container } = this.parseViewElement($shadowRoot);
      let data = await this.option.data();
      await this.appendRuleItemElement($shadowRoot, data);
      await this.updateDeleteAllBtnText($shadowRoot);
    }
    async updateRuleItemElement(data, $oldRuleItem, $shadowRoot) {
      let $newRuleItem = await this.createRuleItemElement(data, $shadowRoot);
      $oldRuleItem.after($newRuleItem);
      $oldRuleItem.remove();
    }
    clearContent($shadowRoot) {
      const { $container } = this.parseViewElement($shadowRoot);
      domUtils.html($container, "");
    }
    setDeleteBtnText($shadowRoot, text, isHTML = false) {
      const { $deleteBtn } = this.parseViewElement($shadowRoot);
      if (isHTML) {
        domUtils.html($deleteBtn, text);
      } else {
        domUtils.text($deleteBtn, text);
      }
    }
    async updateDeleteAllBtnText($shadowRoot) {
      let data = await this.option.data();
      this.setDeleteBtnText($shadowRoot, `清空所有(${data.length})`);
    }
  }
  const MTProductListingReminder = {
    $key: {
      STORAGE_KEY: "mt-productListingReminder-rule",
    },
    init() {
      this.registerMenu();
      this.runRule();
    },
    registerMenu() {
      MenuRegister.add({
        key: "product-reminder",
        text: "⚙ 商品上架提醒",
        autoReload: false,
        isStoreValue: false,
        showText(text) {
          return text;
        },
        callback: () => {
          this.showView();
        },
      });
    },
    async runRule() {
      async function getCurrentProduct() {
        let response = await httpx.get("/keke_integralmall-keke_integralmall.html", {
          allowInterceptConfig: false,
          headers: {
            "User-Agent": utils.getRandomAndroidUA(),
          },
        });
        if (!response.status) {
          Qmsg.error("【积分商城】获取数据失败");
          return;
        }
        let productInfoList = [];
        let doc = domUtils.toElement(response.data.responseText, true, true);
        doc.querySelectorAll(".task-list-wrapper li.col-xs-12").forEach(($taskList) => {
          productInfoList.push({
            name:
              domUtils.text($taskList.querySelector(".mall-info a > *:first-child")) ||
              domUtils.text($taskList.querySelector(".mall-info a")),
            price: domUtils.text($taskList.querySelector(".mall-info span.discount-price i")),
            endTime: domUtils.text($taskList.querySelector(".mall-info #time_hz span.time")),
            remainingQuantity: parseInt(
              $taskList.querySelector(".mall-info .mall-count .count-r")?.innerText?.replace(/仅剩|件/gi, "") || "0"
            ),
          });
        });
        return productInfoList;
      }
      if (MTRouter.isPointsMall()) {
        return;
      }
      let allData = this.getData();
      if (!allData.length) {
        return;
      }
      let productList = await getCurrentProduct();
      if (!productList) {
        return;
      }
      for (const productItem of productList) {
        for (const reminderOption of allData) {
          if (
            reminderOption.enable &&
            productItem["name"].match(new RegExp(reminderOption["productName"], "i")) &&
            !isNaN(productItem["remainingQuantity"]) &&
            productItem["remainingQuantity"] > 0
          ) {
            log.success(`成功匹配对应商品`, reminderOption, productItem);
            __pops__.confirm({
              title: {
                text: "积分商城提醒",
                position: "center",
              },
              content: {
                text: `<br />
                            您设置的商品已上架在积分商城中,当前售价 ${productItem["price"]}金币,仅剩${productItem["remainingQuantity"]}件,是否前往购买?
                            <a style="color: red !important;">(如需关闭提醒,请删除该关键字)</a>
                            <br />`,
                html: true,
              },
              btn: {
                merge: true,
                position: "space-between",
                other: {
                  enable: true,
                  type: "danger",
                  text: "删除提醒",
                  callback: () => {
                    let status = this.deleteData(reminderOption);
                    if (status) {
                      Qmsg.success("删除成功");
                    } else {
                      Qmsg.error("删除失败");
                    }
                  },
                },
                ok: {
                  text: "前往购买",
                  callback: () => {
                    window.location.href = `${window.location.origin}/keke_integralmall-keke_integralmall.html`;
                  },
                },
              },
              width: "300px",
              height: "300px",
            });
            return;
          }
        }
      }
    },
    getTemplateData() {
      return {
        uuid: utils.generateUUID(),
        enable: true,
        name: "",
        productName: "",
      };
    },
    showView() {
      let panelHandlerComponents = __pops__.config.PanelHandlerComponents();
      function generateStorageApi(data) {
        return {
          get(key, defaultValue) {
            return data[key] ?? defaultValue;
          },
          set(key, value) {
            data[key] = value;
          },
        };
      }
      let ruleView = new RuleView({
        title: "商品上架提醒",
        data: () => {
          return this.getData();
        },
        getAddData: () => {
          return this.getTemplateData();
        },
        getDataItemName: (data) => {
          return data["name"];
        },
        updateData: (data) => {
          return this.updateData(data);
        },
        deleteData: (data) => {
          return this.deleteData(data);
        },
        getData: (data) => {
          let allData = this.getData();
          let findValue = allData.find((item) => item.uuid === data.uuid);
          return findValue ?? data;
        },
        itemControls: {
          enable: {
            enable: true,
            getEnable(data) {
              return data.enable;
            },
            callback: (data, enable) => {
              data.enable = enable;
              this.updateData(data);
            },
          },
          edit: {
            enable: true,
            getView: (data, isEdit) => {
              let $fragment = document.createDocumentFragment();
              if (!isEdit) {
                data = this.getTemplateData();
              }
              let enable_template = UISwitch("启用", "enable", true);
              Reflect.set(enable_template.props, PROPS_STORAGE_API, generateStorageApi(data));
              let $enable = panelHandlerComponents.createSectionContainerItem_switch(enable_template).$el;
              let name_template = UIInput("规则名称", "name", "", "", void 0, "必填");
              Reflect.set(name_template.props, PROPS_STORAGE_API, generateStorageApi(data));
              let $name = panelHandlerComponents.createSectionContainerItem_input(name_template).$el;
              let productName_template = UIInput("商品名", "productName", "", "", void 0, "可正则,需手动转义");
              Reflect.set(productName_template.props, PROPS_STORAGE_API, generateStorageApi(data));
              let $productName = panelHandlerComponents.createSectionContainerItem_input(productName_template).$el;
              $fragment.append($enable, $name, $productName);
              return $fragment;
            },
            onsubmit: ($form, isEdit, editData) => {
              let $ulist_li = $form.querySelectorAll(".rule-form-ulist > li");
              let data = this.getTemplateData();
              if (isEdit) {
                data.uuid = editData.uuid;
              }
              $ulist_li.forEach(($li) => {
                let viewConfig = Reflect.get($li, panelHandlerComponents.$data.nodeStoreConfigKey);
                let attrs = Reflect.get(viewConfig, "attributes");
                let storageApi = Reflect.get($li, PROPS_STORAGE_API);
                let key = Reflect.get(attrs, ATTRIBUTE_KEY);
                let defaultValue = Reflect.get(attrs, ATTRIBUTE_DEFAULT_VALUE);
                let value = storageApi.get(key, defaultValue);
                if (Reflect.has(data, key)) {
                  Reflect.set(data, key, value);
                } else {
                  log.error(`${key}不在数据中`);
                }
              });
              if (data.name.trim() === "") {
                Qmsg.error("规则名称不能为空");
                return {
                  success: false,
                  data,
                };
              }
              if (isEdit) {
                return {
                  success: this.updateData(data),
                  data,
                };
              } else {
                return {
                  success: this.addData(data),
                  data,
                };
              }
            },
          },
          delete: {
            enable: true,
            deleteCallBack: (data) => {
              return this.deleteData(data);
            },
          },
        },
      });
      ruleView.showView();
    },
    getData() {
      return _GM_getValue(this.$key.STORAGE_KEY, []);
    },
    setData(data) {
      _GM_setValue(this.$key.STORAGE_KEY, data);
    },
    addData(data) {
      let localData = this.getData();
      let findIndex = localData.findIndex((item) => item.uuid == data.uuid);
      if (findIndex === -1) {
        localData.push(data);
        _GM_setValue(this.$key.STORAGE_KEY, localData);
        return true;
      } else {
        return false;
      }
    },
    updateData(data) {
      let localData = this.getData();
      let index = localData.findIndex((item) => item.uuid == data.uuid);
      let updateFlag = false;
      if (index !== -1) {
        updateFlag = true;
        localData[index] = data;
      }
      this.setData(localData);
      return updateFlag;
    },
    deleteData(data) {
      let localData = this.getData();
      let index = localData.findIndex((item) => item.uuid == data.uuid);
      let deleteFlag = false;
      if (index !== -1) {
        deleteFlag = true;
        localData.splice(index, 1);
      }
      this.setData(localData);
      return deleteFlag;
    },
    clearData() {
      _GM_deleteValue(this.$key.STORAGE_KEY);
    },
  };
  const blackHomeCSS =
    ".pops-confirm-content {\r\n  display: flex;\r\n  flex-direction: column;\r\n}\r\n.blackhome-user-filter input {\r\n  width: -moz-available;\r\n  width: -webkit-fill-available;\r\n  height: 30px;\r\n  margin: 8px 20px;\r\n  border: 0;\r\n  border-bottom: 1px solid;\r\n  text-overflow: ellipsis;\r\n  overflow: hidden;\r\n  white-space: nowrap;\r\n}\r\n.blackhome-user-filter input:focus-within {\r\n  outline: none;\r\n}\r\n.blackhome-user-list {\r\n  flex: 1;\r\n  overflow-y: auto;\r\n}\r\n.blackhome-user-list .blackhome-user-item {\r\n  margin: 15px 10px;\r\n  padding: 10px;\r\n  border-radius: 8px;\r\n  box-shadow:\r\n    0 0 0.6rem #c8d0e7,\r\n    -0.2rem -0.2rem 0.5rem #fff;\r\n}\r\n.blackhome-user {\r\n  display: flex;\r\n}\r\n.blackhome-user img {\r\n  width: 45px;\r\n  height: 45px;\r\n  border-radius: 45px;\r\n}\r\n.blackhome-user-info {\r\n  margin-left: 10px;\r\n}\r\n.blackhome-user-info p:nth-child(1) {\r\n  margin-bottom: 5px;\r\n}\r\n.blackhome-user-info p:nth-child(2) {\r\n  font-size: 14px;\r\n}\r\n.blackhome-user-action {\r\n  display: flex;\r\n  margin: 10px 0;\r\n}\r\n.blackhome-user-action p:nth-child(1),\r\n.blackhome-user-action p:nth-child(2) {\r\n  border: 1px solid red;\r\n  color: red;\r\n  border-radius: 4px;\r\n  padding: 2px 4px;\r\n  font-weight: 500;\r\n  font-size: 14px;\r\n  place-self: center;\r\n}\r\n.blackhome-user-action p:nth-child(2) {\r\n  border: 1px solid #ff4b4b;\r\n  color: #ff4b4b;\r\n  margin-left: 8px;\r\n}\r\n.blackhome-user-uuid {\r\n  border: 1px solid #ff7600;\r\n  color: #ff7600;\r\n  border-radius: 4px;\r\n  padding: 2px 4px;\r\n  font-weight: 500;\r\n  font-size: 14px;\r\n  width: fit-content;\r\n  width: -moz-fit-content;\r\n  margin: 10px 0;\r\n}\r\n.blackhome-operator {\r\n  padding: 10px;\r\n  background-color: #efefef;\r\n  border-radius: 6px;\r\n}\r\n.blackhome-operator-user {\r\n  display: flex;\r\n}\r\n.blackhome-operator-user img {\r\n  width: 35px;\r\n  height: 35px;\r\n  border-radius: 35px;\r\n}\r\n.blackhome-operator-user p {\r\n  align-self: center;\r\n  margin-left: 10px;\r\n}\r\n.blackhome-operator-user-info {\r\n  margin: 10px 0;\r\n  font-weight: 500;\r\n}\r\n\r\n@media screen and (min-width: 800px) {\r\n  .blackhome-user-list {\r\n    display: flex;\r\n    flex-wrap: wrap;\r\n  }\r\n  .blackhome-user-list .blackhome-user-item {\r\n    flex: 1 1 250px;\r\n    max-width: calc(50% - 10px - 10px);\r\n  }\r\n}\r\n";
  const MTBlackHome = {
    $data: {
      cid: "",
    },
    init() {
      this.registerMenu();
    },
    registerMenu() {
      MenuRegister.add({
        key: "black-home",
        text: "⚙ 小黑屋",
        autoReload: false,
        isStoreValue: false,
        showText(text) {
          return text;
        },
        callback: () => {
          this.showBlackHome();
        },
      });
    },
    async showBlackHome() {
      let $loading = Qmsg.loading("正在获取小黑屋名单中...");
      let blackListInfo = await this.getBlackListInfo("");
      $loading.close();
      if (!blackListInfo) {
        return;
      }
      if (blackListInfo.data.length === 0) {
        Qmsg.error("获取小黑屋名单为空");
        return;
      }
      this.$data.cid = blackListInfo.next_cid;
      let $confirm = __pops__.confirm({
        title: {
          text: "小黑屋名单",
          position: "center",
        },
        content: {
          text: `
                <div class="blackhome-user-filter">
                    <input placeholder="过滤用户名/操作人员/UID(可正则)">
                </div>
                <div class="blackhome-user-list"></div>
                `,
          html: true,
        },
        btn: {
          ok: {
            text: "下一页",
            callback: async () => {
              let $loading2 = Qmsg.loading("正在获取小黑屋名单中...");
              log.info("下一页的cid: ", this.$data.cid);
              let nextBlackListInfo2 = await this.getBlackListInfo(this.$data.cid);
              $loading2.close();
              if (!nextBlackListInfo2) {
                return;
              }
              this.$data.cid = nextBlackListInfo2.next_cid;
              nextBlackListInfo2.data.forEach((item) => {
                let $item = this.createListViewItem(item);
                $list.appendChild($item);
              });
              if (nextBlackListInfo2.data.length === 0) {
                Qmsg.error("获取小黑屋名单为空");
              } else {
                Qmsg.success(`成功获取 ${nextBlackListInfo2.data.length}条数据`);
              }
              domUtils.emit($filterInput, "input");
            },
          },
          cancel: {
            text: "关闭",
          },
        },
        width: PanelUISize.settingBig.width,
        height: PanelUISize.settingBig.height,
        style: blackHomeCSS,
      });
      let $list = $confirm.$shadowRoot.querySelector(".blackhome-user-list");
      let $filterInput = $confirm.$shadowRoot.querySelector(".blackhome-user-filter input");
      blackListInfo.data.forEach((item) => {
        let $item = this.createListViewItem(item);
        $list.appendChild($item);
      });
      Qmsg.success(`成功获取 ${blackListInfo.data.length}条数据`);
      let isSeaching = false;
      domUtils.on(
        $filterInput,
        ["input", "propertychange"],
        utils.debounce(() => {
          let inputText = $filterInput.value.trim();
          if (isSeaching) {
            return;
          }
          isSeaching = true;
          if (inputText == "") {
            $confirm.$shadowRoot.querySelectorAll(".blackhome-user-item").forEach((item) => {
              item.removeAttribute("style");
            });
            isSeaching = false;
            return;
          }
          $confirm.$shadowRoot.querySelectorAll(".blackhome-user-item").forEach((item) => {
            if (
              item.getAttribute("data-name").match(new RegExp(inputText, "ig")) ||
              item.getAttribute("data-uid").trim().match(new RegExp(inputText, "ig")) ||
              item.getAttribute("data-operator").match(new RegExp(inputText, "ig"))
            ) {
              item.removeAttribute("style");
            } else {
              item.setAttribute("style", "display:none;");
            }
          });
          isSeaching = false;
        })
      );
      let nextBlackListInfo = await this.getBlackListInfo(this.$data.cid);
      if (!nextBlackListInfo) {
        return;
      }
      this.$data.cid = nextBlackListInfo.next_cid;
    },
    async getBlackListInfo(cid = "") {
      let searchParamsData = {
        mod: "misc",
        action: "showdarkroom",
        cid,
        ajaxdata: "json",
      };
      let response = await httpx.get(`/forum.php?${utils.toSearchParamsStr(searchParamsData)}`, {
        headers: {
          "User-Agent": utils.getRandomPCUA(),
        },
        responseType: "json",
      });
      if (!response.status) {
        return;
      }
      let data = utils.toJSON(response.data.responseText);
      let cidSplit = data["message"].split("|");
      let next_cid = cidSplit[cidSplit.length - 1];
      let blackListData = utils.parseObjectToArray(data["data"]);
      let new_blackListData = [];
      let new_blackListData_noTime = [];
      blackListData.forEach((item) => {
        let date = item["dateline"].match(/([0-9]{4}-[0-9]{1,2}-[0-9]{1,2}[\s]*[0-9]{1,2}:[0-9]{1,2})/g);
        if (date == null) {
          let _time_ = parseInt((Date.now() / 1e3).toString());
          let _time_after_count_ = 0;
          let sec_data = item["dateline"].match(/([0-9]+|半)[\s\S]*秒前/);
          let min_data = item["dateline"].match(/([0-9]+|半)[\s\S]*分钟前/);
          let hour_data = item["dateline"].match(/([0-9]+|半)[\s\S]*小时前/);
          let yesterday_time_data = item["dateline"].match(/昨天[\s\S]*(\d{2}):(\d{2})/);
          let before_yesterday_time_data = item["dateline"].match(/前天[\s\S]*(\d{2}):(\d{2})/);
          let day_data = item["dateline"].match(/([0-9]+|半)[\s\S]*天前/);
          if (sec_data) {
            sec_data = sec_data[sec_data.length - 1];
            sec_data = sec_data.replace(/半/g, 0.5);
            sec_data = parseFloat(sec_data);
            _time_after_count_ = _time_ - sec_data;
          } else if (min_data) {
            min_data = min_data[min_data.length - 1];
            min_data = min_data.replace(/半/g, 0.5);
            min_data = parseFloat(min_data);
            _time_after_count_ = _time_ - min_data * 60;
          } else if (hour_data) {
            hour_data = hour_data[hour_data.length - 1];
            hour_data = hour_data.replace(/半/g, 0.5);
            hour_data = parseFloat(hour_data);
            _time_after_count_ = _time_ - hour_data * 60 * 60;
          } else if (yesterday_time_data) {
            let yesterday_hour_data = yesterday_time_data[1];
            let yesterday_min_data = yesterday_time_data[2];
            _time_after_count_ =
              _time_ - 86400 - parseInt(yesterday_hour_data) * 3600 - parseInt(yesterday_min_data) * 60;
          } else if (before_yesterday_time_data) {
            let before_yesterday_hour_data = before_yesterday_time_data[1];
            let before_yesterday_min_data = before_yesterday_time_data[2];
            _time_after_count_ =
              _time_ -
              86400 * 2 -
              parseInt(before_yesterday_hour_data) * 3600 -
              parseInt(before_yesterday_min_data) * 60;
          } else if (day_data) {
            day_data = day_data[day_data.length - 1];
            day_data = day_data.replace(/半/g, 0.5);
            day_data = parseFloat(day_data);
            _time_after_count_ = _time_ - day_data * 60 * 60 * 24;
          }
          item["time"] = parseInt(_time_after_count_.toString()) * 1e3;
          new_blackListData = new_blackListData.concat(item);
          return;
        } else {
          date = date[0];
        }
        item["time"] = utils.formatToTimeStamp(date);
        new_blackListData = new_blackListData.concat(item);
      });
      utils.sortListByProperty(new_blackListData, "time");
      utils.sortListByProperty(new_blackListData_noTime, "time", false);
      new_blackListData = new_blackListData.concat(new_blackListData_noTime);
      return {
        next_cid,
        data: new_blackListData,
      };
    },
    createListViewItem(userInfo) {
      let $item = domUtils.createElement(
        "div",
        {
          className: "blackhome-user-item",
          innerHTML: `
                <div class="blackhome-user-avatar">
                    <div class="blackhome-user">
                    <img src="${MTUtils.getAvatar(userInfo["uid"], "big")}" loading="lazy">
                    <div class="blackhome-user-info">
                        <p>${userInfo["username"]}</p>
                        <p>${userInfo["dateline"]}</p>
                    </div>
                    </div>
                    <div class="blackhome-user-action">
                    <p>${userInfo["action"]}</p>
                    <p>到期: ${userInfo["groupexpiry"]}</p>
                    </div>
                    <div class="blackhome-user-uuid">UID: ${userInfo["uid"]}</div>
                    <div class="blackhome-operator">
                    <div class="blackhome-operator-user">
                        <img loading="lazy" src="${MTUtils.getAvatar(userInfo["operatorid"], "big")}">
                        <p>${userInfo["operator"]}</p>
                    </div>
                    <div class="blackhome-operator-user-info">
                    ${userInfo["reason"]}
                    </div>
                    </div>
                </div>
                `,
        },
        {
          "data-name": userInfo.username,
          "data-uid": userInfo.uid,
          "data-operator": userInfo.operator,
          "data-operator-uid": userInfo.operatorid,
        }
      );
      domUtils.on($item, "click", ".blackhome-user img", function () {
        window.open(`home.php?mod=space&uid=${userInfo.uid}&do=profile`, "_blank");
      });
      domUtils.on($item, "click", ".blackhome-operator-user img", function () {
        window.open(`home.php?mod=space&uid=${userInfo.operatorid}&do=profile`, "_blank");
      });
      return $item;
    },
  };
  const onlineUserCSS =
    '.pops-alert-content {\r\n  display: flex;\r\n  flex-direction: column;\r\n}\r\n.pops-alert-content > .online-user-info {\r\n  text-align: center;\r\n  padding: 0px 6px;\r\n}\r\n.online-user-filter input {\r\n  width: -webkit-fill-available;\r\n  width: -moz-available;\r\n  height: 30px;\r\n  margin: 8px 20px;\r\n  border: 0;\r\n  border-bottom: 1px solid;\r\n}\r\n.online-user-filter input:focus-within {\r\n  outline: none;\r\n}\r\n.online-user-list {\r\n  flex: 1;\r\n  overflow-y: auto;\r\n}\r\n.online-user-list li {\r\n  margin: 18px 0;\r\n}\r\n.online-user {\r\n  display: flex;\r\n  margin: 2px 20px;\r\n  align-items: center;\r\n}\r\n.online-user img[data-avatar] {\r\n  width: 45px;\r\n  height: 45px;\r\n  border-radius: 45px;\r\n}\r\n.online-user-list .online-user-info {\r\n  margin: 2px 14px;\r\n}\r\n.online-user-list .online-user-info p[data-name] {\r\n  margin-bottom: 4px;\r\n}\r\n.online-user-list .online-user-info span[data-sf] {\r\n  border-radius: 4px;\r\n  padding: 2px 4px;\r\n  font-weight: 500;\r\n  font-size: 14px;\r\n}\r\n.online-user-list .online-user-info span[data-uid] {\r\n  border: 1px solid #ff7600;\r\n  color: #ff7600;\r\n  border-radius: 4px;\r\n  padding: 2px 4px;\r\n  font-weight: 500;\r\n  font-size: 14px;\r\n  width: fit-content;\r\n  width: -moz-fit-content;\r\n  margin: 10px 0;\r\n}\r\n.online-user-list .online-user-info span[data-sf="会员"] {\r\n  color: #88b500;\r\n  border: 1px solid #88b500;\r\n}\r\n.online-user-list .online-user-info span[data-sf="版主"] {\r\n  color: #2db5e3;\r\n  border: 1px solid #2db5e3;\r\n}\r\n.online-user-list .online-user-info span[data-sf="超级版主"] {\r\n  color: #e89e38;\r\n  border: 1px solid #e89e38;\r\n}\r\n.online-user-list .online-user-info span[data-sf="管理员"] {\r\n  color: #ff5416;\r\n  border: 1px solid #ff5416;\r\n}\r\n\r\n@media screen and (min-width: 800px) {\r\n  .online-user-list {\r\n    display: flex;\r\n    flex-wrap: wrap;\r\n  }\r\n  .online-user-list .online-item {\r\n    flex: 1 1 250px;\r\n  }\r\n}\r\n';
  const MTOnlineUser = {
    $data: {},
    init() {
      this.registerMenu();
    },
    registerMenu() {
      MenuRegister.add({
        key: "online-user",
        text: "⚙ 在线用户",
        autoReload: false,
        isStoreValue: false,
        showText(text) {
          return text;
        },
        callback: () => {
          this.showOnlineUser();
        },
      });
    },
    async showOnlineUser() {
      let $loading = Qmsg.loading("正在获取在线用户名单中...");
      let onlineUserInfo = await this.getOnlineUserListInfo();
      $loading.close();
      if (!onlineUserInfo) {
        return;
      }
      let $alert = __pops__.alert({
        title: {
          text: "在线用户",
          position: "center",
        },
        content: {
          text: `
                <div class="online-user-info">${onlineUserInfo.totalOnline} 人在线 - ${onlineUserInfo.onlineUser} 会员${onlineUserInfo.invisibleUser == 0 ? "" : `(${onlineUserInfo.invisibleUser}隐身)`} - ${onlineUserInfo.noRegisterUser} 位游客</div>
                <div class="online-user-filter">
                    <input placeholder="过滤用户名/身份/UID(可正则)"></div>
                <div class="online-user-list"></div>
                `,
          html: true,
        },
        btn: {
          ok: {
            text: "关闭",
            type: "default",
          },
        },
        width: PanelUISize.settingBig.width,
        height: PanelUISize.settingBig.height,
        style: onlineUserCSS,
      });
      let $list = $alert.$shadowRoot.querySelector(".online-user-list");
      let $filterInput = $alert.$shadowRoot.querySelector(".online-user-filter input");
      onlineUserInfo.data.forEach((item) => {
        let $item = this.createListViewItem(item);
        $list.appendChild($item);
      });
      Qmsg.success(`成功获取 ${onlineUserInfo.data.length}条数据`);
      let isSeaching = false;
      DOMUtils.on(
        $filterInput,
        ["propertychange", "input"],
        utils.debounce(() => {
          let inputText = $filterInput.value.trim();
          if (isSeaching) {
            return;
          }
          isSeaching = true;
          if (inputText == "") {
            $alert.$shadowRoot.querySelectorAll(".online-user-list .online-item").forEach((item) => {
              item.removeAttribute("style");
            });
            isSeaching = false;
            return;
          }
          $alert.$shadowRoot.querySelectorAll(".online-user-list .online-item").forEach((item) => {
            if (
              item.getAttribute("data-name").match(new RegExp(inputText, "ig")) ||
              item.getAttribute("data-sf").match(new RegExp(inputText, "ig")) ||
              item.getAttribute("data-uid").match(new RegExp(inputText, "ig"))
            ) {
              item.removeAttribute("style");
            } else {
              item.setAttribute("style", "display:none;");
            }
          });
          isSeaching = false;
        })
      );
    },
    async getOnlineUserListInfo() {
      let searchParamsData = {
        showoldetails: "yes",
      };
      let response = await httpx.get(`/forum.php?${utils.toSearchParamsStr(searchParamsData)}`, {
        headers: {
          "User-Agent": utils.getRandomPCUA(),
        },
      });
      if (!response.status) {
        return;
      }
      let pageHTML = utils.parseFromString(response.data.responseText, "text/html");
      let result = {
        data: [],
        totalOnline: 0,
        onlineUser: 0,
        noRegisterUser: 0,
        invisibleUser: 0,
      };
      let onlineList = pageHTML.querySelectorAll("#onlinelist ul li");
      onlineList.forEach((item) => {
        let uid = item.querySelector("a").getAttribute("href").match("uid-(.+?).html")[1];
        let avatar = MTUtils.getAvatar(uid, "middle");
        let name = item.querySelector("a").innerText;
        let sf = "";
        let space = item.querySelector("a").getAttribute("href");
        let memberSrc = item.querySelector("img").src;
        if (memberSrc.indexOf("online_member") != -1) {
          sf = "会员";
        } else if (memberSrc.indexOf("online_moderator") != -1) {
          sf = "版主";
        } else if (memberSrc.indexOf("online_supermod") != -1) {
          sf = "超级版主";
        } else if (memberSrc.indexOf("online_admin") != -1) {
          sf = "管理员";
        } else {
          sf = "未知身份";
        }
        result.data.push({
          uid,
          avatar,
          name,
          sf,
          space,
        });
      });
      let onlineInfo = pageHTML.querySelector("#online div.bm_h span.xs1").textContent;
      result.totalOnline = utils.parseInt(onlineInfo.match(/([0-9]*)\s*人在线/i), 0);
      result.onlineUser = utils.parseInt(onlineInfo.match(/([0-9]*)\s*会员/i), 0);
      result.noRegisterUser = utils.parseInt(onlineInfo.match(/([0-9]*)\s*位游客/i), 0);
      result.invisibleUser = utils.parseInt(onlineInfo.match(/([0-9]*)\s*隐身/i), 0);
      return result;
    },
    createListViewItem(userInfo) {
      let $item = DOMUtils.createElement(
        "div",
        {
          className: "online-item",
          innerHTML: `
                <div class="online-user">
                    <img data-avatar src="${userInfo["avatar"]}" loading="lazy" class="online-user-avatar">
                    <div class="online-user-info">
                        <p data-name>${userInfo["name"]}</p>
                        <span data-sf="${userInfo["sf"]}">${userInfo["sf"]}</span>
                        <span data-uid>UID: ${userInfo["uid"]}</span>
                    </div>
                </div>
            `,
        },
        {
          "data-name": userInfo.name,
          "data-uid": userInfo.uid,
          "data-sf": userInfo.sf,
        }
      );
      DOMUtils.on($item, "click", ".online-user-avatar", (event) => {
        DOMUtils.preventEvent(event);
        window.open(`home.php?mod=space&uid=${userInfo.uid}&do=profile`, "_blank");
      });
      return $item;
    },
  };
  const MT = {
    $flag: {
      showUserUID_initCSS: false,
    },
    init() {
      Panel.onceExec("mt-MTCommentFilter", () => {
        MTCommentFilter.init();
      });
      if (MTRouter.isPost()) {
        log.info(`Router: 帖子`);
        MTForumPost.init();
      } else if (MTRouter.isGuide()) {
        log.info(`Router: 导读`);
        MTGuide.init();
      } else {
        log.error(`Router: 未适配的链接 ==> ` + window.location.href);
      }
      domUtils.onReady(() => {
        Panel.onceExec("mt-MTProductListingReminder", () => {
          MTProductListingReminder.init();
        });
        Panel.onceExec("mt-blackHome", () => {
          MTBlackHome.init();
        });
        Panel.onceExec("mt-onlineUser", () => {
          MTOnlineUser.init();
        });
        Panel.execMenuOnce("mt-addLatestPostBtn", () => {
          return this.addLatestPostBtn();
        });
        Panel.execMenu("mt-auto-sign", () => {
          MTAutoSignIn.init();
        });
        Panel.execMenu("mt-extend-cookie-expire", () => {
          this.extendCookieExpire();
        });
        if (!MTRouter.isPostPublish_edit()) {
          Panel.execMenuOnce("mt-link-text-to-hyperlink", () => {
            return MTIdentifyLinks();
          });
        }
      });
    },
    addLatestPostBtn() {
      log.info(`新增【最新发表】`);
      const $latest_publication = domUtils.createElement("li", {
        id: "latest_publication",
        innerHTML: `
				<a href="/forum.php?mod=guide&view=newthread" hidefocus="true" title="最新发表">最新发表</a>
			`,
      });
      const $link = $latest_publication.querySelector("a");
      domUtils.append("#comiis_nv .wp.comiis_nvbox.cl ul", $latest_publication);
      if (window.location.href.includes("/forum.php?mod=guide&view=newthread")) {
        domUtils.removeClass("#mn_forum_10", "a");
        domUtils.css(
          $link,
          "background",
          'url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAADICAYAAAAk7PuyAAAAAXNSR0IArs4c6QAAAGFJREFUWEft1zESgCAQQ9HsVfb+d5RRlLHRVotHS5f5+YHKyymXiRAihKMISBDCNOInJHT39iTkcpkIYUcTCUKYkkKCEJBwTaY6cML5eiNGYiRGYrz9pqyDdbAOqxC/q8MApobR97qxnMwAAAAASUVORK5CYII=") repeat-x 50% -50px'
        );
      }
      return [$latest_publication];
    },
    async extendCookieExpire() {
      log.info(`延长cookie有效期`);
      let cookieList = await _GM.cookie.list({});
      let needExtendCookieNameList = ["_auth", "_saltkey", "_client_created", "_client_token"];
      cookieList.forEach(async (cookieItem) => {
        if (cookieItem.session) {
          return;
        }
        let expireTime = cookieItem.expirationDate;
        let nowTime = Date.now() / 1e3;
        if (expireTime < nowTime) {
          return;
        }
        let _30days = 60 * 60 * 24 * 30;
        if (expireTime - nowTime > _30days) {
          return;
        }
        let flag = needExtendCookieNameList.find((it) => cookieItem.name.endsWith(it));
        if (!flag) {
          return;
        }
        _GM.cookie
          .set({
            name: cookieItem.name,
            value: cookieItem.value,
            expirationDate: cookieItem.expirationDate + _30days,
          })
          .then(() => {
            log.info(`延长Cookie +30天成功:${cookieItem.name}`);
          })
          .catch(() => {
            log.error(`延长Cookie +30天失败:${cookieItem.name}`);
          });
      });
    },
  };
  const MTDyncmicAvatar = {
    $upload: {
      small: false,
      middle: false,
      big: false,
    },
    $data: {
      avatarInfo: {
        maxSize: 2097152,
        small: {
          width: 48,
          height: 48,
        },
        middle: {
          width: 120,
          height: 120,
        },
        big: {
          width: 200,
          height: 250,
        },
      },
    },
    $el: {
      $smallUpload: null,
      $middleUpload: null,
      $bigUpload: null,
      $smallStatus: null,
      $middleStatus: null,
      $bigStatus: null,
    },
    $avatar: {
      get small() {
        return MTDyncmicAvatar.$el.$smallUpload.files[0];
      },
      get middle() {
        return MTDyncmicAvatar.$el.$middleUpload.files[0];
      },
      get big() {
        return MTDyncmicAvatar.$el.$bigUpload.files[0];
      },
    },
    init() {
      this.showView();
    },
    showView() {
      const that = this;
      let $confirm = __pops__.confirm({
        title: {
          text: "修改头像",
          position: "center",
        },
        content: {
          text: `
                <div class="avatar-container">
                    <p class="avatar-tip">1. 小头像(图片宽高限制最大尺寸:48×48)</p>
                    <p class="avatar-upload-status" data-type="small">🤡请先上传图片</p>
                    <input type="file" class="avatar-upload" data-type="small" data-maxwidth="48" data-maxheight="48" accept="image/*">
                </div>
                <div class="avatar-container">
                    <p class="avatar-tip">2. 中头像(图片宽高限制最大尺寸:120×120)</p>
                    <p class="avatar-upload-status" data-type="middle">🤡请先上传图片</p>
                    <input type="file" class="avatar-upload" data-type="middle" data-maxwidth="120" data-maxheight="120" accept="image/*">
                </div>
                <div class="avatar-container">
                    <p class="avatar-tip">3. 大头像(图片宽高限制最大尺寸:200×250)</p>
                    <p class="avatar-upload-status" data-type="big">🤡请先上传图片</p>
                    <input type="file" class="avatar-upload" data-type="big" data-maxwidth="200" data-maxheight="250" accept="image/*">
                </div>
                `,
          html: true,
        },
        btn: {
          ok: {
            text: "上传",
            callback: async () => {
              if (!that.$upload.small) {
                Qmsg.error("请上传小头像");
                return;
              }
              if (!that.$upload.middle) {
                Qmsg.error("请上传中头像");
                return;
              }
              if (!that.$upload.big) {
                Qmsg.error("请上传大头像");
                return;
              }
              let $loading = Qmsg.loading("正在处理数据中...");
              try {
                let uploadUrl = await this.getUploadUrl();
                if (uploadUrl == null) {
                  return;
                }
                let formhash = await MTUtils.getFormHash();
                if (formhash == null) {
                  Qmsg.error("获取formhash失败");
                  return;
                }
                let avatarInfo = {
                  big: {
                    base64: await utils.parseFileToBase64(this.$avatar.big),
                  },
                  middle: {
                    base64: await utils.parseFileToBase64(this.$avatar.middle),
                  },
                  small: {
                    base64: await utils.parseFileToBase64(this.$avatar.small),
                  },
                };
                Object.keys(avatarInfo).forEach((keyName) => {
                  let value = avatarInfo[keyName];
                  value.base64 = value.base64.substring(value.base64.indexOf(",") + 1);
                });
                let formData = new FormData();
                formData.append("Filedata", this.$avatar.big || "");
                formData.append("confirm", "确定");
                formData.append("avatar1", avatarInfo.big.base64);
                formData.append("avatar2", avatarInfo.middle.base64);
                formData.append("avatar3", avatarInfo.small.base64);
                formData.append("formhash", formhash);
                log.info(`头像的base64字符串`, avatarInfo);
                let response = await httpx.post(uploadUrl, {
                  data: formData,
                  processData: false,
                  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.9",
                    "User-Agent": utils.getRandomPCUA(),
                    Host: window.location.hostname,
                    Origin: window.location.origin,
                    Referer: `${window.location.origin}/home.php?mod=spacecp&ac=avatar`,
                  },
                });
                if (!response.status) {
                  return;
                }
                if (response.data.responseText.indexOf("window.parent.postMessage('success','*')") != -1) {
                  $confirm.close();
                  Qmsg.success("上传成功");
                } else {
                  log.error("上传失败", response);
                  Qmsg.error(response.data.responseText, {
                    timeout: 6e3,
                    isHTML: false,
                  });
                }
              } catch (error) {
                log.error(error);
              } finally {
                $loading.close();
              }
            },
          },
        },
        width: window.innerWidth > 500 ? "500px" : "88vw",
        height: window.innerHeight > 500 ? "500px" : "80vh",
        style: `
            .avatar-container{
                display: flex;
                width: -webkit-fill-available;
                width: -moz-available;
                margin: 6px 10px;
                flex-direction: column;
            }
            .avatar-tip{
                float: left;
                font-weight: bold;
            }
            .avatar-upload-status {
                padding: 0px;
                padding-left: 10px;
                font-weight: bold;
                width: -webkit-fill-available;
                text-align: left;
                font-size: small;
            }
            .avatar-upload-status[data-success="false"]{
                color: red;
            }
            .avatar-upload-status[data-success="true"]{
                color: green;
            }
            .avatar-upload {
                margin: 20px 0px;
            }
            `,
      });
      this.$el.$smallUpload = $confirm.$shadowRoot.querySelector(".avatar-upload[data-type='small']");
      this.$el.$middleUpload = $confirm.$shadowRoot.querySelector(".avatar-upload[data-type='middle']");
      this.$el.$bigUpload = $confirm.$shadowRoot.querySelector(".avatar-upload[data-type='big']");
      this.$el.$smallStatus = $confirm.$shadowRoot.querySelector(".avatar-upload-status[data-type='small']");
      this.$el.$middleStatus = $confirm.$shadowRoot.querySelector(".avatar-upload-status[data-type='middle']");
      this.$el.$bigStatus = $confirm.$shadowRoot.querySelector(".avatar-upload-status[data-type='big']");
      this.setUploadChangeEvent(this.$el.$smallUpload, this.$el.$smallStatus, this.$data.avatarInfo.small, () => {
        this.$upload.small = true;
      });
      this.setUploadChangeEvent(this.$el.$middleUpload, this.$el.$middleStatus, this.$data.avatarInfo.middle, () => {
        this.$upload.middle = true;
      });
      this.setUploadChangeEvent(this.$el.$bigUpload, this.$el.$bigStatus, this.$data.avatarInfo.big, () => {
        this.$upload.big = true;
      });
    },
    setUploadChangeEvent($file, $status, sizeInfo, successCallBack) {
      domUtils.on($file, "change", (event) => {
        if (!$file.files?.length) {
          return;
        }
        domUtils.text($status, "🤡获取文件信息中...");
        $status.removeAttribute("data-success");
        let uploadImageFile = $file.files[0];
        let fileSize = uploadImageFile.size;
        let $image = new Image();
        let reader = new FileReader();
        reader.readAsDataURL(uploadImageFile);
        reader.onload = function (response) {
          $image.src = response.target.result;
          $image.onload = function () {
            if ($image.width > sizeInfo.width || $image.height > sizeInfo.height) {
              $file.value = "";
              $status.setAttribute("data-success", "false");
              domUtils.text($status, `🤡校验失败 ==> 图片尺寸不符合,宽:${$image.width} 高:${$image.height}`);
              return;
            }
            if (fileSize > MTDyncmicAvatar.$data.avatarInfo.maxSize) {
              $file.value = "";
              $status.setAttribute("data-success", "false");
              domUtils.text(
                $status,
                `🤡校验失败 ==> 图片大小不符合:${fileSize}byte,限制最大:${MTDyncmicAvatar.$data.avatarInfo.maxSize}byte`
              );
              return;
            }
            $status.setAttribute("data-success", "true");
            domUtils.text($status, `🤣 通过 宽:${$image.width} 高:${$image.height} 大小(byte):${fileSize}`);
            successCallBack();
          };
        };
      });
    },
    async getUploadUrl() {
      let response = await httpx.get("/home.php?mod=spacecp&ac=avatar", {
        headers: {
          "User-Agent": utils.getRandomPCUA(),
        },
      });
      if (!response.status) {
        return;
      }
      if (utils.isNull(response.data.responseText)) {
        Qmsg.error("动态头像:获取上传地址的内容失败");
        return;
      }
      let dataMatch = response.data.responseText.match(/var[\s]*data[\s]*=[\s]*"(.+?)"/);
      if (dataMatch == null || dataMatch.length != 2) {
        Qmsg.error("动态头像:获取变量data失败");
        return;
      }
      let data = dataMatch[dataMatch.length - 1];
      let data_split = data.split(",");
      let srcIndex = data_split.indexOf("stl_src");
      if (srcIndex === -1) {
        srcIndex = data_split.indexOf("src");
      }
      if (srcIndex === -1) {
        Qmsg.error("动态头像:获取上传地址失败");
        return;
      }
      let uploadUrl = data_split[srcIndex + 1];
      let uploadUrlInst = new URL(uploadUrl);
      uploadUrlInst.pathname = uploadUrlInst.pathname.replace("/images/camera.swf", "/index.php");
      uploadUrlInst.searchParams.delete("inajax");
      uploadUrlInst.searchParams.set("m", "user");
      uploadUrlInst.searchParams.set("a", "rectavatar");
      uploadUrlInst.searchParams.set("base64", "yes");
      uploadUrl = uploadUrlInst.toString();
      log.info(`上传地址:` + uploadUrl);
      return uploadUrl;
    },
  };
  const Component_Common = {
    id: "component-common",
    title: "通用",
    views: [
      {
        text: "",
        type: "container",
        views: [
          {
            text: "Toast配置",
            type: "deepMenu",
            views: [
              {
                text: "",
                type: "container",
                views: [
                  UISelect(
                    "Toast位置",
                    "qmsg-config-position",
                    "bottom",
                    [
                      {
                        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: "右下角",
                      },
                    ],
                    (isSelectedInfo) => {
                      log.info("设置当前Qmsg弹出位置" + isSelectedInfo.text);
                    },
                    "Toast显示在页面九宫格的位置"
                  ),
                  UISelect(
                    "最多显示的数量",
                    "qmsg-config-maxnums",
                    3,
                    [
                      {
                        value: 1,
                        text: "1",
                      },
                      {
                        value: 2,
                        text: "2",
                      },
                      {
                        value: 3,
                        text: "3",
                      },
                      {
                        value: 4,
                        text: "4",
                      },
                      {
                        value: 5,
                        text: "5",
                      },
                    ],
                    void 0,
                    "限制Toast显示的数量"
                  ),
                  UISwitch("逆序弹出", "qmsg-config-showreverse", false, void 0, "修改Toast弹出的顺序"),
                ],
              },
            ],
          },
        ],
      },
      {
        text: "",
        type: "container",
        views: [
          {
            text: "功能",
            type: "deepMenu",
            views: [
              {
                text: "",
                type: "container",
                views: [
                  UISwitch("新增【最新发表】", "mt-addLatestPostBtn", true, void 0, "便于快捷跳转"),
                  UISwitch(
                    "文本转超链接",
                    "mt-link-text-to-hyperlink",
                    true,
                    void 0,
                    "自动把符合超链接格式的文字转为超链接"
                  ),
                  UISwitch(
                    "延长登录Cookie过期时间",
                    "mt-extend-cookie-expire",
                    false,
                    void 0,
                    "减少频繁登录账号的问题"
                  ),
                ],
              },
            ],
          },
          {
            type: "deepMenu",
            text: "自动签到",
            views: [
              {
                text: "",
                type: "container",
                views: [
                  UISwitch("启用", "mt-auto-sign", true, void 0, "自动请求签到"),
                  UISwitch("使用fetch请求", "mt-auto-sign-useFetch", false, void 0, ""),
                  UIButton(
                    "签到信息",
                    `上次签到时间:${(() => {
                      let signInfo = MTAutoSignIn.getHostNameSignInfo(window.location.hostname);
                      if (signInfo) {
                        return Utils.formatTime(signInfo.time);
                      } else {
                        return "尚未签到";
                      }
                    })()}`,
                    "清空信息",
                    void 0,
                    void 0,
                    void 0,
                    "primary",
                    (event) => {
                      let $click = event.composedPath()[0];
                      let $desc = $click.closest("li").querySelector(".pops-panel-item-left-desc-text");
                      __pops__.confirm({
                        title: {
                          text: "提示 ",
                          position: "center",
                        },
                        content: {
                          text: "<p>是否清空脚本签到记录的时间?</p>",
                          html: true,
                        },
                        btn: {
                          ok: {
                            enable: true,
                            callback: (event2) => {
                              let hostName = window.location.hostname;
                              MTAutoSignIn.clearSignInfo(hostName);
                              Qmsg.success("删除成功");
                              domUtils.text(
                                $desc,
                                `上次签到时间:${(() => {
                                  let signInfo = MTAutoSignIn.getHostNameSignInfo(hostName);
                                  if (signInfo) {
                                    return Utils.formatTime(signInfo.time);
                                  } else {
                                    return "尚未签到";
                                  }
                                })()}`
                              );
                              event2.close();
                            },
                          },
                        },
                        width: "300px",
                        height: "200px",
                      });
                    }
                  ),
                ],
              },
            ],
          },
          {
            text: "头像",
            type: "deepMenu",
            views: [
              {
                text: "<a href='https://ezgif.com/resize' target='_blank'>Resize Image</a>",
                type: "container",
                views: [
                  UIOwn(
                    ($li) => {
                      const $left = domUtils.createElement("div", {
                        className: "pops-panel-item-left-text",
                        innerHTML: `
											<p class="pops-panel-item-left-main-text">头像(有缓存)</p>
											<p class="pops-panel-item-left-desc-text">小、中、大</p>
											`,
                      });
                      const $right = domUtils.createElement("div", {
                        className: "pops-panel-avatar-img",
                        innerHTML: `
											<img 
												src="/uc_server/avatar.php?uid=${MTUtils.getCurrentUID()}&size=small"
												class="avatar-img" data-size="small">
											<img 
												src="/uc_server/avatar.php?uid=${MTUtils.getCurrentUID()}&size=middle"
												class="avatar-img" data-size="middle">
											<img 
												src="/uc_server/avatar.php?uid=${MTUtils.getCurrentUID()}&size=big"
												class="avatar-img" data-size="big">
											`,
                      });
                      const $style = domUtils.createElement("style", {
                        innerHTML: `
											.avatar-img {
												width: 30px;
												height: 30px;
												border-radius: 50%;
												overflow: hidden;
											}
										`,
                      });
                      $right.querySelector(".avatar-img[data-size='small']");
                      $right.querySelector(".avatar-img[data-size='middle']");
                      $right.querySelector(".avatar-img[data-size='big']");
                      $li.appendChild($left);
                      $li.appendChild($right);
                      $li.appendChild($style);
                      return $li;
                    },
                    void 0,
                    {
                      text: "头像(有缓存)",
                      desc: "小、中、大",
                    }
                  ),
                  UIOwn(
                    ($li) => {
                      const $left = domUtils.createElement("div", {
                        className: "pops-panel-item-left-text",
                        innerHTML: `
											<p class="pops-panel-item-left-main-text">头像</p>
											<p class="pops-panel-item-left-desc-text">小、中、大</p>
											`,
                      });
                      const $right = domUtils.createElement("div", {
                        className: "pops-panel-avatar-img",
                        innerHTML: `
											<img 
												src="/uc_server/avatar.php?uid=${MTUtils.getCurrentUID()}&size=small&ts=${Date.now()}"
												class="avatar-img" data-size="small">
											<img 
												src="/uc_server/avatar.php?uid=${MTUtils.getCurrentUID()}&size=middle&ts=${Date.now()}"
												class="avatar-img" data-size="middle">
											<img 
												src="/uc_server/avatar.php?uid=${MTUtils.getCurrentUID()}&size=big&ts=${Date.now()}"
												class="avatar-img" data-size="big">
											`,
                      });
                      $li.appendChild($left);
                      $li.appendChild($right);
                      return $li;
                    },
                    void 0,
                    {
                      text: "头像",
                      desc: "小、中、大",
                    }
                  ),
                  UIButton(
                    "修改头像",
                    `可以上传gif图片,注意图片最大限制为${Utils.formatByteToSize(
                      MTDyncmicAvatar.$data.avatarInfo.maxSize
                    )}`,
                    "上传",
                    void 0,
                    false,
                    false,
                    "primary",
                    () => {
                      MTDyncmicAvatar.init();
                    }
                  ),
                ],
              },
            ],
          },
        ],
      },
    ],
  };
  const Component_ForumPost = {
    id: "component-forum-post",
    title: "帖子",
    views: [
      {
        type: "container",
        text: "",
        views: [
          {
            text: "功能",
            type: "deepMenu",
            views: [
              {
                type: "container",
                text: "",
                views: [
                  UISwitch(
                    "拦截附件",
                    "mt-forum-post-interceptionAttachment",
                    true,
                    void 0,
                    "点击附件时弹出提示框进行确认是否下载附件"
                  ),
                  UISwitch(
                    "图片查看优化",
                    "mt-forum-post-optimizationImagePreview",
                    true,
                    void 0,
                    "使用Viewer查看图片"
                  ),
                  UISwitch("自动加载下一页", "mt-forum-post-loadNextPageComment", true, void 0, "无缝预览下一页"),
                  UISwitch(
                    "代码块优化",
                    "mt-forum-post-codeQuoteOptimization",
                    true,
                    void 0,
                    "自动检测代码块语言并设置关键字高亮"
                  ),
                ],
              },
            ],
          },
          {
            type: "deepMenu",
            text: "用户信息块",
            views: [
              {
                type: "container",
                text: "",
                views: [
                  UISwitch(
                    "探测用户在线状态",
                    "mt-forum-post-detectingUserOnlineStatus",
                    false,
                    void 0,
                    "获取用户在线状态并在用户信息处显示状态表情"
                  ),
                  UISwitch(
                    "显示用户等级",
                    "mt-forum-post-showUserLevel",
                    true,
                    void 0,
                    "在用户信息处显示当前用户的等级"
                  ),
                  UISwitch(
                    "隐藏底部信息块",
                    "mt-forum-post-hideBottomInfoBlock",
                    false,
                    void 0,
                    "包括金币、好评、信誉等信息"
                  ),
                ],
              },
            ],
          },
          {
            type: "deepMenu",
            text: "右侧悬浮工具栏",
            views: [
              {
                type: "container",
                text: "",
                views: [
                  UISwitch(
                    "新增【快捷收藏】",
                    "mt-forum-post-quickCollentBtn",
                    true,
                    void 0,
                    "在右侧悬浮工具栏添加【收藏】按钮,用于快捷收藏"
                  ),
                  UISwitch(
                    "快捷回复优化",
                    "mt-forum-post-quickReplyOptimization",
                    true,
                    void 0,
                    "为快捷回复弹窗底部区域添加【一键空格】按钮"
                  ),
                ],
              },
            ],
          },
        ],
      },
    ],
  };
  const Component_Guide = {
    id: "component-guide",
    title: "导读",
    views: [
      {
        type: "container",
        text: "",
        views: [UISwitch("页面美化", "mt-guide-beautifyPage", true, void 0, "美化样式")],
      },
    ],
  };
  PanelContent.addContentConfig([Component_Common, Component_ForumPost, Component_Guide]);
  Panel.init();
  MT.init();
})(Qmsg, DOMUtils, pops, Utils, hljs, Viewer);