Greasy Fork

Greasy Fork is available in English.

LeetCodeRating|显示力扣周赛难度分

LeetCodeRating 力扣周赛分数显现和相关力扣小功能,目前浏览器更新规则,使用该插件前请手动打开浏览器开发者模式再食用~

目前为 2025-05-12 提交的版本,查看 最新版本

// ==UserScript==
// @name         LeetCodeRating|显示力扣周赛难度分
// @namespace    https://github.com/zhang-wangz
// @version      3.0.2
// @license      MIT
// @description  LeetCodeRating 力扣周赛分数显现和相关力扣小功能,目前浏览器更新规则,使用该插件前请手动打开浏览器开发者模式再食用~
// @author       小东是个阳光蛋(力扣名)
// @leetcodehomepage   https://leetcode.cn/u/runonline/
// @homepageURL  https://github.com/zhang-wangz/LeetCodeRating
// @contributionURL https://www.showdoc.com.cn/2069209189620830
// @run-at       document-end
// @match        *://*leetcode.cn/*
// @grant        GM_xmlhttpRequest
// @grant        GM_registerMenuCommand
// @grant        GM_unregisterMenuCommand
// @grant        GM_openInTab
// @grant        GM_notification
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_addStyle
// @grant        GM_getResourceText
// @connect      zerotrac.github.io
// @connect      raw.gitmirror.com
// @connect      hub.gitmirror.com
// @connect      raw.githubusercontents.com
// @connect      raw.githubusercontent.com
// @require      https://unpkg.com/[email protected]/dist/jquery.min.js
// @require      https://unpkg.com/[email protected]/dist/layui.js
// @grant        unsafeWindow
// ==/UserScript==

