LeetCodeRating|显示力扣周赛难度分

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

// ==UserScript==
// @name         LeetCodeRating|显示力扣周赛难度分
// @namespace    https://github.com/zhang-wangz
// @version      3.0.0
// @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      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.0"
    let pbstatusVersion = "version16"
    // xmr劫持时使用,保留原始
    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]
            }
        }
    }
    // 确认之后不再刷新
    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()
                let levelId = getLevelId(pbName)
                let id = getPbNameId(pbName)
                let level = levelData[levelId]
                // console.log(pbName, level)
                let hit = false
                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": "困难" }
                // rating
                if (id && t2rate[id]) {
                    // console.log(id)
                    let ndRate = t2rate[id]["Rating"]
                    nd.textContent = ndRate
                    hit = true
                } else {
                    if (!nd) break
                    let clr = nd.getAttribute("class")
                    if (clr == null) continue
                    let flag = true
                    for (let c in lightn2c) {
                        if (!flag) break
                        if (clr.includes(c)) {
                            nd.innerText = lightn2c[c]
                            flag= false
                        }
                    }
                    for (let c in darkn2c) {
                        if (!flag) break
                        if (clr.includes(c)) {
                            nd.innerText = darkn2c[c]
                            flag= false
                        }
                    }
                }
                // level渲染
                if (level && GM_getValue("switchlevel")) {
                    // console.log(pbName, level)
                    let text = document.createElement('span')
                    text.setAttribute("class", pbhtml.getAttribute("class"));
                    text.style = nd.getAttribute("style")
                    text.innerHTML = "算术评级: " + level["Level"].toString()
                    if (hit) text.style.paddingRight = "125px" // 命中之后宽度不一样
                    else text.style.paddingRight = "130px"
                    nd.parentNode.insertBefore(text, nd)
                }
            }
        }
        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
        ) {
            // 临时加的pbside
            if (pbsideCnt == normalCnt) clearId("pbside")
            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]
                let data = pbName.split(".")
                let id = data[0]
                let level = levelData[id]
                // console.log(pbName)
                // console.log(level)
                let hit = false
                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": "困难" }
                // rating
                if (id && t2rate[id]) {
                    let ndRate = t2rate[id]["Rating"]
                    nd.textContent = ndRate
                    hit = true
                } else {
                    if (!nd) break
                    let clr = nd.getAttribute("class")
                    if (clr == null) continue
                    let flag = true
                    for (let c in lightn2c) {
                        if (!flag) break
                        if (clr.includes(c)) {
                            nd.innerText = lightn2c[c]
                            flag= false
                        }
                    }
                    for (let c in darkn2c) {
                        if (!flag) break
                        if (clr.includes(c)) {
                            nd.innerText = darkn2c[c]
                            flag= false
                        }
                    }
                }
                // level渲染
                if (level && GM_getValue("switchlevel")) {
                    let text = document.createElement('span')
                    text.setAttribute("class", pbhtml.getAttribute("class"));
                    text.style = nd.getAttribute("style")
                    text.innerHTML = "算术评级: " + level["Level"].toString()
                    if (hit) text.style.paddingRight = "75px" // 命中之后宽度不一样
                    else text.style.paddingRight = "80px"
                    nd.parentNode.insertBefore(text, nd)
                }
            }
        }
        if(totArr.firstChild?.childNodes[0]) pbsidef = totArr.firstChild.childNodes[0].textContent
        if(totArr.lastChild?.childNodes[0]) pbsidee = totArr.lastChild.childNodes[0].textContent
        console.log("已经刷新侧边栏envType分数...")
    }


    // var lang, statusQus
    let eventhappend = function() {
        let key = document.querySelector('.inputarea')
        key.setAttribute('aria-autocomplete','both')
        key.setAttribute('aria-haspopup',false)
        key.removeAttribute('data-focus-visible-added')
        key.removeAttribute('aria-activedescendant')
    }

    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")
                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]
                    if (nd == null) {
                        // console.log(nd)
                        continue
                    }
                    // 如果为算术,说明当前已被替换过
                    if (nd.textContent.includes("算术")) continue
                    let data = pbName.split(".")
                    // console.log(pbName)
                    let hit = false
                    let id = data[0]
                    let level = levelData[id]
                    let darkn2c =  {"text-sd-easy": "简单", "text-sd-medium": "中等", "text-sd-hard": "困难" }
                    let lightn2c =  {"text-sd-easy": "简单", "text-sd-medium": "中等", "text-sd-hard": "困难" }
                    // rating
                    if (id && t2rate[id]) {
                        let ndRate = t2rate[id]["Rating"]
                        nd.textContent = ndRate
                        hit = true
                    } else {
                        if (!nd) break
                        let clr = nd.getAttribute("class")
                        if (clr == null) continue
                        let flag = true
                        for (let c in lightn2c) {
                            if (!flag) break
                            if (clr.includes(c)) {
                                nd.innerText = lightn2c[c]
                                flag = false
                            }
                        }
                        for (let c in darkn2c) {
                            if (!flag) break
                            if (clr.includes(c)) {
                                nd.innerText = darkn2c[c]
                                flag = false
                            }
                        }
                    }
                    // level渲染
                    if (level && GM_getValue("switchlevel")) {
                        let text = document.createElement('span')
                        text.setAttribute("class", pbhtml.getAttribute("class"));
                        text.style = nd.getAttribute("style")
                        text.innerHTML = "算术评级: " + level["Level"].toString()
                        if (hit) text.style.paddingRight = "75px" // 命中之后宽度不一样
                        else text.style.paddingRight = "80px"
                        nd.parentNode.insertBefore(text, nd)
                    }
                }
                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"]
                    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")) {
    // url数据
    let imgUrl = papermanpic

    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(`
        .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:url(${imgUrl}) 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);
}

})();