(async function () {
  'use strict';

  let version = '3.0.2';
  let pbstatusVersion = 'version16';
  // xhr劫持时使用,保留原始
  const dummySend = XMLHttpRequest.prototype.send;
  const originalOpen = XMLHttpRequest.prototype.open;
  // css 渲染
  $(document.body).append(
    `<link href="https://unpkg.com/[email protected]/index.min.css" rel="stylesheet">`
  );

  // 页面相关url
  const allUrl = 'https://leetcode.cn/problemset/.*';
  const pblistUrl = 'https://leetcode.cn/problem-list/.*';
  const pbUrl = 'https://leetcode.{2,7}/problems/.*';
  // 限定pbstatus使用, 不匹配题解链接
  const pbSolutionUrl = 'https://leetcode.{2,7}/problems/.*/solution.*';

  const searchUrl = 'https://leetcode.cn/search/.*';
  const studyUrl = 'https://leetcode.cn/studyplan/.*';
  const problemUrl = 'https://leetcode.cn/problemset';
  const discussUrl = 'https://leetcode.cn/discuss/.*';

  // req相关url
  const lcnojgo = 'https://leetcode.cn/graphql/noj-go/';
  const lcgraphql = 'https://leetcode.cn/graphql/';
  const chContestUrl = 'https://leetcode.cn/contest/';
  const zhContestUrl = 'https://leetcode.com/contest/';

  // 灵茶相关url
  const teaSheetUrl = 'https://docs.qq.com/sheet/DWGFoRGVZRmxNaXFz';
  // 因为ui更新,暂时去除,没有位置存放当前位置了
  // const lc0x3fsolveUrl = "https://huxulm.github.io/lc-rating/search"

  // 用于延时函数的通用id
  let id = '';
  // 制片人url, 通过接口从version.json拿取
  let papermanpic = '';

  // rank 相关数据
  let t2rate = JSON.parse(GM_getValue('t2ratedb', '{}').toString());
  // pbstatus数据
  let pbstatus = JSON.parse(GM_getValue('pbstatus', '{}').toString());
  // 题目名称-id ContestID_zh-ID
  // 中文
  let pbName2Id = JSON.parse(GM_getValue('pbName2Id', '{}').toString());
  // 英文
  let pbNamee2Id = JSON.parse(GM_getValue('pbNamee2Id', '{}').toString());
  // preDate为更新分数使用,preDate1为更新版本使用
  let preDate = GM_getValue('preDate', '');
  let preDate1 = GM_getValue('preDate1', '');
  // level数据
  let levelData = JSON.parse(GM_getValue('levelData', '{}').toString());
  // 中文
  let levelTc2Id = JSON.parse(GM_getValue('levelTc2Id', '{}').toString());
  // 英文
  let levelTe2Id = JSON.parse(GM_getValue('levelTe2Id', '{}').toString());
  // 是否使用动态布局
  let localVal = localStorage.getItem('used-dynamic-layout');
  let isDynamic = localVal != null ? localVal.includes('true') : false;

  // ElementGetter依赖相关
  let ElementGetter = (function () {
    const _jQuery = Symbol('jQuery');
    const _window = Symbol('window');
    const _matches = Symbol('matches');
    const _MutationObs = Symbol('MutationObs');
    const _listeners = Symbol('listeners');
    const _addObserver = Symbol('addObserver');
    const _addFilter = Symbol('addFilter');
    const _removeFilter = Symbol('removeFilter');
    const _query = Symbol('query');
    const _getOne = Symbol('getOne');
    const _getList = Symbol('getList');
    class ElementGetter {
      [_addObserver](target, callback) {
        const observer = new this[_MutationObs](mutations => {
          for (const mutation of mutations) {
            if (mutation.type === 'attributes') {
              callback(mutation.target);
              if (observer.canceled) return;
            }
            for (const node of mutation.addedNodes) {
              if (node instanceof Element) callback(node);
              if (observer.canceled) return;
            }
          }
        });
        observer.canceled = false;
        observer.observe(target, { childList: true, subtree: true, attributes: true });
        return () => {
          observer.canceled = true;
          observer.disconnect();
        };
      }
      [_addFilter](target, filter) {
        let listener = this[_listeners].get(target);
        if (!listener) {
          listener = {
            filters: new Set(),
            remove: this[_addObserver](target, el => {
              listener.filters.forEach(f => f(el));
            })
          };
          this[_listeners].set(target, listener);
        }
        listener.filters.add(filter);
      }
      [_removeFilter](target, filter) {
        const listener = this[_listeners].get(target);
        if (!listener) return;
        listener.filters.delete(filter);
        if (!listener.filters.size) {
          listener.remove();
          this[_listeners].delete(target);
        }
      }
      [_query](all, selector, parent, includeParent) {
        const $ = this[_jQuery];
        if ($) {
          let jNodes = includeParent ? $(parent) : $([]);
          jNodes = jNodes.add([...parent.querySelectorAll('*')]).filter(selector);
          if (all) {
            return $.map(jNodes, el => $(el));
          } else {
            return jNodes.length ? $(jNodes.get(0)) : null;
          }
        } else {
          const checkParent = includeParent && this[_matches].call(parent, selector);
          if (all) {
            const result = checkParent ? [parent] : [];
            result.push(...parent.querySelectorAll(selector));
            return result;
          } else {
            return checkParent ? parent : parent.querySelector(selector);
          }
        }
      }
      [_getOne](selector, parent, timeout) {
        return new Promise(resolve => {
          const node = this[_query](false, selector, parent, false);
          if (node) return resolve(node);
          let timer;
          const filter = el => {
            const node = this[_query](false, selector, el, true);
            if (node) {
              this[_removeFilter](parent, filter);
              timer && clearTimeout(timer);
              resolve(node);
            }
          };
          this[_addFilter](parent, filter);
          if (timeout > 0) {
            timer = setTimeout(() => {
              this[_removeFilter](parent, filter);
              resolve(null);
            }, timeout);
          }
        });
      }
      [_getList](selectorList, parent, timeout) {
        return Promise.all(selectorList.map(selector => this[_getOne](selector, parent, timeout)));
      }
      constructor(jQuery) {
        this[_jQuery] = jQuery && jQuery.fn && jQuery.fn.jquery ? jQuery : null;
        this[_window] = window.unsafeWindow || document.defaultView || window;
        const elProto = this[_window].Element.prototype;
        this[_matches] =
          elProto.matches ||
          elProto.matchesSelector ||
          elProto.mozMatchesSelector ||
          elProto.oMatchesSelector ||
          elProto.webkitMatchesSelector;
        this[_MutationObs] =
          this[_window].MutationObserver ||
          this[_window].WebkitMutationObserver ||
          this[_window].MozMutationObserver;
        this[_listeners] = new WeakMap();
      }
      get(selector, ...args) {
        const parent = (typeof args[0] !== 'number' && args.shift()) || this[_window].document;
        const timeout = args[0] || 0;
        if (Array.isArray(selector)) {
          return this[_getList](selector, parent, timeout);
        } else {
          return this[_getOne](selector, parent, timeout);
        }
      }
      each(selector, ...args) {
        const parent = (typeof args[0] !== 'function' && args.shift()) || this[_window].document;
        const callback = args[0];
        const refs = new WeakSet();
        const nodes = this[_query](true, selector, parent, false);
        for (const node of nodes) {
          refs.add(this[_jQuery] ? node.get(0) : node);
          if (callback(node, false) === false) return;
        }
        const filter = el => {
          const nodes = this[_query](true, selector, el, true);
          for (const node of nodes) {
            const _el = this[_jQuery] ? node.get(0) : node;
            if (!refs.has(_el)) {
              refs.add(_el);
              if (callback(node, true) === false) {
                return this[_removeFilter](parent, filter);
              }
            }
          }
        };
        this[_addFilter](parent, filter);
      }
      create(domString, parent) {
        const template = this[_window].document.createElement('template');
        template.innerHTML = domString;
        const node = template.content.firstElementChild || template.content.firstChild;
        parent ? parent.appendChild(node) : node.remove();
        return node;
      }
    }
    return ElementGetter;
  })();

  // 监听相关, 监听之后提出变化并且重启插件
  let debounceTimer = null;
  let isSelfChanging = false;
  const observedElements = new WeakMap();

  function observeIfNeeded(target) {
    if (!target || !(target instanceof Node)) return;
    if (observedElements.has(target)) return;

    const observer = new MutationObserver(mutationsList => {
      if (isSelfChanging) return;
      if (debounceTimer) return;
      console.log('内容变化,执行 clearAndStart');
      clearAndStart(location.href, 500, false);
      debounceTimer = setTimeout(() => {
        debounceTimer = null;
      }, 5000); // 连续变化时只触发一次
    });

    observer.observe(target, {
      childList: true,
      characterData: true,
      subtree: true
    });

    observedElements.set(target, observer);
  }

  function getPbNameId(pbName) {
    pbName2Id = JSON.parse(GM_getValue('pbName2Id', '{}').toString());
    pbNamee2Id = JSON.parse(GM_getValue('pbNamee2Id', '{}').toString());
    let id = null;
    if (pbName2Id[pbName]) {
      id = pbName2Id[pbName];
    } else if (pbNamee2Id[pbName]) {
      id = pbNamee2Id[pbName];
    }
    return id;
  }

  function getLevelId(pbName) {
    levelTc2Id = JSON.parse(GM_getValue('levelTc2Id', '{}').toString());
    levelTe2Id = JSON.parse(GM_getValue('levelTe2Id', '{}').toString());
    if (levelTc2Id[pbName]) {
      return levelTc2Id[pbName];
    }
    if (levelTe2Id[pbName]) {
      return levelTe2Id[pbName];
    }
    return null;
  }

  // 同步函数
  function waitForKeyElements(selectorTxt, actionFunction, bWaitOnce, iframeSelector) {
    let targetNodes, btargetsFound;
    if (typeof iframeSelector == 'null') targetNodes = $(selectorTxt);
    else targetNodes = $(iframeSelector).contents().find(selectorTxt);

    if (targetNodes && targetNodes.length > 0) {
      btargetsFound = true;
      targetNodes.each(function () {
        let jThis = $(this);
        let alreadyFound = jThis.data('alreadyFound') || false;
        if (!alreadyFound) {
          let cancelFound = actionFunction(jThis);
          if (cancelFound) btargetsFound = false;
          else jThis.data('alreadyFound', true);
        }
      });
    } else {
      btargetsFound = false;
    }
    let controlObj = waitForKeyElements.controlObj || {};
    let controlKey = selectorTxt.replace(/[^\w]/g, '_');
    let timeControl = controlObj[controlKey];
    if (btargetsFound && bWaitOnce && timeControl) {
      clearInterval(timeControl);
      delete controlObj[controlKey];
    } else {
      if (!timeControl) {
        timeControl = setInterval(function () {
          waitForKeyElements(selectorTxt, actionFunction, bWaitOnce, iframeSelector);
        }, 300);
        controlObj[controlKey] = timeControl;
      }
    }
    waitForKeyElements.controlObj = controlObj;
  }

  let ajaxReq = (type, reqUrl, headers, data, successFuc, withCredentials = true) => {
    $.ajax({
      // 请求方式
      type: type,
      // 请求的媒体类型
      contentType: 'application/json;charset=UTF-8',
      // 请求地址
      url: reqUrl,
      // 数据,json字符串
      data: data != null ? JSON.stringify(data) : null,
      // 同步方式
      async: false,
      xhrFields: {
        withCredentials: true
      },
      headers: headers,
      // 请求成功
      success: function (result) {
        successFuc(result);
      },
      // 请求失败,包含具体的错误信息
      error: function (e) {
        console.log(e.status);
        console.log(e.responseText);
      }
    });
  };

  // 刷新菜单
  script_setting();
  // 注册urlchange事件
  initUrlChange()();

  // 常量数据
  const regDiss = '.*//leetcode.cn/problems/.*/discussion/.*';
  const regSovle = '.*//leetcode.cn/problems/.*/solutions/.*';
  const regPbSubmission = '.*//leetcode.cn/problems/.*/submissions/.*';

  // 监听urlchange事件定义
  function initUrlChange() {
    let isLoad = false;
    const load = () => {
      if (isLoad) return;
      isLoad = true;
      const oldPushState = history.pushState;
      const oldReplaceState = history.replaceState;
      history.pushState = function pushState(...args) {
        const res = oldPushState.apply(this, args);
        window.dispatchEvent(new Event('urlchange'));
        return res;
      };
      history.replaceState = function replaceState(...args) {
        const res = oldReplaceState.apply(this, args);
        window.dispatchEvent(new Event('urlchange'));
        return res;
      };
      window.addEventListener('popstate', () => {
        window.dispatchEvent(new Event('urlchange'));
      });
    };
    return load;
  }

  let isVpn = !GM_getValue('switchvpn');
  // 访问相关url
  let versionUrl, sciptUrl, rakingUrl, levelUrl;
  if (isVpn) {
    versionUrl = 'https://raw.githubusercontent.com/zhang-wangz/LeetCodeRating/main/version.json';
    sciptUrl =
      'https://raw.githubusercontent.com/zhang-wangz/LeetCodeRating/main/leetcodeRating_greasyfork.user.js';
    rakingUrl = 'https://zerotrac.github.io/leetcode_problem_rating/data.json';
    levelUrl =
      'https://raw.githubusercontent.com/zhang-wangz/LeetCodeRating/main/stormlevel/data.json';
  } else {
    versionUrl = 'https://raw.gitmirror.com/zhang-wangz/LeetCodeRating/main/version.json';
    sciptUrl =
      'https://raw.gitmirror.com/zhang-wangz/LeetCodeRating/main/leetcodeRating_greasyfork.user.js';
    rakingUrl = 'https://raw.gitmirror.com/zerotrac/leetcode_problem_rating/main/data.json';
    levelUrl = 'https://raw.gitmirror.com/zhang-wangz/LeetCodeRating/main/stormlevel/data.json';
  }

  // 菜单方法定义
  function script_setting() {
    let menu_ALL = [
        ['switchvpn', 'vpn', '是否使用cdn访问数据', false, false],
        ['switchupdate', 'switchupdate', '是否每天最多只更新一次', true, true],
        ['switchTea', '0x3f tea', '题库页灵茶信息显示', true, true],
        ['switchpbRepo', 'pbRepo function', '题库页周赛难度评分(不包括灵茶)', true, false],
        ['switchpbscore', 'pb function', '题目页周赛难度评分', true, true],
        ['switchcopyright', 'pb function', '题解复制去除版权信息', true, true],
        ['switchpbside', 'switchpbside function', '题目页侧边栏分数显示', true, true],
        ['switchpbsearch', 'switchpbsearch function', '题目页题目搜索框', true, true],
        ['switchsearch', 'search function', '题目搜索页周赛难度评分', true, false],
        [
          'switchpblist',
          'pbList function',
          '题单页周赛难度评分(包含自定义和官方题单)',
          true,
          false
        ],
        ['switchpblistRateDisplay', 'pbList function', '题单页一直显示通过率', true, false],
        ['switchstudy', 'studyplan function', '学习计划周赛难度评分', true, false],
        ['switchcontestpage', 'contestpage function', '竞赛页面双栏布局', true, false],
        [
          'switchlevel',
          'studyplan level function',
          '算术评级(显示题库/题单/题目/学习计划页)',
          true,
          false
        ],
        ['switchrealoj', 'delvip function', '模拟oj环境(去除通过率,难度,周赛Qidx等)', false, true],
        ['switchdark', 'dark function', '自动切换白天黑夜模式(早8晚8切换制)', false, true],
        ['switchpbstatus', 'pbstatus function', '讨论区和题目页显示题目完成状态', true, true],
        [
          'switchpbstatusscoredefault',
          'pbstatusscore function',
          '题目完成状态增加难度分和会员题状态',
          false,
          true
        ],
        [
          'switchpbstatusLocationRight',
          'switchpbstatusLocation function',
          '题目显示完成状态(位置改为右方)',
          false,
          true
        ],
        [
          'switchpbstatusBtn',
          'pbstatusBtn function',
          '讨论区和题目页添加同步题目状态按钮',
          true,
          true
        ],
        ['switchperson', 'person function', '纸片人', false, true]
      ],
      menu_ID = [],
      menu_ID_Content = [];
    for (const element of menu_ALL) {
      // 如果读取到的值为 null 就写入默认值
      if (GM_getValue(element[0]) == null) {
        GM_setValue(element[0], element[3]);
      }
    }
    registerMenuCommand();

    // 注册脚本菜单
    function registerMenuCommand() {
      if (menu_ID.length > menu_ALL.length) {
        // 如果菜单ID数组多于菜单数组,说明不是首次添加菜单,需要卸载所有脚本菜单
        for (const element of menu_ID) {
          GM_unregisterMenuCommand(element);
        }
      }
      for (let i = 0; i < menu_ALL.length; i++) {
        // 循环注册脚本菜单
        menu_ALL[i][3] = GM_getValue(menu_ALL[i][0]);
        let content = `${menu_ALL[i][3] ? '✅' : '❎'} ${menu_ALL[i][2]}`;
        menu_ID[i] = GM_registerMenuCommand(content, function () {
          menu_switch(
            `${menu_ALL[i][0]}`,
            `${menu_ALL[i][1]}`,
            `${menu_ALL[i][2]}`,
            `${menu_ALL[i][3]}`
          );
        });
        menu_ID_Content[i] = content;
      }
      menu_ID[menu_ID.length] = GM_registerMenuCommand(`🏁 当前版本 ${version}`, function () {});
      menu_ID_Content[menu_ID_Content.length] = `🏁 当前版本 ${version}`;
      menu_ID[menu_ID.length + 1] = GM_registerMenuCommand(`🏁 企鹅群号 654726006`, function () {});
      menu_ID_Content[menu_ID_Content.length + 1] = `🏁 654726006`;
    }

    //切换选项
    function menu_switch(name, ename, cname, value) {
      if (value == 'false') {
        GM_setValue(`${name}`, true);
        registerMenuCommand(); // 重新注册脚本菜单
        location.reload(); // 刷新网页
        GM_notification({ text: `「${cname}」已开启\n`, timeout: 3500 }); // 提示消息
      } else {
        GM_setValue(`${name}`, false);
        registerMenuCommand(); // 重新注册脚本菜单
        location.reload(); // 刷新网页
        GM_notification({ text: `「${cname}」已关闭\n`, timeout: 3500 }); // 提示消息
      }
      registerMenuCommand(); // 重新注册脚本菜单
    }
  }

  function copyNoRight() {
    new ElementGetter().each('.WRmCx > div:has(code)', document, item => {
      addCopy(item);
      let observer = new MutationObserver(function (mutationsList, observer) {
        // 检查每个变化
        mutationsList.forEach(function (mutation) {
          addCopy(item);
        });
      });
      // 配置 MutationObserver 监听的内容和选项
      let config = { attributes: false, childList: true, subtree: false };
      observer.observe(item, config);
    });
    function addCopy(item) {
      let nowShow = item.querySelector('div:not(.hidden) > div.group.relative > pre > code');
      console.log(nowShow);
      let copyNode = nowShow.parentElement.nextElementSibling.cloneNode(true);
      nowShow.parentElement.nextElementSibling.setAttribute('hidden', true);
      copyNode.classList.add('copyNode');
      copyNode.onclick = function () {
        let nowShow = item.querySelector('div:not(.hidden) > div.group.relative > pre > code');
        navigator.clipboard.writeText(nowShow.textContent).then(() => {
          layer.msg('复制成功');
        });
      };
      nowShow.parentNode.parentNode.appendChild(copyNode);
    }
  }
  if (GM_getValue('switchcopyright') && location.href.match(pbUrl)) copyNoRight();

  // lc 基础req
  let baseReq = (type, reqUrl, query, variables, successFuc) => {
    //请求参数
    let list = { query: query, variables: variables };
    //
    ajaxReq(type, reqUrl, null, list, successFuc);
  };

  // post请求
  let postReq = (reqUrl, query, variables, successFuc) => {
    baseReq('POST', reqUrl, query, variables, successFuc);
  };

  // 基础函数休眠
  async function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
  }

  let lcTheme = mode => {
    let headers = {
      accept: '*/*',
      'accept-language': 'zh-CN,zh;q=0.9,zh-TW;q=0.8,en;q=0.7',
      'content-type': 'application/json'
    };
    let body = {
      operationName: 'setTheme',
      query:
        '\n    mutation setTheme($darkMode: String!) {\n  setDarkSide(darkMode: $darkMode)\n}\n    ',
      variables: {
        darkMode: mode
      }
    };
    ajaxReq('POST', lcnojgo, headers, body, () => {});
  };

  if (GM_getValue('switchdark')) {
    let h = new Date().getHours();
    if (h >= 8 && h < 20) {
      lcTheme('light');
      localStorage.setItem('lc-dark-side', 'light');
      console.log('修改至light mode...');
    } else {
      lcTheme('dark');
      localStorage.setItem('lc-dark-side', 'dark');
      console.log('修改至dark mode...');
    }
  }

  function allPbPostData(skip, limit) {
    let reqs = {
      query: `query problemsetQuestionList($categorySlug: String, $limit: Int, $skip: Int, $filters: QuestionListFilterInput) {
                problemsetQuestionList(
                    categorySlug: $categorySlug
                    limit: $limit
                    skip: $skip
                    filters: $filters
                ) {
                    hasMore
                    total
                    questions {
                    acRate
                    difficulty
                    freqBar
                    frontendQuestionId
                    isFavor
                    paidOnly
                    solutionNum
                    status
                    title
                    titleCn
                    titleSlug
                    topicTags {
                        name
                        nameTranslated
                        id
                        slug
                    }
                    extra {
                        hasVideoSolution
                        topCompanyTags {
                        imgUrl
                        slug
                        numSubscribed
                        }
                    }
                    }
                }
            }`,
      variables: {
        categorySlug: 'all-code-essentials',
        skip: skip,
        limit: limit,
        filters: {}
      }
    };
    reqs.key = 'LeetcodeRating';
    return reqs;
  }

  function getpbCnt() {
    let total = 0;
    let headers = {
      'Content-Type': 'application/json'
    };
    ajaxReq('POST', lcgraphql, headers, allPbPostData(0, 0), res => {
      total = res.data.problemsetQuestionList.total;
    });
    return total;
  }

  // 从题目链接提取slug
  // 在这之前需要匹配出所有符合条件的a标签链接
  function getSlug(problemUrl) {
    let preUrl = 'https://leetcode-cn.com/problems/';
    let nowurl = 'https://leetcode.cn/problems/';
    if (problemUrl.startsWith(preUrl)) return problemUrl.replace(preUrl, '').split('/')[0];
    else if (problemUrl.startsWith(nowurl)) return problemUrl.replace(nowurl, '').split('/')[0];
    return null;
  }

  // 获取题目相关内容
  function getpbRelation(pburl) {
    let pbstatus = JSON.parse(GM_getValue('pbstatus', '{}').toString());
    let titleSlug = getSlug(pburl);
    if (!titleSlug) return [null, null, null];
    let status = pbstatus[titleSlug] == null ? 'NOT_STARTED' : pbstatus[titleSlug]['status'];
    // 获取分数
    let score;
    let idExist = pbstatus[titleSlug] != null && t2rate[pbstatus[titleSlug]['id']] != null;
    if (idExist) {
      score = t2rate[pbstatus[titleSlug]['id']]['Rating'];
    }
    let paid = pbstatus[titleSlug] == null ? null : pbstatus[titleSlug]['paidOnly'];
    return [status, score, paid];
  }

  // 1 ac 2 tried 3 not_started
  function getPbstatusIcon(code, score, paid) {
    let value;
    switch (code) {
      case 1:
        value = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="1em" height="1em" fill="currentColor" class="myiconsvg h-[18px] w-[18px]  text-green-s dark:text-dark-green-s"><path fill-rule="evenodd" d="M20 12.005v-.828a1 1 0 112 0v.829a10 10 0 11-5.93-9.14 1 1 0 01-.814 1.826A8 8 0 1020 12.005zM8.593 10.852a1 1 0 011.414 0L12 12.844l8.293-8.3a1 1 0 011.415 1.413l-9 9.009a1 1 0 01-1.415 0l-2.7-2.7a1 1 0 010-1.414z" clip-rule="evenodd"></path></svg> `;
        break;
      case 2:
        value = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="1.6 0 12.5 14" width="1.2em" height="1.2em" fill="currentColor" class="myiconsvg text-message-warning dark:text-message-warning"><path d="M6.998 7v-.6a.6.6 0 00-.6.6h.6zm.05 0h.6a.6.6 0 00-.6-.6V7zm0 .045v.6a.6.6 0 00.6-.6h-.6zm-.05 0h-.6a.6.6 0 00.6.6v-.6zm5-.045a5 5 0 01-5 5v1.2a6.2 6.2 0 006.2-6.2h-1.2zm-5 5a5 5 0 01-5-5h-1.2a6.2 6.2 0 006.2 6.2V12zm-5-5a5 5 0 015-5V.8A6.2 6.2 0 00.798 7h1.2zm5-5a5 5 0 015 5h1.2a6.2 6.2 0 00-6.2-6.2V2zm2.2 5a2.2 2.2 0 01-2.2 2.2v1.2a3.4 3.4 0 003.4-3.4h-1.2zm-2.2 2.2a2.2 2.2 0 01-2.2-2.2h-1.2a3.4 3.4 0 003.4 3.4V9.2zM4.798 7a2.2 2.2 0 012.2-2.2V3.6a3.4 3.4 0 00-3.4 3.4h1.2zm2.2-2.2a2.2 2.2 0 012.2 2.2h1.2a3.4 3.4 0 00-3.4-3.4v1.2zm0 2.8h.05V6.4h-.05v1.2zm-.55-.6v.045h1.2V7h-1.2zm.6-.555h-.05v1.2h.05v-1.2zm.55.6V7h-1.2v.045h1.2z"></path></svg> `;
        break;
      // code3 的时候需要调整style,所以设置了class,调整在css中
      case 3:
        value = `<svg class="myiconsvg" width="21" height="20">
                            <circle class="mycircle" stroke="black" stroke-width="2" fill="white"></circle>
                        </svg> `;
        break;
      default:
        value = '';
        break;
    }
    //  [难度分 1980] (会员题)
    if (GM_getValue('switchpbstatusscoredefault')) {
      if (score) {
        value += ` [难度分 ${score}] `;
      }
      if (paid != null && paid != false) {
        value += ` (会员题) `;
      }
    }
    return value;
  }

  function handleLink(link) {
    // 每日一题或者是标签icon内容,不做更改直接跳过
    // no-underline是标题
    // rounded排除每日一题的火花和题目侧边栏,火花一开始刷新时候href为空,直到lc请求接口之后才显示每日一题链接,所以有一瞬间的时间会错误识别
    if (
      link.href.includes('daily-question') ||
      link.getAttribute('class')?.includes('rounded') ||
      link.getAttribute('data-state') ||
      link.getAttribute('class')?.includes('no-underline')
    ) {
      link.setAttribute('linkId', 'leetcodeRating');
      return;
    }
    // console.log(link.href)
    // console.log(link)
    let linkId = link.getAttribute('linkId');
    if (linkId != null && linkId == 'leetcodeRating') {
      console.log(getSlug(link.href) + '已经替换..., 略过');
      return;
    }
    let [status, score, paid] = getpbRelation(link.href);
    if (!status) {
      link.setAttribute('linkId', 'leetcodeRating');
      return;
    }
    // console.log(status);
    // 1 ac 2 tried 3 not_started
    let code = status == 'NOT_STARTED' ? 3 : status == 'AC' ? 1 : 2;
    // console.log(code);
    let iconStr = getPbstatusIcon(code, score, paid);
    let iconEle = document.createElement('span');
    iconEle.innerHTML = iconStr;
    // console.log(iconEle);
    // 获取元素的父节点
    link.setAttribute('linkId', 'leetcodeRating');
    const parent = link.parentNode;
    // 改变方位
    // 功能不开启的时候移动到左边-历史遗留问题
    if (!GM_getValue('switchpbstatusLocationRight')) {
      parent.insertBefore(iconEle, link);
    } else {
      if (link.nextSibling) {
        parent.insertBefore(iconEle, link.nextSibling);
      } else {
        parent.appendChild(iconEle);
      }
    }
  }

  async function createstatusBtn() {
    // console.log("start...")
    if (document.querySelector('#statusBtn')) return;
    let span = document.createElement('span');
    span.setAttribute('data-small-spacing', 'true');
    span.setAttribute('id', 'statusBtn');
    // 判断同步按钮
    if (GM_getValue('switchpbstatusBtn')) {
      // console.log(levelData[id])
      span.innerHTML = `<i style="font-size:12px;" class="layui-icon layui-icon-refresh"></i> 同步题目状态`;
      span.onclick = function (e) {
        layer.open({
          type: 1,
          content: `${pbstatusContent}`,
          title: '同步所有题目状态',
          area: ['550px', '250px'],
          shade: 0.6
        });
      };
      // 使用layui的渲染
      layuiload();
    }
    new ElementGetter().each('.flex-wrap.items-center', document, userinfo => {
      if (userinfo?.lastChild?.textContent?.includes('发布于')) {
        // console.log(userinfo)
        span.setAttribute('class', userinfo.lastChild.getAttribute('class'));
        span.setAttribute('class', span.getAttribute('class') + ' hover:text-blue-s');
        span.setAttribute('style', 'cursor:pointer');
        userinfo.appendChild(span);
      }
    });
    // console.log("end...")
  }

  // 监听变化
  // 改变大小
  let whetherSolution = location.href.match(pbUrl);
  if (whetherSolution) {
    // 左边
    if (!GM_getValue('switchpbstatusLocationRight')) {
      GM_addStyle(`
                circle.mycircle {
                    cx: 9;
                    cy: 9;
                    r: 7;
                }
            `);
    } else {
      // 右边
      GM_addStyle(`
                circle.mycircle {
                    cx: 13;
                    cy: 9;
                    r: 7;
                }
            `);
    }
  } else {
    // 左边
    if (!GM_getValue('switchpbstatusLocationRight')) {
      GM_addStyle(`
                circle.mycircle {
                    cx: 8;
                    cy: 9;
                    r: 7;
                }
            `);
    } else {
      // 右边
      GM_addStyle(`
                circle.mycircle {
                    cx: 13;
                    cy: 10;
                    r: 7;
                }
            `);
    }
  }

  function realOpr() {
    // 只有讨论区才制作同步按钮,题解区不做更改
    if (window.location.href.match(discussUrl)) {
      createstatusBtn();
    }
    // 只有讨论区和题目页进行a标签制作
    if (window.location.href.match(discussUrl) || window.location.href.match(pbUrl)) {
      // 获取所有的<a>标签
      let links = document.querySelectorAll('a');
      // 过滤出符合条件的<a>标签
      let matchingLinks = Array.from(links).filter(link => {
        return (
          !link.getAttribute('linkId') && link.href.match(pbUrl) && !link.href.match(pbSolutionUrl)
        );
      });
      // console.log(matchingLinks);
      // 符合条件的<a>标签
      matchingLinks.forEach(link => {
        handleLink(link);
      });
    }
  }
  function waitOprpbStatus() {
    if (GM_getValue('switchpbstatus')) {
      if (window.location.href.match(discussUrl) || window.location.href.match(pbUrl)) {
        let css_flag = '';
        if (window.location.href.match(discussUrl)) {
          // css_flag = ".css-qciawt-Wrapper";
          css_flag = '.relative.flex';
        } else {
          css_flag = '#qd-content';
        }
        new ElementGetter().each(css_flag, document, item => {
          if (window.location.href.match(discussUrl)) realOpr();
          let observer = new MutationObserver(function (mutationsList, observer) {
            // 检查变化
            mutationsList.forEach(function (mutation) {
              realOpr();
            });
          });
          // 配置 MutationObserver 监听的内容和选项
          let config = { attributes: false, childList: true, subtree: true };
          observer.observe(item, config);
        });
      }
    }
  }
  waitOprpbStatus();

  function pbsubmitListen() {
    var originalFetch = fetch;
    window.unsafeWindow.fetch = function () {
      return originalFetch.apply(this, arguments).then(function (response) {
        let checkUrl = 'https://leetcode.cn/submissions/detail/[0-9]*/check/.*';
        let clonedResponse = response.clone();
        clonedResponse.text().then(function (bodyText) {
          if (
            clonedResponse.url.match(checkUrl) &&
            clonedResponse.status == 200 &&
            clonedResponse.ok
          ) {
            // console.log('HTTP请求完成:', arguments[0]);
            let resp = JSON.parse(bodyText);
            // console.log('响应数据:', resp);
            if (resp?.status_msg?.includes('Accepted')) {
              let pbstatus = JSON.parse(GM_getValue('pbstatus', '{}').toString());
              let slug = getSlug(location.href);
              if (!pbstatus[slug]) pbstatus[slug] = {};
              pbstatus[slug]['status'] = 'AC';
              GM_setValue('pbstatus', JSON.stringify(pbstatus));
              console.log('提交成功,当前题目状态已更新');
            } else if (resp?.status_msg && !resp.status_msg.includes('Accepted')) {
              let pbstatus = JSON.parse(GM_getValue('pbstatus', '{}').toString());
              let slug = getSlug(location.href);
              // 同步一下之前的记录是什么状态
              let query =
                '\n    query userQuestionStatus($titleSlug: String!) {\n  question(titleSlug: $titleSlug) {\n    status\n  }\n}\n    ';
              let headers = {
                'Content-Type': 'application/json'
              };
              let postdata = {
                query: query,
                variables: {
                  titleSlug: slug
                },
                operationName: 'userQuestionStatus'
              };
              let status;
              ajaxReq('POST', lcgraphql, headers, postdata, response => {
                status = response.data.question.status;
              });
              // 如果之前为ac状态,那么停止更新,直接返回
              if (status && status == 'ac') {
                if (!pbstatus[slug]) pbstatus[slug] = {};
                pbstatus[slug]['status'] = 'AC';
                GM_setValue('pbstatus', JSON.stringify(pbstatus));
                console.log('提交失败,但是之前已经ac过该题,所以状态为ac');
              } else {
                // 之前没有提交过或者提交过但是没有ac的状态,那么仍然更新为提交失败状态
                if (!pbstatus[slug]) pbstatus[slug] = {};
                pbstatus[slug]['status'] = 'TRIED';
                GM_setValue('pbstatus', JSON.stringify(pbstatus));
                console.log('提交失败, 当前题目状态已更新');
              }
            }
          }
        });
        return response;
      });
    };
  }
  if (GM_getValue('switchpbstatus') && location.href.match(pbUrl)) pbsubmitListen();

  // 获取数字
  function getcontestNumber(url) {
    return parseInt(url.substr(15));
  }

  // 获取时间
  function getCurrentDate(format) {
    let now = new Date();
    let year = now.getFullYear(); //得到年份
    let month = now.getMonth(); //得到月份
    let date = now.getDate(); //得到日期
    let hour = now.getHours(); //得到小时
    let minu = now.getMinutes(); //得到分钟
    let sec = now.getSeconds(); //得到秒
    month = month + 1;
    if (month < 10) month = '0' + month;
    if (date < 10) date = '0' + date;
    if (hour < 10) hour = '0' + hour;
    if (minu < 10) minu = '0' + minu;
    if (sec < 10) sec = '0' + sec;
    let time = '';
    // 精确到天
    if (format == 1) {
      time = year + '年' + month + '月' + date + '日';
    }
    // 精确到分
    else if (format == 2) {
      time = year + '-' + month + '-' + date + ' ' + hour + ':' + minu + ':' + sec;
    } else if (format == 3) {
      time = year + '/' + month + '/' + date;
    }
    return time;
  }

  GM_addStyle(`
        .containerlingtea {
            background: rgba(233, 183, 33, 0.2);
            white-space: pre-wrap;
            word-wrap: break-word;
            display: block;
        }
    `);

  // 因为力扣未捕获错误信息,所以重写一下removechild方法
  const removeChildFn = Node.prototype.removeChild;
  Node.prototype.removeChild = function (n) {
    let err = null;
    try {
      err = removeChildFn.call(this, n); // 正常删除
    } catch (error) {
      if (!error.toString().includes('NotFoundError'))
        console.log('力扣api发生错误: ', error.toString().substr(0, 150));
    }
    return err;
  };

  // 竞赛页面双栏布局
  // 来源 better contest page / author ExplodingKonjac
  let switchcontestpage = GM_getValue('switchcontestpage');
  if (location.href.match('https://leetcode.cn/contest/.*/problems/.*') && switchcontestpage) {
    const CSS = `
            body {
                display: flex;
                flex-direction: column;
            }

            body .content-wrapper {
                height: 0;
                min-height: 0 !important;
                flex: 1;
                display: flex;
                flex-direction: column;
                padding-bottom: 0 !important;
            }

            .content-wrapper #base_content {
                display: flex;
                overflow: hidden;
                height: 0;
                flex: 1;
            }

            .content-wrapper #base_content > .container {
                width: 40%;
                overflow: scroll;
            }

            .content-wrapper #base_content > .container .question-content {
                overflow: unset !important;
            }

            .content-wrapper #base_content > .container .question-content > pre {
                white-space: break-spaces;
            }

            .content-wrapper #base_content > .editor-container {
                flex: 1;
                overflow: scroll;
            }

            .content-wrapper #base_content > .editor-container .container {
                width: 100% !important;
            }

            .content-wrapper #base_content > .custom-resize {
                width: 4px;
                height: 100%;
                background: #eee;
                cursor: ew-resize;
                margin: 0 2px;
            }

            .content-wrapper #base_content > .custom-resize:hover {
                background: #1a90ff;
            }
        `;

    const storageKey = '--previous-editor-size';
    (function () {
      const $css = document.createElement('style');
      $css.innerHTML = CSS;
      document.head.append($css);
      const $problem = document.querySelector('.content-wrapper #base_content > .container');
      const $editor = document.querySelector('.content-wrapper #base_content > .editor-container');
      const $resize = document.createElement('div');
      if (localStorage.getItem(storageKey)) {
        $problem.style.width = localStorage.getItem(storageKey);
      }
      $editor.parentElement.insertBefore($resize, $editor);
      $resize.classList.add('custom-resize');
      let currentSize,
        startX,
        resizing = false;
      $resize.addEventListener('mousedown', e => {
        currentSize = $problem.getBoundingClientRect().width;
        startX = e.clientX;
        resizing = true;
        $resize.style.background = '#1a90ff';
      });
      window.addEventListener('mousemove', e => {
        if (!resizing) return;
        const deltaX = e.clientX - startX;
        const newSize = Math.max(450, Math.min(1200, currentSize + deltaX));
        $problem.style.width = `${newSize}px`;
        e.preventDefault();
      });
      window.addEventListener('mouseup', e => {
        if (!resizing) return;
        e.preventDefault();
        resizing = false;
        $resize.style.background = '';
        localStorage.setItem(storageKey, $problem.style.width);
      });
    })();
  }

  function createProblemCard({ title, pburl, difficulty, rate, parentNodeList }) {
    const $a = $('<a>', {
      class: 'group flex flex-col rounded-[8px] duration-300',
      id: Date.now(), // 随便给个唯一id
      target: '_blank',
      href: pburl // 跳转链接
    });

    const $div1 = $('<div>', {
      class: 'flex h-[44px] w-full items-center space-x-3 px-4'
    });

    const $wrapper = $('<div>', {
      style: 'transform: translateX(-3px);'
    });

    // 嵌套的小结构
    const $inner1 = $('<div>', {
      class: 'flex items-center justify-center w-[20px] h-[20px]'
    }).append(
      $('<svg>', {
        xmlns: 'http://www.w3.org/2000/svg',
        viewBox: '0 0 576 512',
        fill: 'currentColor',
        class: 'w-4 h-4 text-yellow-400', // 大小4×4,黄色
        html: `
                    <path d="M287.9 0c9.2 0 17.6 5.2 21.6 13.5l68.6 141.3
                    153.2 22.6c9 1.3 16.5 7.6 19.3 16.3s.5 18.1-5.9 24.5L433.6
                    328.4l26.2 155.6c1.5 9-2.2 18.1-9.6 23.5s-17.3 6-25.3
                    1.7l-137-73.2-137 73.2c-8.1 4.3-17.9 3.7-25.3-1.7s-11.2-14.5-9.7-23.5
                    l26.2-155.6-111-108.2c-6.5-6.4-8.7-15.9-5.9-24.5s10.3-14.9
                    19.3-16.3l153.2-22.6 68.6-141.3C270.4 5.2 278.7 0 287.9 0z"/>
                `
      })
    );

    // 第二块内容
    const $inner2 = $('<div>', {
      class: 'relative flex h-full w-full cursor-pointer items-center'
    }).append(
      $('<div>', { class: 'flex w-0 flex-1 items-center space-x-2' }).append(
        $('<div>', { class: 'text-body text-sd-foreground max-w-[90%] font-medium' }).append(
          $('<div>', { class: 'ellipsis line-clamp-1' }).text(title)
        )
      ),
      $('<div>', {
        class:
          'text-sd-muted-foreground flex w-[70px] items-center justify-center text-sm opacity-0 group-hover:opacity-100 lc-xl:opacity-100',
        'data-state': 'closed'
      }).text(rate),
      $('<p>', { class: 'mx-0 text-[14px] lc-xl:mx-4' }).text(difficulty)
    );

    // 第三个部分 小竖条
    const $inner3 = $('<div>', { 'data-state': 'closed' }).append(
      $('<div>', { class: 'flex gap-0.5 px-1' }).append(
        Array.from({ length: 8 }).map(() =>
          $('<div>', { class: 'h-2 w-0.5 rounded bg-sd-foreground opacity-20' })
        )
      )
    );

    // 收藏
    const $inner4 = $('<div>', {
      class: 'hover:bg-sd-accent flex h-7 w-7 items-center justify-center rounded opacity-0',
      type: 'button',
      'aria-haspopup': 'dialog',
      'aria-expanded': 'false',
      'aria-controls': 'xxx',
      'data-state': 'closed'
    }).append(
      $('<div>', {
        class:
          'relative text-[14px] leading-[normal] p-[1px] before:block before:h-3.5 before:w-3.5 text-sd-muted-foreground',
        html: ''
      })
    );

    $div1.append($inner1, $inner2, $inner3, $inner4);
    $wrapper.append($div1);
    $a.append($wrapper);
    // 插入到第一个父元素的最前面
    if (parentNodeList && parentNodeList.childNodes.length > 0) {
      const firstChild = parentNodeList.childNodes[0];
      if (firstChild) {
        parentNodeList.insertBefore($a[0], firstChild);
      } else {
        parentNodeList.appendChild($a[0]);
      }
    }
  }

  let lcCnt = 0;
  let pbSetCnt = 0;
  function getData() {
    let switchpbRepo = GM_getValue('switchpbRepo');
    let switchTea = GM_getValue('switchTea');
    let switchrealoj = GM_getValue('switchrealoj');
    let switchlevel = GM_getValue('switchlevel');
    let arr = document.querySelector('[class*="pb-[80px]"]');
    let everydatpbidx = 0;
    // pb页面加载时直接返回
    if (arr == null) {
      return;
    }
    observeIfNeeded(arr);
    isSelfChanging = true;
    try {
      if (pbSetCnt && pbSetCnt == arr.childNodes.length) {
        console.log('第' + lcCnt + '次刷新插件...');
        // 到达次数之后删除定时防止卡顿
        if (lcCnt == shortCnt) {
          console.log('到达当前功能指定刷新次数, 检测暂时无更新, 暂停刷新...');
          clearId('all');
        }
        lcCnt += 1;
        return;
      }
      t2rate = JSON.parse(GM_getValue('t2ratedb', '{}').toString());
      // 灵茶题目渲染
      if (switchTea) {
        let first = arr.firstChild;
        if (!first.textContent.includes('灵茶题集')) {
          createProblemCard({
            title: '灵茶题集' + '-' + getCurrentDate(3),
            pburl: teaSheetUrl,
            difficulty: '暂无',
            rate: '暂无',
            parentNodeList: arr
          });
        }
        // 经过灵茶之后,无论如何数量都会变成1
        everydatpbidx = 1;
      }
      if (switchpbRepo) {
        let childs = arr.childNodes;
        let idx = switchTea ? 1 : 0;
        let childLength = childs.length;
        for (; idx < childLength; idx++) {
          let v = childs[idx];
          // 如果元素第一个就不存在或undifined就直接返回
          if (!v) return;
          let t = v.textContent;

          let data = t.split('.');
          let id = data[0].trim();
          let $item = $(v);
          let difficulty = $item.find('.text-sd-medium, .text-sd-easy, .text-sd-hard').first();
          let passRate = difficulty.siblings('div.text-sd-muted-foreground').first();
          // 如果没有难度和通过率属性,则跳过步骤
          if (difficulty.length <= 0 || passRate.length <= 0) continue;
          if (switchrealoj) {
            // 难度修改为隐藏
            if (difficulty.length > 0) {
              difficulty.text('隐藏');
              difficulty.removeClass('text-sd-easy text-sd-medium text-sd-hard');
            }

            // 通过率修改为隐藏
            if (passRate.length > 0) {
              passRate.text('隐藏');
            }
            continue;
          }
          // 因为lc请求是有缓存的,所以多次刷新的时候同一个位置会是不同的题目,这时候需要还原
          if (t2rate[id] != null) {
            let ndScore = t2rate[id]['Rating'];
            difficulty.text(ndScore);
            // 修改尺寸使得数字分数和文字比如(困难)保持在同一行
            passRate.removeClass('w-[70px]');
            passRate.addClass('w-[55px]');
          } else {
            let nd2ch = {
              'mx-0 text-[14px] text-sd-easy lc-xl:mx-4': '简单',
              'mx-0 text-[14px] text-sd-medium lc-xl:mx-4': '中等',
              'mx-0 text-[14px] text-sd-hard lc-xl:mx-4': '困难'
            };
            difficulty.text(nd2ch[difficulty.attr('class')]);
            // 恢复原有大小尺寸
            passRate.removeClass('w-[55px]');
            passRate.addClass('w-[70px]');
          }

          // 增加算术评级插入操作
          if (switchlevel) {
            let level = levelData[id];
            let levelText = level ? '算术评级: ' + level['Level'] : '';
            let $existingLevel = passRate.siblings('.arithmetic-level');
            // 如果已经操作过
            if ($existingLevel.length > 0) {
              // 如果含有算术评级则更新文本,如果没有则删除原来插入的数据
              if (level) {
                $existingLevel.text(levelText);
              } else {
                $existingLevel.remove();
              }
            } else if (level) {
              // 如果没有操作过
              // 如果含有算术评级则插入,如果没有算术评级,则不做任何操作
              // 构造新的算术等级元素(保持结构一致)
              const $level = $('<div></div>')
                .addClass(passRate.attr('class')) // 复用样式
                .addClass('arithmetic-level') // 自定义类作为标记
                .text(levelText);
              // 去除灰色颜色和尺寸限制
              $level
                .removeClass('w-[70px] w-[55px] text-sd-muted-foreground')
                .addClass('min-w-[100px]');
              // 如果插入的为每日一题位置,需要修改尺寸,左移8px
              if (idx == everydatpbidx) {
                $level.css('transform', 'translateX(-8px)');
              }
              // 插入到通过率前面
              passRate.before($level);
            }
          }
        }
        console.log('has refreshed problemlist...');
      }
      pbSetCnt = arr.childNodes.length;
    } finally {
      isSelfChanging = false;
    }
  }

  // pblist插件刷新次数
  let pbListCnt = 0;
  // pblist当前刷新之后列表所含题目数量
  let pbListpbCnt = 0;
  function getPblistData() {
    if (!GM_getValue('switchpblist')) return;
    let switchrealoj = GM_getValue('switchrealoj');
    let switchlevel = GM_getValue('switchlevel');
    let switchpblistRateDisplay = GM_getValue('switchpblistRateDisplay');
    let pre = document.querySelector('.w-full .pb-20');
    let arr = pre?.childNodes[0]?.lastChild?.childNodes[0];
    if (!arr) return;
    // 设置监听官方渲染,并标记当前自己修改不被监听
    observeIfNeeded(arr);
    isSelfChanging = true;
    try {
      // console.log(arr)
      // console.log(pbListpbCnt)
      // console.log(arr.childNodes.length)
      if (pbListpbCnt && pbListpbCnt == arr.childNodes.length) {
        console.log('第' + pbListCnt + '次刷新插件...');
        // 到达次数之后删除定时防止卡顿
        if (pbListCnt == shortCnt) {
          console.log('到达当前功能指定刷新次数, 检测暂时无更新, 暂停刷新...');
          console.log('清理标记');
          clearId('pblist');
        }
        pbListCnt += 1;
        return;
      }
      t2rate = JSON.parse(GM_getValue('t2ratedb', '{}').toString());
      let childs = arr.childNodes;
      let childLength = childs.length;
      for (let idx = 0; idx < childLength; idx++) {
        let v = childs[idx];
        if (!v) return;
        let t = v.textContent;
        let data = t.split('.');
        let id = data[0].trim();
        // console.log(id)
        // 如果不是a标签,说明是自定义题单,需要多进一层
        let $item = $(v);
        let difficulty = $item.find('.text-sd-medium, .text-sd-easy, .text-sd-hard').first();
        let passRate = difficulty.siblings('div.text-sd-muted-foreground').first();
        if (switchpblistRateDisplay) passRate.removeClass('opacity-0').addClass('opacity-100');
        // 如果没有难度属性,则跳过步骤
        if (difficulty.length <= 0 || passRate.length <= 0) continue;
        if (switchrealoj) {
          // 难度修改为隐藏
          if (difficulty.length > 0) {
            difficulty.text('隐藏');
            difficulty.removeClass('text-sd-easy text-sd-medium text-sd-hard');
          }

          // 通过率修改为隐藏
          if (passRate.length > 0) {
            passRate.text('隐藏');
          }
          continue;
        }

        // 插入竞赛分数
        if (t2rate[id] != null) {
          let ndScore = t2rate[id]['Rating'];
          difficulty.text(ndScore);
          // 修改尺寸使得数字分数和文字比如(困难)保持在同一行
          passRate.removeClass('w-[70px]');
          passRate.addClass('w-[55px]');
        } else {
          let nd2ch = {
            'mx-0 text-[14px] text-sd-easy lc-xl:mx-4': '简单',
            'mx-0 text-[14px] text-sd-medium lc-xl:mx-4': '中等',
            'mx-0 text-[14px] text-sd-hard lc-xl:mx-4': '困难'
          };
          difficulty.text(nd2ch[difficulty.attr('class')]);
          // 恢复原有大小尺寸
          passRate.removeClass('w-[55px]');
          passRate.addClass('w-[70px]');
        }

        // 增加算术评级插入操作
        if (switchlevel) {
          let level = levelData[id];
          let levelText = level ? '算术评级: ' + level['Level'] : '';
          let $existingLevel = passRate.siblings('.arithmetic-level');
          // 如果已经操作过
          if ($existingLevel.length > 0) {
            // 如果含有算术评级则更新文本,如果没有则删除原来插入的数据
            if (level) {
              $existingLevel.text(levelText);
            } else {
              $existingLevel.remove();
            }
          } else if (level) {
            // 如果没有操作过
            // 如果含有算术评级则插入,如果没有算术评级,则不做任何操作
            // 构造新的算术等级元素(保持结构一致)
            const $level = $('<div></div>')
              .addClass(passRate.attr('class')) // 复用样式
              .addClass('arithmetic-level') // 自定义类作为标记
              .text(levelText);
            // 去除灰色颜色和尺寸限制
            $level
              .removeClass('opacity-0 w-[70px] w-[55px] text-sd-muted-foreground')
              .addClass('min-w-[100px] opacity-100');
            // 插入到通过率前面
            passRate.before($level);
          }
        }
      }
      console.log('has refreshed...');
      pbListpbCnt = arr.childNodes.length;
    } finally {
      isSelfChanging = false;
    }
  }

  function getSearch() {
    if (!GM_getValue('switchsearch')) return;
    let arr = $("div[role='table']");
    if (arr.length == 0) return;
    arr = arr[0].childNodes[1];

    let head = document.querySelector("div[role='row']");
    if (!head) rerurn;
    // 确认难度序列
    let rateRefresh = false;
    let headndidx;
    for (let i = 0; i < head.childNodes.length; i++) {
      let headEle = head.childNodes[i];
      if (headEle.textContent.includes('难度')) {
        headndidx = i;
      }
      if (headEle.textContent.includes('题目评分')) {
        rateRefresh = true;
      }
    }
    if (!arr) return;
    let childs = arr.childNodes;
    for (const element of childs) {
      let v = element;
      if (!v.childNodes[1]) return;
      let t = v.childNodes[1].textContent;
      let data = t.split('.');
      let id = data[0].trim();
      let nd = v.childNodes[headndidx].childNodes[0].innerHTML;
      if (t2rate[id] != null && !rateRefresh) {
        nd = t2rate[id]['Rating'];
        v.childNodes[headndidx].childNodes[0].innerHTML = nd;
      } else {
        let nd2ch = { 'text-green-s': '简单', 'text-yellow': '中等', 'text-red-s': '困难' };
        let clr = v.childNodes[headndidx].childNodes[0].getAttribute('class');
        v.childNodes[headndidx].childNodes[0].innerHTML = nd2ch[clr];
      }
    }
  }

  /**
   * 渲染 rating
   * @param {HTMLElement} nd 要操作的节点
   * @param {string | undefined} ndRate rating
   * @param {Record<string, string>} lightn2c 亮模式难度列表
   * @param {Record<string, string>} darkn2c 暗模式难度列表
   * @returns {boolean} 是否命中
   */
  function renderRating(nd, ndRate, lightn2c, darkn2c) {
    if (ndRate) {
      nd.textContent = ndRate;
      return true;
    }

    let clr = nd.classList;
    if (clr.length === 0) return false;

    for (const [className, text] of Object.entries({ ...lightn2c, ...darkn2c })) {
      if (clr.contains(className)) {
        nd.innerText = text;
        return true;
      }
    }

    return false;
  }

  /**
   * 渲染 level
   * @param {HTMLElement} nd 要操作的节点
   * @param {string | undefined} level 评级
   * @param {DOMTokenList} cls class 列表
   * @param {boolean} hit 是否命中
   * @param {number} padding 单位: px, 默认80
   */
  function renderLevel(nd, level, cls, hit, padding = 80) {
    if (level && GM_getValue('switchlevel')) {
      let text = document.createElement('span');
      text.classList.add(...cls);
      text.innerHTML = '算术评级: ' + level;
      text.style = nd.getAttribute('style');
      text.style.paddingRight = `${hit ? padding - 5 : padding}px`; // 命中之后宽度不一样
      nd.parentNode.insertBefore(text, nd);
    }
  }

  /**
   * 修正侧边栏高亮题目的样式
   * @param {HTMLElement} listNode 侧边栏列表节点
   * @param {string} cssSelector 子节点选择器
   */
  function fixSiderbarProblemHighlight(listNode, cssSelector) {
    // console.log("修正侧边栏高亮题目样式");
    const pbList = listNode.querySelectorAll(cssSelector);

    pbList.forEach(div => {
      const levelSpan = div.querySelector(':scope > span');
      const pbDiv = div.querySelector(':scope > div > div');
      if (!levelSpan) return;

      if (pbDiv.className !== levelSpan.className) {
        // 如果className不一致,说明是高亮状态不一致
        levelSpan.className = pbDiv.className;
      }
    });
  }

  // 确认之后不再刷新
  let studyf;
  let studyCnt = 0;
  function getStudyData(css_selector) {
    if (!GM_getValue('switchstudy')) return;
    levelData = JSON.parse(GM_getValue('levelData', '{}').toString());
    let totArr = null;
    // 如果传入的是已经找到的node元素, 就不再搜索
    if (css_selector instanceof Element) {
      totArr = css_selector;
    } else {
      totArr = document.querySelector(css_selector);
    }
    if (totArr == null) return;
    let first = totArr.firstChild?.childNodes[1]?.textContent;
    if (studyf && first && studyf == first) {
      // 到达次数之后删除定时防止卡顿
      if (studyCnt == shortCnt) {
        clearId('study');
      }
      studyCnt += 1;
      return;
    }
    let childs = totArr.childNodes;
    for (const arr of childs) {
      for (let pbidx = 1; pbidx < arr.childNodes.length; pbidx++) {
        let pb = arr.childNodes[pbidx];
        let pbNameLabel = pb.querySelector('.truncate');
        if (pbNameLabel == null) continue;
        let pbName = pbNameLabel.textContent;
        let nd = pb.childNodes[0].childNodes[1].childNodes[1];
        let pbhtml = pb?.childNodes[0]?.childNodes[1]?.childNodes[0]?.childNodes[0];
        pbName = pbName.trim();

        // 保证 nd 存在
        if (nd == null || nd.classList.length === 0) {
          // console.log(nd)
          continue;
        }

        let levelId = getLevelId(pbName);
        let id = getPbNameId(pbName);
        // console.log(pbName, level)

        let darkn2c = {
          'text-lc-green-60': '简单',
          'text-lc-yellow-60': '中等',
          'text-lc-red-60': '困难'
        };
        let lightn2c = {
          'text-lc-green-60': '简单',
          'text-lc-yellow-60': '中等',
          'text-lc-red-60': '困难'
        };

        // render rating
        let hit = renderRating(nd, t2rate?.[id]?.Rating, lightn2c, darkn2c);

        // render level
        renderLevel(nd, levelData[levelId]?.Level?.toString(), pbhtml.classList, hit, 130);
      }
    }
    if (totArr.firstChild?.childNodes[1]) studyf = totArr.firstChild?.childNodes[1]?.textContent;
    console.log('has refreshed...');
  }

  let pbsidef;
  let pbsidee;
  function getpbside(css_selector) {
    let totArr = null;
    // 如果传入的是已经找到的node元素, 就不再搜索
    if (css_selector instanceof Element) {
      totArr = css_selector;
    } else {
      totArr = document.querySelector(css_selector);
    }
    if (totArr == null) return;
    if (totArr.firstChild == null) return;
    let first = totArr.firstChild?.childNodes[0]?.textContent;
    let last = totArr.lastChild?.childNodes[0]?.textContent;
    if (first && pbsidef && pbsidef == first && last && pbsidee && pbsidee == last) {
      if (pbsideCnt == normalCnt) clearId('pbside');

      // TODO: 没想到什么好的办法来确切的监听源站前端对题目列表的更新,只能大概等一个延时
      if (pbsideCnt === 1) {
        // 在此处检查高亮状态是否改变,并修正
        fixSiderbarProblemHighlight(totArr, ':scope > div > div[id] > div > :nth-child(2)');
      }

      pbsideCnt += 1;
      return;
    }
    let childs = totArr.childNodes;
    for (const arr of childs) {
      // 特殊判定, 如果大于30则是每日一题列表
      let pbidx = 1;
      if (arr.childNodes.length >= 30) pbidx = 0;
      for (; pbidx < arr.childNodes.length; pbidx++) {
        let pb = arr.childNodes[pbidx];
        let pbName = pb.childNodes[0].childNodes[1].childNodes[0].textContent;
        let nd = pb.childNodes[0].childNodes[1].childNodes[1];
        let pbhtml = pb?.childNodes[0]?.childNodes[1]?.childNodes[0]?.childNodes[0];

        // 保证 nd 存在
        if (nd == null || nd.classList.length === 0) {
          // console.log(nd)
          continue;
        }

        // console.log(pbName)
        let data = pbName.split('.');
        let id = data[0];

        let darkn2c = {
          'text-lc-green-60': '简单',
          'text-lc-yellow-60': '中等',
          'text-lc-red-60': '困难'
        };
        let lightn2c = {
          'text-lc-green-60': '简单',
          'text-lc-yellow-60': '中等',
          'text-lc-red-60': '困难'
        };

        // render rating
        let hit = renderRating(nd, t2rate?.[id]?.Rating, lightn2c, darkn2c);

        // render level
        renderLevel(nd, levelData[id]?.Level?.toString(), pbhtml.classList, hit);
      }
    }
    if (totArr.firstChild?.childNodes[0]) pbsidef = totArr.firstChild.childNodes[0].textContent;
    if (totArr.lastChild?.childNodes[0]) pbsidee = totArr.lastChild.childNodes[0].textContent;
    // console.log(pbsidef, pbsidee)
    console.log('已经刷新侧边栏envType分数...');
  }

  let pbsideCnt = 0;
  function getpbsideData() {
    // 左侧栏分数显示
    let searchParams = location.search;
    levelData = JSON.parse(GM_getValue('levelData', '{}').toString());
    // ?envType=study-plan-v2&envId=leetcode-75
    // 类似学习计划的展开栏
    if (
      searchParams.includes('envType') &&
      !searchParams.includes('daily-question') &&
      !searchParams.includes('problem-list')
    ) {
      let overflow = document.querySelector('.overflow-auto.p-5');
      if (overflow == null) return;
      let studyplan = overflow.childNodes[0].childNodes[1];
      if (!studyplan) studyf = null;
      if (GM_getValue('switchstudy') && studyplan) {
        getpbside(studyplan);
      }
    } else {
      // 普通展开栏
      let overflow = document.querySelector('.overflow-auto.p-4');
      if (overflow == null) return;
      let pbarr = overflow?.childNodes[0]?.childNodes[1];
      if (pbarr == null) return;
      if (pbarr.firstChild == null) return;
      if (pbarr.lastChild == null) return;
      if (pbsidef == pbarr.firstChild?.textContent && pbsidee == pbarr.lastChild?.textContent) {
        if (pbsideCnt == normalCnt) clearId('pbside');

        // TODO: 没想到什么好的办法来确切的监听源站前端对题目列表的更新,只能大概等一个延时
        // 根据列表的大小不同,更新耗时可能不同,故直接对快慢两种情况运行两次修正
        if (pbsideCnt === 4 || pbsideCnt === 1) {
          // 在此处检查高亮状态是否改变,并修正
          fixSiderbarProblemHighlight(pbarr, ':scope > .group > :first-child > :nth-child(2)');
        }

        pbsideCnt += 1;
        return;
      }
      if (pbarr != null) {
        for (const onepb of pbarr.childNodes) {
          let tp = onepb.childNodes[0]?.childNodes[1];
          if (!tp) {
            // console.log(tp)
            continue;
          }
          let pbName = tp.childNodes[0]?.textContent;
          if (pbName == null) {
            continue;
            // pbName = tp.childNodes[0]?.textContent
            // console.log(pbName)
          }
          let nd = tp.childNodes[1];
          let pbhtml = tp.childNodes[0]?.childNodes[0];

          // 保证 nd 存在
          if (nd == null || nd.classList.length === 0) {
            // console.log(nd)
            continue;
          }
          // 如果为算术,说明当前已被替换过
          if (nd.textContent.includes('算术')) continue;

          // console.log(pbName)
          let data = pbName.split('.');
          let id = data[0];

          let darkn2c = {
            'text-sd-easy': '简单',
            'text-sd-medium': '中等',
            'text-sd-hard': '困难'
          };
          let lightn2c = {
            'text-sd-easy': '简单',
            'text-sd-medium': '中等',
            'text-sd-hard': '困难'
          };

          // render rating
          let hit = renderRating(nd, t2rate?.[id]?.Rating, lightn2c, darkn2c);

          // render level
          renderLevel(nd, levelData[id]?.Level?.toString(), pbhtml.classList, hit);
        }
        pbsidef = pbarr.firstChild.textContent;
        pbsidee = pbarr.lastChild.textContent;
        // console.log(pbsidef, pbsidee)
        console.log('已经刷新侧边栏题库分数...');
      }
    }
  }

  function createSearchBtn() {
    if (!GM_getValue('switchpbsearch')) return;
    if (document.querySelector('#id-dropdown') == null) {
      // 做个搜索框
      let div = document.createElement('div');
      div.setAttribute('class', 'layui-inline');
      // 适配黑色主题
      div.classList.add('leetcodeRating-search');
      div.innerHTML += `<input name="" placeholder="请输入题号或关键字" class="lcr layui-input" id="id-dropdown">`;
      let center = document.querySelector('.flex.justify-between');
      center = center?.childNodes[0]?.childNodes[0]?.childNodes[0];
      if (center == null) return;
      if (center.childNodes.length > 0) center.insertBefore(div, center.childNodes[1]);
      else center.appendChild(div);
      layui.use(function () {
        let dropdown = layui.dropdown;
        let $ = layui.$;
        let inst = dropdown.render({
          elem: '#id-dropdown',
          data: [],
          click: function (obj) {
            this.elem.val(obj.title);
            this.elem.attr('data-id', obj.id);
          }
        });
        let elemInput = $(inst.config.elem);
        let lastQueryTime = '';
        let timer;
        elemInput.on('input propertychange', function (event) {
          clearTimeout(timer);
          timer = setTimeout(function () {
            let currentTime = Date.now();
            if (currentTime - lastQueryTime >= 800) {
              let elem = $(inst.config.elem);
              let value = elem.val().trim();
              elem.removeAttr('data-id');
              let dataNew = findData(value);
              dropdown.reloadData(inst.config.id, {
                data: dataNew
              });
              lastQueryTime = currentTime;
            }
          }, 800);
        });

        $(inst.config.elem).on('blur', function () {
          let elem = $(this);
          let dataId = elem.attr('data-id');
          if (!dataId) {
            elem.val('');
          }
        });
        function findData(value) {
          return getsearch(value);
        }
        function getsearch(search) {
          let queryT = `
                        query problemsetQuestions($in: ProblemsetQuestionsInput!) {
                            problemsetQuestions(in: $in) {
                            hasMore
                            questions {
                                titleCn
                                titleSlug
                                title
                                frontendId
                                acRate
                                solutionNum
                                difficulty
                                userQuestionStatus
                            }
                            }
                        }
                    `;
          let list = {
            query: queryT,
            operationName: 'problemsetQuestions',
            variables: { in: { query: search, limit: 10, offset: 0 } }
          };
          let resLst = [];
          $.ajax({
            type: 'POST',
            url: lcnojgo,
            data: JSON.stringify(list),
            success: function (res) {
              let data = res.data.problemsetQuestions.questions;
              for (let idx = 0; idx < data.length; idx++) {
                let resp = data[idx];
                let item = {};
                item.id = idx;
                item.title = resp.frontendId + '.' + resp.titleCn;
                item.href = 'https://leetcode.cn/problems/' + resp.titleSlug;
                item.target = '_self';
                resLst.push(item);
              }
            },
            async: false,
            xhrFields: { withCredentials: true },
            contentType: 'application/json;charset=UTF-8'
          });
          return resLst;
        }
      });
    }
  }

  // 因为字符显示问题,暂时去除
  // <span class="layui-progress-text myfont">0%</span>
  let pbstatusContent = `
        <div style="text-align: center;">
            <strong class="myfont"> 希望有大佬可以美化这丑丑的界面~ =v= <strong>
            <p style="padding-top: 10px;"></p>
            <div class="layui-progress layui-progress-big" lay-showpercent="true" lay-filter="demo-filter-progress">
                <div class="layui-progress-bar" lay-percent="0%">
                </div>
            </div>
            <p style="padding-top: 20px;"></p>
            <div class="layui-btn-container" style="">
                <button id="statusasyc" class="layui-btn layui-btn-radius" lay-on="loading">同步所有问题状态按钮</button>
            </div>
        </div>
        `;
  let levelContent = `
        1      无算法要求
        2      知道常用数据结构和算法并简单使用
        3      理解常用数据结构和算法
        4      掌握常用数据结构和算法
        5      熟练掌握常用数据结构和算法,初步了解高级数据结构
        6      深入理解并灵活应用数据结构和算法,理解高级数据结构
        7      结合多方面的数据结构和算法,处理较复杂问题
        8      掌握不同的数据结构与算法之间的关联性,处理复杂问题,掌握高级数据结构
        9      处理复杂问题,对时间复杂度的要求更严格
        10     非常复杂的问题,非常高深的数据结构和算法(例如线段树、树状数组)
        11     竞赛内容,知识点超出面试范围
        `;
  async function layuiload() {
    // 使用layui的渲染
    layui.use(function () {
      let element = layui.element;
      let util = layui.util;
      let pbstatus = JSON.parse(GM_getValue('pbstatus', '{}').toString());
      // 普通事件
      util.on('lay-on', {
        // loading
        loading: function (othis) {
          let DISABLED = 'layui-btn-disabled';
          if (othis.hasClass(DISABLED)) return;
          othis.addClass(DISABLED);
          let cnt = Math.trunc((getpbCnt() + 99) / 100);
          let headers = {
            'Content-Type': 'application/json'
          };
          let skip = 0;
          let timer = setInterval(
            async function () {
              ajaxReq('POST', lcgraphql, headers, allPbPostData(skip, 100), res => {
                let questions = res.data.problemsetQuestionList.questions;
                for (let pb of questions) {
                  pbstatus[pb.titleSlug] = {
                    titleSlug: pb.titleSlug,
                    id: pb.frontendQuestionId,
                    status: pb.status,
                    title: pb.title,
                    titleCn: pb.titleCn,
                    difficulty: pb.difficulty,
                    paidOnly: pb.paidOnly
                  };
                }
              });
              skip += 100;
              // skip / 100 是当前已经进行的次数
              let showval = Math.trunc((skip / 100 / cnt) * 100);
              if (skip / 100 >= cnt) {
                showval = 100;
                clearInterval(timer);
              }
              element.progress('demo-filter-progress', showval + '%');
              if (showval == 100) {
                pbstatus[pbstatusVersion] = {};
                GM_setValue('pbstatus', JSON.stringify(pbstatus));
                console.log('同步所有题目状态完成...');
                await sleep(1000);
                layer.msg('同步所有题目状态完成!');
                await sleep(1000);
                layer.closeAll();
              }
            },
            300 + Math.random() * 1000
          );
        }
      });
    });
  }
  let t1; // pb
  let pbCnt = 0;
  let pbCnt2 = 0;
  function getpb() {
    let switchrealoj = GM_getValue('switchrealoj');
    // 搜索功能
    if (GM_getValue('switchpbsearch')) createSearchBtn();
    // 题目页面
    let curUrl = location.href;
    // 只有描述页才进行加载
    let isDescript =
      !curUrl.match(regDiss) && !curUrl.match(regSovle) && !curUrl.match(regPbSubmission);
    // 如果持续10次都不在描述页面, 则关闭pb定时
    if (!isDescript) {
      // 非des清除定时
      if (pbCnt == shortCnt) clearId('pb');
      pbCnt += 1;
      return;
    }
    // 流动布局逻辑
    if (isDynamic) {
      // pb其他页面时刷新多次后也直接关闭
      let t = document.querySelector('.text-title-large');
      if (t == null) {
        t1 = 'unknown';
        pbCnt = 0;
        if (pbCnt2 == shortCnt) clearId('pb');
        pbCnt2 += 1;
        return;
      }

      // console.log(t1, t.textContent)
      if (t1 != null && t1 == t.textContent) {
        // des清除定时
        if (pbCnt == shortCnt) clearId('pb');
        pbCnt += 1;
        return;
      }
      let data = t.textContent.split('.');
      let id = data[0].trim();
      let colorA = ['.text-difficulty-hard', '.text-difficulty-easy', '.text-difficulty-medium'];
      let colorSpan;
      for (const color of colorA) {
        colorSpan = document.querySelector(color);
        if (colorSpan) break;
      }
      if (!colorSpan) {
        if (switchrealoj) return;
        console.log('color ele not found');
        return;
      }

      // 统计难度分数并且修改
      let nd = colorSpan.getAttribute('class');
      let nd2ch = {
        'text-difficulty-easy': '简单',
        'text-difficulty-medium': '中等',
        'text-difficulty-hard': '困难'
      };
      if (switchrealoj || (t2rate[id] != null && GM_getValue('switchpbscore'))) {
        if (switchrealoj) colorSpan.remove();
        else if (t2rate[id] != null) colorSpan.innerHTML = t2rate[id]['Rating'];
      } else {
        for (let item in nd2ch) {
          if (nd.toString().includes(item)) {
            colorSpan.innerHTML = nd2ch[item];
            break;
          }
        }
      }

      // 逻辑,准备做周赛链接,如果已经不存在组件就执行操作
      let url = chContestUrl;
      let zhUrl = zhContestUrl;
      let tips = colorSpan?.parentNode;
      if (tips == null) return;
      let tipsPa = tips?.parentNode;
      // tips 一栏的父亲节点第一子元素的位置, 插入后变成竞赛信息位置
      let tipsChildone = tipsPa.childNodes[1];
      // 题目内容, 插入后变成原tips栏目
      let pbDescription = tipsPa.childNodes[2];
      if (pbDescription?.childNodes[0]?.getAttribute('data-track-load') != null) {
        let divTips = document.createElement('div');
        divTips.setAttribute('class', 'flex gap-1');
        let abody = document.createElement('a');
        abody.setAttribute('data-small-spacing', 'true');
        abody.setAttribute('class', 'css-nabodd-Button e167268t1 hover:text-blue-s');
        let abody2 = document.createElement('a');
        abody2.setAttribute('data-small-spacing', 'true');
        abody2.setAttribute('class', 'css-nabodd-Button e167268t1 hover:text-blue-s');

        let abody3 = document.createElement('a');
        abody3.setAttribute('data-small-spacing', 'true');
        abody3.setAttribute('class', 'css-nabodd-Button e167268t1 hover:text-blue-s');

        let abody4 = document.createElement('p');
        abody4.setAttribute('data-small-spacing', 'true');
        abody4.setAttribute('class', 'css-nabodd-Button e167268t1 hover:text-blue-s');

        let span = document.createElement('span');
        let span2 = document.createElement('span');
        let span3 = document.createElement('span');
        let span4 = document.createElement('span');
        // 判断同步按钮
        if (GM_getValue('switchpbstatusBtn')) {
          // console.log(levelData[id])
          span4.innerHTML = `<i style="font-size:12px" class="layui-icon layui-icon-refresh"></i>&nbsp;同步题目状态`;
          span4.onclick = function (e) {
            layer.open({
              type: 1,
              content: `${pbstatusContent}`,
              title: '同步所有题目状态',
              area: ['550px', '250px'],
              shade: 0.6
            });
          };
          span4.setAttribute('style', 'cursor:pointer;');
          // 使用layui的渲染
          layuiload();
          abody4.removeAttribute('hidden');
        } else {
          span4.innerText = '未知按钮';
          abody4.setAttribute('hidden', 'true');
        }
        abody4.setAttribute('style', 'padding-left: 10px;');

        levelData = JSON.parse(GM_getValue('levelData', '{}').toString());
        if (levelData[id] != null) {
          // console.log(levelData[id])
          let des = '算术评级: ' + levelData[id]['Level'].toString();
          span3.innerText = des;
          span3.onclick = function (e) {
            e.preventDefault();
            layer.open({
              type: 1, // Page 层类型
              area: ['700px', '450px'],
              title: '算术评级说明',
              shade: 0.6, // 遮罩透明度
              maxmin: true, // 允许全屏最小化
              anim: 5, // 0-6的动画形式,-1不开启
              content: `<p class="containerlingtea" style="padding:10px;color:#000;">${levelContent}</p>`
            });
          };
          abody3.removeAttribute('hidden');
        } else {
          span3.innerText = '未知评级';
          abody3.setAttribute('hidden', 'true');
        }
        abody3.setAttribute('href', '/xxx');
        abody3.setAttribute('style', 'padding-right: 10px;');
        abody3.setAttribute('target', '_blank');

        if (t2rate[id] != null) {
          let contestUrl;
          let num = getcontestNumber(t2rate[id]['ContestSlug']);
          if (num < 83) {
            contestUrl = zhUrl;
          } else {
            contestUrl = url;
          }
          span.innerText = t2rate[id]['ContestID_zh'];
          span2.innerText = t2rate[id]['ProblemIndex'];
          abody.setAttribute('href', contestUrl + t2rate[id]['ContestSlug']);
          abody.setAttribute('target', '_blank');
          abody.removeAttribute('hidden');
          abody2.setAttribute(
            'href',
            contestUrl + t2rate[id]['ContestSlug'] + '/problems/' + t2rate[id]['TitleSlug']
          );
          abody2.setAttribute('target', '_blank');
          if (switchrealoj) abody2.setAttribute('hidden', true);
          else abody2.removeAttribute('hidden');
        } else {
          span.innerText = '对应周赛未知';
          abody.setAttribute('href', '/xxx');
          abody.setAttribute('target', '_self');
          abody.setAttribute('hidden', 'true');
          span2.innerText = '未知';
          abody2.setAttribute('href', '/xxx');
          abody2.setAttribute('target', '_self');
          abody2.setAttribute('hidden', 'true');
        }
        abody.setAttribute('style', 'padding-right: 10px;');
        // abody2.setAttribute("style", "padding-top: 1.5px;")
        abody.appendChild(span);
        abody2.appendChild(span2);
        abody3.appendChild(span3);
        abody4.appendChild(span4);
        divTips.appendChild(abody3);
        divTips.appendChild(abody);
        divTips.appendChild(abody2);
        divTips.appendChild(abody4);
        tipsPa.insertBefore(divTips, tips);
      } else if (
        tipsChildone.childNodes != null &&
        tipsChildone.childNodes.length >= 2 &&
        (tipsChildone.childNodes[2].textContent.includes('Q') ||
          tipsChildone.childNodes[2].textContent.includes('未知'))
      ) {
        let pa = tipsChildone;
        let le = pa.childNodes.length;

        // 判断同步按钮
        if (GM_getValue('switchpbstatusBtn')) {
          // 使用layui的渲染, 前面已经添加渲染按钮,所以这里不用重新添加
          pa.childNodes[le - 1].removeAttribute('hidden');
        } else {
          pa.childNodes[le - 1].childNodes[0].innerText = '未知按钮';
          pa.childNodes[le - 1].setAttribute('hidden', 'true');
        }

        // 存在就直接替换
        let levelData = JSON.parse(GM_getValue('levelData', '{}').toString());
        if (levelData[id] != null) {
          let des = '算术评级: ' + levelData[id]['Level'].toString();
          pa.childNodes[le - 4].childNodes[0].innerText = des;
          pa.childNodes[le - 4].childNodes[0].onclick = function (e) {
            e.preventDefault();
            layer.open({
              type: 1, // Page 层类型
              area: ['700px', '450px'],
              title: '算术评级说明',
              shade: 0.6, // 遮罩透明度
              maxmin: true, // 允许全屏最小化
              anim: 5, // 0-6的动画形式,-1不开启
              content: `<p class="containerlingtea" style="padding:10px;color:#000;">${levelContent}</p>`
            });
          };
          pa.childNodes[le - 4].removeAttribute('hidden');
        } else {
          pa.childNodes[le - 4].childNodes[0].innerText = '未知评级';
          pa.childNodes[le - 4].setAttribute('hidden', 'true');
          pa.childNodes[le - 4].setAttribute('href', '/xxx');
        }
        // ContestID_zh  ContestSlug
        if (t2rate[id] != null) {
          let contestUrl;
          let num = getcontestNumber(t2rate[id]['ContestSlug']);
          if (num < 83) {
            contestUrl = zhUrl;
          } else {
            contestUrl = url;
          }
          pa.childNodes[le - 3].childNodes[0].innerText = t2rate[id]['ContestID_zh'];
          pa.childNodes[le - 3].setAttribute('href', contestUrl + t2rate[id]['ContestSlug']);
          pa.childNodes[le - 3].setAttribute('target', '_blank');
          pa.childNodes[le - 3].removeAttribute('hidden');

          pa.childNodes[le - 2].childNodes[0].innerText = t2rate[id]['ProblemIndex'];
          pa.childNodes[le - 2].setAttribute(
            'href',
            contestUrl + t2rate[id]['ContestSlug'] + '/problems/' + t2rate[id]['TitleSlug']
          );
          pa.childNodes[le - 2].setAttribute('target', '_blank');
          if (switchrealoj) pa.childNodes[le - 2].setAttribute('hidden', 'true');
          else pa.childNodes[le - 2].removeAttribute('hidden');
        } else {
          pa.childNodes[le - 3].childNodes[0].innerText = '对应周赛未知';
          // 不填写的话默认为当前url
          pa.childNodes[le - 3].setAttribute('href', '/xxx');
          pa.childNodes[le - 3].setAttribute('target', '_self');
          pa.childNodes[le - 3].setAttribute('hidden', 'true');

          pa.childNodes[le - 2].childNodes[0].innerText = '未知';
          pa.childNodes[le - 2].setAttribute('href', '/xxx');
          pa.childNodes[le - 2].setAttribute('target', '_self');
          pa.childNodes[le - 2].setAttribute('hidden', 'true');
        }
      }
      t1 = t.textContent;
    }
  }

  function clearId(name) {
    // 'all', 'tag', 'pb', 'company', 'pblist', 'search', 'study'
    let tmp = GM_getValue(name, -1);
    clearInterval(tmp);
    console.log('clear ' + name + ' ' + id + ' success');
  }

  let shortCnt = 3;
  let normalCnt = 5;
  function initCnt() {
    // 卡顿问题页面修复
    // 搜索页面为自下拉,所以需要无限刷新,无法更改,这一点不会造成卡顿,所以剔除计划
    // 题库页 ✅
    lcCnt = 0;
    pbSetCnt = 0;

    // 题目页
    pbCnt = 0; // ✅
    pbCnt2 = 0; // ✅

    // 题单页  ✅
    pbsideCnt = 0;
    pbListpbCnt = 0;
    pbListCnt = 0; // ✅

    studyCnt = 0; // ✅
  }

  function clearAndStart(url, timeout, isAddEvent) {
    initCnt();
    let start = '';
    let targetIdx = -1;
    let pageLst = ['all', 'pb', 'pblist', 'search', 'study'];
    let urlLst = [allUrl, pbUrl, pblistUrl, searchUrl, studyUrl];
    let funcLst = [getData, getpb, getPblistData, getSearch, getStudyData];
    for (let index = 0; index < urlLst.length; index++) {
      const element = urlLst[index];
      if (url.match(element)) {
        targetIdx = index;
      } else if (!url.match(element)) {
        // 清理其他的
        let tmp = GM_getValue(pageLst[index], -1);
        clearInterval(tmp);
      }
    }
    if (targetIdx != -1) start = pageLst[targetIdx];
    if (start != '') {
      // 清理重复运行
      let preId = GM_getValue(start);
      if (preId != null) {
        clearInterval(preId);
      }
      let css_selector = 'div.relative.flex.w-full.flex-col > .flex.w-full.flex-col.gap-4';
      if (start == 'study') {
        id = setInterval(getStudyData, timeout, css_selector);
      } else if (start == 'pb') {
        id = setInterval(getpb, timeout);
        if (GM_getValue('switchpbside')) {
          let pbsideId = setInterval(getpbsideData, timeout);
          GM_setValue('pbside', pbsideId);
        }
      } else {
        id = setInterval(funcLst[targetIdx], timeout);
      }
      GM_setValue(start, id);
    }
    if (isAddEvent) {
      // 只需要定位urlchange变更
      window.addEventListener('urlchange', () => {
        console.log('urlchange/event/happened');
        let newUrl = location.href;
        clearAndStart(newUrl, 1000, false);
      });
    }
  }

  // 获取界面所需数据, 需要在菜单页面刷新前进行更新
  function getNeedData() {
    // 更新分数数据
    async function getScore() {
      let now = getCurrentDate(1);
      preDate = GM_getValue('preDate', '');
      if (t2rate['tagVersion9'] == null || preDate == '' || preDate != now) {
        // 每天重置为空
        GM_setValue('pbSubmissionInfo', '{}');
        let res = await new Promise((resolve, reject) => {
          GM_xmlhttpRequest({
            method: 'get',
            url: rakingUrl + '?timeStamp=' + new Date().getTime(),
            headers: {
              'Content-Type': 'application/x-www-form-urlencoded'
            },
            onload: function (res) {
              resolve(res);
            },
            onerror: function (err) {
              console.log('error');
              console.log(err);
            }
          });
        });
        if (res.status === 200) {
          // 保留唯一标识
          t2rate = {};
          pbName2Id = {};
          pbNamee2Id = {};
          let dataStr = res.response;
          let json = eval(dataStr);
          for (const element of json) {
            t2rate[element.ID] = element;
            t2rate[element.ID]['Rating'] = Number.parseInt(
              Number.parseFloat(element['Rating']) + 0.5
            );
            pbName2Id[element.TitleZH] = element.ID;
            pbNamee2Id[element.Title] = element.ID;
          }
          t2rate['tagVersion9'] = {};
          console.log('everyday getdata once...');
          preDate = now;
          GM_setValue('preDate', preDate);
          GM_setValue('t2ratedb', JSON.stringify(t2rate));
          GM_setValue('pbName2Id', JSON.stringify(pbName2Id));
          GM_setValue('pbNamee2Id', JSON.stringify(pbNamee2Id));
        }
      }
    }
    getScore();

    // 更新level数据
    async function getPromiseLevel() {
      let week = new Date().getDay();
      if (levelData['tagVersion24'] == null || week == 1) {
        let res = await new Promise((resolve, reject) => {
          GM_xmlhttpRequest({
            method: 'get',
            url: levelUrl + '?timeStamp=' + new Date().getTime(),
            headers: {
              'Content-Type': 'application/x-www-form-urlencoded'
            },
            onload: function (res) {
              resolve(res);
            },
            onerror: function (err) {
              console.log('error');
              console.log(err);
            }
          });
        });
        if (res.status === 200) {
          levelData = {};
          levelTc2Id = {};
          levelTe2Id = {};
          let dataStr = res.response;
          let json = eval(dataStr);
          for (const element of json) {
            if (typeof element.TitleCn == 'string') {
              let titlec = element.TitleCn;
              let title = element.Title;
              levelData[element.ID] = element;
              levelTc2Id[titlec] = element.ID;
              levelTe2Id[title] = element.ID;
            }
          }
          levelData['tagVersion24'] = {};
          console.log('every Monday get level once...');
          GM_setValue('levelData', JSON.stringify(levelData));
          GM_setValue('levelTc2Id', JSON.stringify(levelTc2Id));
          GM_setValue('levelTe2Id', JSON.stringify(levelTe2Id));
        }
      }
    }
    getPromiseLevel();

    // 版本更新机制
    let now = getCurrentDate(1);
    preDate1 = GM_getValue('preDate1', '');
    let checkVersionLayer = GM_getValue('switchupdate') ? preDate1 == '' || preDate1 != now : true;
    GM_xmlhttpRequest({
      method: 'get',
      url: versionUrl + '?timeStamp=' + new Date().getTime(),
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
      },
      onload: function (res) {
        if (res.status === 200) {
          console.log('check version success...');
          let dataStr = res.response;
          let json = JSON.parse(dataStr);
          let v = json['version'];
          let upcontent = json['content'];
          // 更新纸片人地址
          papermanpic = json['papermanpic'];
          // 通过更新 CSS 变量来更新纸片人
          document.documentElement.style.setProperty('--mumu-img', `url(${papermanpic})`);
          console.log(papermanpic);
          if (v != version) {
            if (checkVersionLayer) {
              console.log('弹窗更新栏一次..');
              layer.open({
                area: ['500px', '300px'],
                content:
                  '<pre class="versioncontent" style="color:#000">更新通知: <br/>leetcodeRating有新的版本' +
                  v +
                  '啦,请前往更新~ <br/>' +
                  '更新内容: <br/>' +
                  upcontent +
                  '</pre>',
                yes: function (index, layer0) {
                  let c = window.open(sciptUrl + '?timeStamp=' + new Date().getTime());
                  // c.close()
                  layer.close(index);
                  preDate1 = now;
                  GM_setValue('preDate1', preDate1);
                  console.log('update preDate1 success');
                }
              });
            } else {
              console.log('有新的版本,但是已经弹窗过且开启了最多只更新一次功能,等待明天弹窗..');
            }
          } else {
            console.log('leetcodeRating难度分插件当前已经是最新版本~');
          }
        }
      },
      onerror: function (err) {
        console.log('error');
        console.log(err);
      }
    });
  }
  // 获取必须获取的数据
  getNeedData();

  // 如果pbstatus数据开关已打开且需要更新
  if (GM_getValue('switchpbstatus')) {
    (function () {
      let pbstatus = JSON.parse(GM_getValue('pbstatus', '{}').toString());
      if (pbstatus[pbstatusVersion]) {
        console.log('已经同步过初始题目状态数据...');
        return;
      }
      let syncLayer = layer.confirm(
        '<div class="myfont">检测本地没有题目数据状态,即将开始初始化进行所有题目状态,是否开始同步? <br/> tips:(该检测和开启讨论区展示题目状态功能有关)</div>',
        { icon: 3 },
        function () {
          layer.close(syncLayer);
          layer.open({
            type: 1,
            content: `${pbstatusContent}`,
            title: '同步所有题目状态',
            area: ['550px', '250px'],
            shade: 0.6
          });
          layuiload();
        },
        function () {
          // do nothong
        }
      );
    })();
  }

  // 定时启动函数程序
  clearAndStart(location.href, 1000, true);
  GM_addStyle(`
        .versioncontent {
            white-space: pre-wrap;
            word-wrap: break-word;
            display: block;
        }
    `);

  // spig js 纸片人相关
  if (GM_getValue('switchperson')) {
    const isindex = true;
    const visitor = '主人';
    let msgs = [];

    // 求等级用的数据
    let userTag = null;
    let level = 0;
    let score = 0;
    const queryProcess =
      '\n    query userQuestionProgress($userSlug: String!) {\n  userProfileUserQuestionProgress(userSlug: $userSlug) {\n    numAcceptedQuestions {\n      difficulty\n      count\n    }\n    numFailedQuestions {\n      difficulty\n      count\n    }\n    numUntouchedQuestions {\n      difficulty\n      count\n    }\n  }\n}\n    ';
    const queryUser =
      '\n    query globalData {\n  userStatus {\n    isSignedIn\n    isPremium\n    username\n    realName\n    avatar\n    userSlug\n    isAdmin\n    checkedInToday\n    useTranslation\n    premiumExpiredAt\n    isTranslator\n    isSuperuser\n    isPhoneVerified\n    isVerified\n  }\n  jobsMyCompany {\n    nameSlug\n  }\n  commonNojPermissionTypes\n}\n    ';
    GM_addStyle(`
        :root {
            --mumu-img: url(${papermanpic});
        }
        .spig {
            display:block;
            width:154px;
            height:190px;
            position:absolute;
            top: -150px;
            left: 160px;
            z-index:9999;
        }
        #message {
            line-height:170%;
            color :#191919;
            border: 1px solid #c4c4c4;
            background:#ddd;
            -moz-border-radius:5px;
            -webkit-border-radius:5px;
            border-radius:5px;
            min-height:1em;
            padding:5px;
            top:-30px;
            position:absolute;
            text-align:center;
            width:auto !important;
            z-index:10000;
            -moz-box-shadow:0 0 15px #eeeeee;
            -webkit-box-shadow:0 0 15px #eeeeee;
            border-color:#eeeeee;
            box-shadow:0 0 15px #eeeeee;
            outline:none;
            opacity: 0.75 !important;
        }
        .mumu {
            width:154px;
            height:190px;
            cursor: move;
            background:var(--mumu-img) no-repeat;
        }

        #level {
            text-align:center;
            z-index:9999;
            color :#191919;
        }
    `);

    const spig = `<div id="spig" class="spig" hidden>
                            <div id="message">正在加载中……</div>
                            <div style="height=80px"/>
                            <div id="mumu" class="mumu"></div>
                            <div id="level">level loading...</div>
                        </div>`;
    const hitokoto = `<span class="hitokoto" id="hitokoto" style="display:none">Loading...</span>`;
    $('body').append(spig, hitokoto);

    // 消息函数
    let showMessage = (a, b) => {
      if (b == null) b = 10000;
      $('#mumu').css({ opacity: '0.5 !important' });
      $('#message').hide().stop();
      $('#message').html(a);
      $('#message').fadeIn();
      $('#message').fadeTo('1', 1);
      $('#message').fadeOut(b);
      $('#mumu').css({ opacity: '1 !important' });
    };

    // 右键菜单
    jQuery(document).ready(function ($) {
      $('#spig').mousedown(function (e) {
        if (e.which == 3) {
          showMessage(`秘密通道:<br/> <a href="${problemUrl}" title="题库">题库</a>`, 10000);
        }
      });
      $('#spig').bind('contextmenu', function (e) {
        return false;
      });
    });

    function getscore(userTag) {
      let list = { query: queryProcess, variables: { userSlug: userTag } };
      $.ajax({
        type: 'POST',
        url: lcgraphql,
        data: JSON.stringify(list),
        success: function (res) {
          let levelData = res.data.userProfileUserQuestionProgress.numAcceptedQuestions;
          levelData.forEach(e => {
            if (e.difficulty == 'EASY') score += e.count * 10;
            else if (e.difficulty == 'MEDIUM') score += e.count * 20;
            else if (e.difficulty == 'HARD') score += e.count * 100;
          });
          level = score / 1000;
          $('#level').text('level: ' + Math.trunc(level).toString());
          console.log('目前纸片人的等级是: ' + Math.trunc(level).toString());
        },
        async: false,
        xhrFields: { withCredentials: true },
        contentType: 'application/json;charset=UTF-8'
      });
    }

    $.ajax({
      type: 'POST',
      url: lcgraphql,
      data: JSON.stringify({ query: queryUser, variables: {} }),
      success: function (res) {
        userTag = res.data.userStatus.userSlug;
        // console.log(userTag)
      },
      async: false,
      xhrFields: { withCredentials: true },
      contentType: 'application/json;charset=UTF-8'
    });

    if (userTag != null) {
      getscore(userTag);
    } else {
      // console.log(userTag)
      $('#level').text('请登录后再尝试获取level');
    }
    // 监听分数提交
    let addListener2 = () => {
      let checkUrl = 'https://leetcode.cn/submissions/detail/[0-9]*/check/.*';
      XMLHttpRequest.prototype.send = function (str) {
        const _onreadystatechange = this.onreadystatechange;
        this.onreadystatechange = (...args) => {
          if (this.readyState == this.DONE && this.responseURL.match(checkUrl)) {
            let resp = JSON.parse(this.response);
            // console.log(resp)
            if (resp && resp.status_msg && resp.status_msg.includes('Accepted')) {
              showMessage(
                '恭喜主人成功提交, 当前分数为: ' +
                  score +
                  ', 当前等级为: ' +
                  Math.trunc(level).toString()
              );
              console.log(
                '恭喜主人成功提交, 当前分数为: ' +
                  score +
                  ', 当前等级为: ' +
                  Math.trunc(level).toString()
              );
            } else if (resp && resp.status_msg && !resp.status_msg.includes('Accepted')) {
              showMessage(
                '很遗憾,主人提交失败,不过也不要气馁呀,加油! <br/> 当前分数为: ' +
                  score +
                  ', 当前等级为: ' +
                  Math.trunc(level).toString()
              );
              console.log(
                '很遗憾,主人提交失败,不过也不要气馁呀,加油! 当前分数为: ' +
                  score +
                  ', 当前等级为: ' +
                  Math.trunc(level).toString()
              );
            }
          }
          if (_onreadystatechange) {
            _onreadystatechange.apply(this, args);
          }
        };
        return dummySend.call(this, str);
      };
    };
    addListener2();

    // 鼠标在消息上时
    jQuery(document).ready(function ($) {
      $('#message').hover(function () {
        $('#message').fadeTo('100', 1);
      });
    });

    // 鼠标在上方时
    jQuery(document).ready(function ($) {
      $('.mumu').mouseover(function () {
        $('.mumu').fadeTo('300', 0.3);
        msgs = [
          '我隐身了,你看不到我',
          '我会隐身哦!嘿嘿!',
          '别动手动脚的,把手拿开!',
          '把手拿开我才出来!'
        ];
        let i = Math.floor(Math.random() * msgs.length);
        showMessage(msgs[i]);
      });
      $('.mumu').mouseout(function () {
        $('.mumu').fadeTo('300', 1);
      });
    });

    function msgPageWelcome(url, isAddEvent) {
      let urlLst = [allUrl, pbUrl, pblistUrl, searchUrl];
      let msgShow = [
        '欢迎来到题库页, 美好的一天从做每日一题开始~',
        '欢迎来到做题页面,让我看看是谁光看不做?🐰',
        '欢迎来到题单页面~',
        '欢迎来到搜索页,在这里你能搜到一切你想做的题!'
      ];
      for (let index = 0; index < urlLst.length; index++) {
        const element = urlLst[index];
        if (url.match(element)) {
          // console.log(msgShow[index])
          showMessage(msgShow[index]);
        }
      }
      if (isAddEvent) {
        window.addEventListener('urlchange', () => {
          let newUrl = location.href;
          msgPageWelcome(newUrl, false);
        });
      }
    }

    // 开始
    jQuery(document).ready(function ($) {
      if (isindex) {
        // 如果是主页
        let now = new Date().getHours();
        if (now > 0 && now <= 6) {
          showMessage(visitor + ' 你是夜猫子呀?还不睡觉,明天起的来么你?', 6000);
        } else if (now > 6 && now <= 11) {
          showMessage(
            visitor + ' 早上好,早起的鸟儿有虫吃噢!早起的虫儿被鸟吃,你是鸟儿还是虫儿?嘻嘻!',
            6000
          );
        } else if (now > 11 && now <= 14) {
          showMessage(visitor + ' 中午了,吃饭了么?不要饿着了,饿死了谁来挺我呀!', 6000);
        } else if (now > 14 && now <= 18) {
          showMessage(visitor + ' 中午的时光真难熬!还好有你在!', 6000);
        } else {
          showMessage(visitor + ' 快来逗我玩吧!', 6000);
        }
        msgPageWelcome(location.href, true);
      } else {
        showMessage('力扣欢迎你~', 6000);
      }
      let top = $('#spig').offset().top + 150;
      let left = document.body.offsetWidth - 160;
      if (location.href.match(pbUrl)) {
        top = $('#spig').offset().top + 200;
      }
      $('#spig').attr('hidden', false);
      $('#spig').css({ top: top, left: left });
    });

    // 随滚动条移动
    jQuery(document).ready(function ($) {
      let f = $('.spig').offset().top;
      $(window).scroll(function () {
        $('.spig').animate(
          {
            top: $(window).scrollTop() + f + 150
          },
          {
            queue: false,
            duration: 1000
          }
        );
      });
    });

    // 鼠标点击时
    jQuery(document).ready(function ($) {
      let stat_click = 0;
      let i = 0;
      $('.mumu').click(function () {
        if (!ismove) {
          stat_click++;
          if (stat_click > 4) {
            msgs = [
              '你有完没完呀?',
              '你已经摸我' + stat_click + '次了',
              '非礼呀!救命!OH,My ladygaga'
            ];
            i = Math.floor(Math.random() * msgs.length);
            showMessage(msgs[i]);
          } else {
            msgs = [
              '筋斗云!~我飞!',
              '我跑呀跑呀跑!~~',
              '别摸我,有什么好摸的!',
              '惹不起你,我还躲不起你么?',
              '不要摸我了,我会告诉你老婆来打你的!',
              '干嘛动我呀!小心我咬你!'
            ];
            i = Math.floor(Math.random() * msgs.length);
            showMessage(msgs[i]);
          }
          let s = [
            0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.75, -0.1, -0.2, -0.3, -0.4, -0.5, -0.6, -0.7, -0.75
          ];
          let i1 = Math.floor(Math.random() * s.length);
          let i2 = Math.floor(Math.random() * s.length);
          $('.spig').animate(
            {
              left: (document.body.offsetWidth / 2) * (1 + s[i1]),
              top: (document.body.offsetHeight / 2) * (1 + s[i2])
            },
            {
              duration: 500,
              complete: showMessage(msgs[i])
            }
          );
        } else {
          ismove = false;
        }
      });
    });

    // 拖动
    let _move = false;
    let ismove = false; // 移动标记
    let _x, _y; // 鼠标离控件左上角的相对位置

    jQuery(document).ready(function ($) {
      $('#spig').mousedown(function (e) {
        _move = true;
        _x = e.pageX - parseInt($('#spig').css('left'));
        _y = e.pageY - parseInt($('#spig').css('top'));
      });
      $(document)
        .mousemove(function (e) {
          if (_move) {
            let x = e.pageX - _x;
            let y = e.pageY - _y;
            let wx = $(window).width() - $('#spig').width();
            let dy = $(document).height() - $('#spig').height();
            if (x >= 0 && x <= wx && y > 0 && y <= dy) {
              $('#spig').css({
                top: y,
                left: x
              }); //控件新位置
              ismove = true;
            }
          }
        })
        .mouseup(function () {
          _move = false;
        });
    });

    // 纸片人一言api
    // $("#spig").attr("hidden", false)
    let hitokotohtml = function () {
      let msgShow = [$('#hitokoto').text()];
      showMessage(msgShow[0]);
      setTimeout(hitokotohtml, 15000);
    };
    setTimeout(hitokotohtml, 6000);

    function getkoto() {
      $.get('https://v1.hitokoto.cn/?c=j&encode=json')
        .then(res => {
          echokoto(res);
        })
        .catch(xhr => xhr);
      setTimeout(getkoto, 6000);
    }
    function echokoto(result) {
      let hc = eval(result);
      document.getElementById('hitokoto').textContent = hc.hitokoto;
      // console.log(hc.content)
    }
    setTimeout(getkoto, 5000);
  }
})();