Greasy Fork

Greasy Fork is available in English.

Bilibili【哔哩哔哩】 用户成分标签

根据 Bilibili 用户近期动态、粉丝勋章内容检测成分添加自定义标签

当前为 2022-11-01 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Bilibili【哔哩哔哩】 用户成分标签
// @author       Lyzoris
// @namespace    lycoris
// @version      2.2
// @description  根据 Bilibili 用户近期动态、粉丝勋章内容检测成分添加自定义标签
// @supportURL   https://github.com/lyzoris/BilibiliComments-userTag/issues
// @compatible   chrome 80 or later
// @compatible   edge 80 or later
// @match        https://www.bilibili.com/video/*
// @match        https://t.bilibili.com/*
// @match        https://space.bilibili.com/*
// @match        https://www.bilibili.com/bangumi/play/*
// @icon         https://static.hdslb.com/images/favicon.ico
// @connect      bilibili.com
// @grant        unsafeWindow
// @grant        GM_xmlhttpRequest
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_deleteValue
// @grant        GM_listValues
// @grant        GM_setClipboard
// @license MIT
// @run-at document-end
// ==/UserScript==
(function() {
        "use surict";
        const ApiUrl = {
            blog: 'https://api.bilibili.com/x/polymer/web-dynamic/v1/feed/space?&host_mid=',
            concerns: 'https://api.bilibili.com/x/relation/followings?vmid=',
            medal: 'https://api.live.bilibili.com/xlive/web-ucenter/user/MedalWall?target_id='
        };
        const is_new = document.getElementsByClassName('item goback').length != 0;
        const childTagReg = new RegExp(/^(\[.*?\])(\[.*?\])*(\[.*?\])$/);
        const Style_tagName = document.createElement('style');
        const Style_tagSize = document.createElement('style');
        const Style_tagPlace = document.createElement('style');
        const Style_script = document.createElement('style');
        const Html_script = document.createElement('div');
        const tagSizeDict = {
            small: `.tag-class,.tag-name{height: 12px;line-height: 12px;}.tag-font{transform: scale(0.5) translate(-50%, -50%);}`,
            middle: `.tag-class,.tag-name{height: 16px;line-height: 16px;}.tag-font{transform: scale(0.6) translate(-40%, -30%);}`
        };
        const tagHideDict = {
            true: `.tag-class {display:none;}`,
            false: `.tag-class {display:block;}`
        };
        const tagPlaceDict = {
            middle: `.userTag {display: inline-block;position: relative;text-align: center;border-width: 0px;vertical-align: text-top; margin-left: 4px;cursor: default;}`,
            sub: `.userTag {display: inline-block;position: relative;text-align: center;border-width: 0px;vertical-align: sub; margin-left: 4px;cursor: default;}`
        };
        Style_tagSize.innerHTML = tagSizeDict.middle;
        Style_tagName.innerHTML = tagHideDict.false;
        Style_tagPlace.innerHTML = tagPlaceDict.middle;
        Style_script.innerHTML = `
       .tag-name{border-color:rgba(169,195,233,0.1803921568627451);color:rgba(87,127,184,1);background-color:#9ebae833;float:left;text-align:center;border-width:0.5px;border-style:solid;border-bottom-left-radius:1px;border-top-left-radius:1px}.tag-class{position:relative;border-bottom-right-radius:1px;border-top-right-radius:1px;float:left;box-sizing:content-box;text-align:center;border-width:0.5px;border-color:#f25d8e;border-style:solid;border-bottom-left-radius:1px;border-top-left-radius:1px;color:#f25d8e}.tag-font{width:200%;height:200%;font-weight:400;transform-origin:center;font-size:20px;line-height:24px}.script-hide{position:fixed;right:10px;bottom:10px;width:20px;height:20px;font-size:15px;line-height:20px;text-align:center;color:#009688;background-color:#e2e1e2b3;border-radius:5px;box-shadow:2px 0px 4px 0px #0000002b}.script-hide svg{width:100%;height:100%}.script-hide:hover{background-color:#76cb9dc9;box-shadow:2px 0px 4px 0px #76cb9d91}.script-hide:hover svg path{fill:#ffffff}.script-like{display:none;position:fixed;right:10px;bottom:40px;width:20px;height:20px;font-size:15px;line-height:26px;text-align:center;color:#009688;background-color:#e2e1e2b3;border-radius:5px;box-shadow:2px 0px 4px 0px #0000002b}.script-like:hover{background-color:#76cb9dc9;box-shadow:2px 0px 4px 0px #76cb9d91}.script-like svg{width:80%;height:80%;margin-left:1px}.script-like:hover svg path{fill:#ffffff}.tagbar-active{background-color:#ab85d1c9;box-shadow:2px 0px 4px 0px #c893e291}
       .tagbar-active svg path{fill:#ffffff}.script-main{display:none;position:fixed;z-index:999;right:65px;bottom:20px;background-color:#ffffff;color:#929292;height:300px;width:250px;border-radius:4px;box-shadow:0px 0px 4px 2px #0000002b;padding:10px}.tag-bar{width:250px;height:90%;margin-top:30px}.comment-bar{display:none;width:250px;margin-top:30px;height:90%}.setting-bar{display:none;width:250px;margin-top:30px}svg.icon{width:10px;height:10px}.tagbar-action{position:absolute;top:2px;width:15px;height:15px;line-height:15px;margin:0;border-radius:50%;background-color:#fff0;text-align:center;font-size:small;color:#929292}.script-main input[type="checkbox"],input[type="radio"]{appearance:auto}.tagbar-btn{background-color:#ffffff;color:#929292;height:20px;margin:5px 0px 5px 0;padding:0 4px 0 4px;border:none;border-radius:4px;font-weight:bold;transform-origin:center;transform:scale(0.9) translate(-10%,-10%);font-size:13px;text-align:center;box-shadow:#b1b1b13d 0px 0px 3px 2px}.tagbar-btn:hover{color:#37a279ab}.tagbar-btn:active{color:#b4b6ee}.input-tag{margin-bottom:4px;width:74%;left:20%;border-radius:4px;border:solid 1px #b0b0b0}.input-tag:focus{outline:none;background-color:#d5d5d559}.tagbar-label{font-size:12px;display:inline-block;margin-right:10px}#input-tagcolor{width:52px;height:20px;border-radius:4px;border:solid 1px #b0b0b0}
       .tags{display:inline-block;width:40px;height:20px;font-size:12px;border-radius:5px;color:#49414b;text-align:center;transform-origin:center;transform:scale(0.9) translate(-10%,-10%);line-height:20px;background-color:#ededed;margin-left:5px;margin-top:5px;cursor:pointer;box-shadow:0px 1px 5px 0 #00000033}.tags:hover{background-color:#ced1d2c4}.delete-tag{position:relative;top:-3px;right:0;width:20px;height:20px;border-radius:50%;transform-origin:center;transform:scale(0.6) translate(-50%,-50%);font-size:20px;color:#837171;line-height:18px;background-color:#b2bfc67a;box-shadow:0px 0px 3px 1px #00000033}.delete-tag:hover{color:white;background-color:crimson}.delete-tag:active{color:white;background-color:#f0f}.tag-info{position:relative;margin-top:-20px;font-weight:bold}#refresh-time{width:80px;height:5px;outline:none;margin:0 10px 0 25px;appearance:none;background:#b6b2b8;border-radius:4px}#refresh-time::-webkit-slider-thumb{-webkit-appearance:none;-moz-appearance:none;appearance:none;box-shadow:0 0 2px;width:10px;height:10px;border-radius:50%;background-size:cover;background-color:#fff}.tagbar-taglist{margin-top:2px;width:97%;height:51%;bottom:0px;border-radius:4px;background-color:rgb(243,238,233);overflow-y:auto;padding:4px}.tagbar-commentlist{margin-top:35px;width:97%;height:75.5%;bottom:0px;border-radius:4px;background-color:rgb(243,238,233);overflow-y:auto;padding:4px}
       .tagbar-taglist::-webkit-scrollbar,.tagbar-commentlist::-webkit-scrollbar,.medal-table::-webkit-scrollbar,#import-area::-webkit-scrollbar{width:4px;height:4px}.tagbar-taglist::-webkit-scrollbar-thumb,.tagbar-commentlist::-webkit-scrollbar-thumb,.medal-table::-webkit-scrollbar-thumb,#import-area::-webkit-scrollbar-thumb{border-radius:5px;box-shadow:inset 0 0 5px rgba(0,0,0,0.2);background:rgba(0,0,0,0.2)}.tagbar-taglist::-webkit-scrollbar-track,.tagbar-commentlist::-webkit-scrollbar-track,.medal-table::-webkit-scrollbar-track{box-shadow:inset 0 0 5px rgba(0,0,0,0.2);border-radius:0px;background:rgba(0,0,0,0.1)}#flash-time{margin-right:10px}.tagSize{margin:5px 0 5px 0}.tagSize-label{display:inline-block;text-align:center}.tagSize-radio{vertical-align:text-bottom}.set-label{font-size:12px;display:inline-block;margin:5px 0 5px 0}.medalTag{margin-left:5px;cursor:pointer}.medal-table{display:none;position:absolute;padding:5px;max-width:230px;max-height:160px;overflow-y:auto;font-size:12px;background-color:#fffefd;border-radius:5px;cursor:default;z-index:2;box-shadow:0px 0px 4px 2px #0000002b}.fans-tag{float:left;margin:4px 4px 4px 4px;border:solid 1px #6a99de;border-radius:2px}.fans-tag .tag-name{border:none;width:18px}#import-area{font-size:10px;margin:10px 0 0 0;max-width:244px;min-width:244px;height:22px;min-height:20px;max-height:20px;background-color:#f3f3f3;border-radius:5px}#import-area:focus{outline:none}
       .topnav{top:8px;left:5px;height:20px;line-height:20px;position:absolute;color:#8e8e8e;background-color:#ddddd98c;border-radius:4px;cursor:default}.topnav-active{color:#dd7a7a;background-color:#ffffff;border-radius:4px;height:16px;line-height:16px;box-shadow:0 0 3px 1px #3f3d3d80}.topnav-option{display:inline-block;font-size:12px;font-weight:bold;padding:0 5px 0 5px}.topnav-option:nth-child(2){margin:0 38px 0 38px}#dynamic-like svg{width:25px;height:25px;margin:0 0 0 25px}#dynamic-like:hover svg path{fill:#19aada}
    `;
        Html_script.innerHTML = `
    <div class='script-like'>
        <svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="16" height="16">
            <path d="M857.28 344.992h-264.832c12.576-44.256 18.944-83.584 18.944-118.208 0-78.56-71.808-153.792-140.544-143.808-60.608 8.8-89.536 59.904-89.536 125.536v59.296c0 76.064-58.208 140.928-132.224 148.064l-117.728-0.192A67.36 67.36 0 0 0 64 483.04V872c0 37.216 30.144 67.36 67.36 67.36h652.192a102.72 102.72 0 0 0 100.928-83.584l73.728-388.96a102.72 102.72 0 0 0-100.928-121.824zM128 872V483.04c0-1.856 1.504-3.36 3.36-3.36H208v395.68H131.36A3.36 3.36 0 0 1 128 872z m767.328-417.088l-73.728 388.96a38.72 38.72 0 0 1-38.048 31.488H272V476.864a213.312 213.312 0 0 0 173.312-209.088V208.512c0-37.568 12.064-58.912 34.72-62.176 27.04-3.936 67.36 38.336 67.36 80.48 0 37.312-9.504 84-28.864 139.712a32 32 0 0 0 30.24 42.496h308.512a38.72 38.72 0 0 1 38.048 45.888z" fill="#459cdd"></path>
        </svg>
    </div>
    <div class='script-hide'>
        <svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="16" height="16">
            <path d="M593.949942 770.425747c2.908236-4.233418 4.614088-9.380648 4.614088-14.892175s-1.705851-10.658757-4.614088-14.922874L431.084621 577.00041c-10.32209-10.324136-10.32209-27.042913 0-37.381375l158.601204-159.117974c5.376451-4.843308 8.771781-11.818163 8.771781-19.61371 0-14.602579-11.83249-26.433022-26.434046-26.433022-5.953595 0-11.420097 1.979074-15.835663 5.298679l-5.300726 5.299703L375.020744 520.936533c-20.650319 20.647249-20.650319 54.114478 0 74.763774l177.556928 177.590698 1.811252 1.794879c4.690836 4.264117 10.903328 6.884804 17.740036 6.884804C581.18829 781.968641 589.183382 777.399579 593.949942 770.425747z" fill="#009688"></path>
        </svg>
    </div>
    <div class='script-main'>
        <div class="topnav">
            <div class="topnav-option topnav-active" id="tag-btn">成分标签</div>
            <div class="topnav-option" id="comment-btn">评论屏蔽</div>
            <div class="topnav-option" id="setting-btn">脚本设置</div>
        </div>
        <div class="scriptBar setting-bar">
            <input type="button" class="tagbar-btn" id="export-tag" value="导出配置" title="导出标签配置到剪切板" style="float:left; margin:0;">
            <input type="button" class="tagbar-btn" id="import-tag" value="导入配置" title="导入配置到油猴存储&#10;请先将配置粘贴到下方并确认无误,再点击本按键&#10;导入配置后请刷新界面以应用配置" style="float:right; margin:0;">
            <textarea id="import-area" placeholder="请在此处粘贴配置后点击【导入配置】"></textarea>
            <label class="set-label" title="除用户动态以外的用户标签检测选项(可多选)">检测选项
                    <label for="detect-concerns" title="检测用户关注列表" style="margin-left:20px">用户关注
                        <input type="checkbox" id="detect-concerns" style="margin-left:5px;height:11px">
                    </label>
            <label for="detect-medal" title="检测用户的粉丝勋章&#10;开启后用户标签末尾出现【勋章】标签,&#10;点击【勋章】展开勋章栏显示所有勋章&#10;鼠标放上显示对应Up主,点击可跳转&#10;点击【勋章】或空白处收起" style="margin-left:20px">
                        粉丝勋章<input type="checkbox" id="detect-medal" style="margin-left:5px;height:11px">
                    </label>
            </label>
            <div class="tagSize set-label">
                <label title="更改标签大小后刷新界面即可">标签大小</label>
                <div class="tagSzie-option" style="display:inline-block; margin-left: 20px;">
                    <label calss="tagSize-label">较小</label>
                    <input class="tagSize-radio" type="radio" name="tagSize" value="small" style="margin-left: 10px;">
                </div>
                <div class="tagSzie-option" style="display:inline-block; margin-left: 40px;">
                    <label calss="tagSize-label">标准</label>
                    <input class="tagSize-radio" type="radio" name="tagSize" value="middle" checked="true" style="margin-left: 10px;">
                </div>
            </div>
            <label class="set-label" for="refresh-time" style="margin: 5px 0 5px 0;font-size: 12px;display: block;" title="页面滚动时脚本刷新间隔时间,5-10s 为宜">刷新间隔<input type="range" id="refresh-time" min="2" max="20" step="1" value="5"><span id="show-time">5s</span></label>
            <label class="set-label" for="tagname-hide" title="不显示标签分类,建议开启&#10;出现标签样式错误时请开启此项">标签不显示分类<input type="checkbox" id="tagname-hide" style="margin-left:50px;height:11px"></label>
            <label class="set-label" for="tag-merge" title="相同类型标签合并,只显示一个标签分类&#10;可能影响标签样式,建议同时打开【标签不显示分类】">同类型标签合并<input type="checkbox" id="tag-merge" style="margin-left:50px;height:11px"></label>
            <label class="set-label" for="link-delete" title="去除 评论区评论关键词蓝色点击跳转">去除关键词跳转<input type="checkbox" id="link-delete" style="margin-left:50px;height:11px"></label>
            <label class="set-label" for="close-comment" title="动态评论末尾添加【收起评论】按键">动态添加收起评论<input type="checkbox" id="close-comment" style="margin-left:38px;height:11px"></label>
            <label class="set-label" for="dynamic-btn" title="动态页面添加【批量点赞】按键">动态页批量点赞<input type="checkbox" id="dynamic-btn" style="margin-left:50px;height:11px"></label>
        </div>
        <div class="scriptBar tag-bar">
            <label class="tagbar-label" for="input-tagname" title="标签的分类,比如游戏、Vtuber、主播、UP主等&#10;用来识别标签类型,尽量短一些">标签分类</label><input type="text" id="input-tagname" class="input-tag" autocomplete="off">
            <label class="tagbar-label" for="input-tagtext" title="标签具体显示的内容,以区别每个标签">标签内容</label><input type="text" id="input-tagtext" class="input-tag" autocomplete="off">
            <label class="tagbar-label" for="input-tagreg" title="匹配用户标签的关键词,使用 & 和 | 分隔,使用 ( ) 组合&#10;多关键词任一匹配:王者荣耀或王者 -&gt; 王者荣耀|王者 &#10;多关键词同时匹配:王者荣耀与吃鸡 -&gt; 王者荣耀&吃鸡 &#10;多关键词组合匹配:(王者|王者荣耀)&(吃鸡|和平精英)&#10;&#10;合并标签时填写 [子标签内容][子标签内容] 如[王者][原神]&#10;注意:面板中合并标签需在所有子标签之后">标签规则</label><input type="text" id="input-tagreg"
                class="input-tag" autocomplete="off">
            <label class="tagbar-label" for="input-tagcolor" title="标签文字颜色,可在面板中预览">标签颜色</label><input type="color" name="" id="input-tagcolor">
            <label class="tagbar-label" style="margin: 0 0 0 12px ;" for="tag-hide">屏蔽标签用户评论<input type="checkbox" id="tag-hide" style="margin-left:9px;height:11px"></label>
            <input type="button" class="tagbar-btn" id="add-tag" value="添加标签">
            <div class="tagbar-taglist"></div>
        </div>
        <div class="scriptBar comment-bar">
            <label class="tagbar-label" for="input-comment-reg" title="评论关键词屏蔽规则,同 【标签规则】">评论规则</label><input type="text" id="input-comment-reg" class="input-tag" autocomplete="off">
            <input type="button" class="tagbar-btn" id="add-comment-reg" style="float:left; margin:5px 0 5px 0;" value="添加规则">
            <div class="tagbar-commentlist"></div>
        </div>
    </div>`;
        const Head = document.head || document.querySelector('head');
        const Body = document.body || document.querySelector('body');
        Head.appendChild(Style_tagName);
        Head.appendChild(Style_script);
        Head.appendChild(Style_tagSize);
        Head.appendChild(Style_tagPlace);
        Body.appendChild(Html_script);
        const scriptHide = document.querySelector('.script-hide');
        const scriptMain = document.querySelector('.script-main');
        const topNav = document.querySelectorAll('.topnav-option');
        const scriptBar = document.querySelectorAll('.scriptBar');
        let tagname_hide = document.querySelector('#tagname-hide');
        let tag_merge = document.querySelector('#tag-merge');
        let detect_concerns = document.querySelector('#detect-concerns');
        let detect_medal = document.querySelector('#detect-medal');
        let link_delete = document.querySelector('#link-delete');
        let close_comment = document.querySelector('#close-comment');
        let tagSize_radio = document.querySelectorAll('.tagSize-radio');
        let import_tag = document.querySelector('#import-tag');
        let import_area = document.querySelector('#import-area');
        let tag_name = document.querySelector('#input-tagname');
        let tag_text = document.querySelector('#input-tagtext');
        let tag_reg = document.querySelector('#input-tagreg');
        let tag_color = document.querySelector('#input-tagcolor');
        let add_tag_btn = document.querySelector('#add-tag');
        let export_tag = document.querySelector('#export-tag');
        let taglist = document.querySelector('.tagbar-taglist');
        let tag_hide = document.querySelector('#tag-hide');
        let refresh_time = document.querySelector("#refresh-time");
        let add_tag_reg = document.querySelector('#add-comment-reg');
        let comment_reg = document.querySelector('#input-comment-reg');
        let commentlist = document.querySelector('.tagbar-commentlist');
        let dynamic_btn = document.querySelector('#dynamic-btn');
        let script_like = document.querySelector('.script-like');
        scriptHide.onclick = () => {
            if (scriptMain.style.display === 'block') {
                scriptMain.style.display = 'none';
                scriptHide.classList.remove('tagbar-active');
            } else {
                scriptMain.style.display = 'block';
                scriptHide.classList.add('tagbar-active');
            }
        };
        topNav.forEach(btn => {
            btn.onclick = function() {
                topNav.forEach(i => {
                    i.classList.remove('topnav-active');
                });
                this.classList.add('topnav-active');
                scriptBar.forEach(i => {
                    i.style.display = 'none';
                });
                document.querySelector('.' + this.getAttribute('id').replace('btn', 'bar')).style.display = 'block';
            };
        });
        dynamic_btn.onclick = () => {
            script_like.style.display = dynamic_btn.checked ? 'block' : 'none';
            GM_setValue('DynamicLike', dynamic_btn.checked);
        };
        script_like.onclick = dynamic_click;
        const TagNameHide = () => {
            Style_tagName.innerHTML = tagHideDict[String(tagname_hide.checked)];
            GM_setValue('TagNameHide', tagname_hide.checked);
        };
        tagname_hide.onclick = TagNameHide;
        detect_concerns.onclick = () => {
            tag_list.detectConcerns = detect_concerns.checked;
            GM_setValue('DetectConcerns', detect_concerns.checked);
        };
        detect_medal.onclick = () => {
            tag_list.detectMedal = detect_medal.checked;
            GM_setValue('DetectMedal', detect_medal.checked);
        };
        tag_merge.onclick = () => {
            tagMerge = tag_merge.checked;
            GM_setValue('TagMerge', tagMerge);
        };
        link_delete.onclick = () => { GM_setValue('NoJump', link_delete.checked); };
        close_comment.onclick = () => { GM_setValue('CloseComment', close_comment.checked); };
        add_tag_btn.onclick = () => {
            if (tag_name.value && tag_text.value && tag_reg.value) {
                addTag({
                    tag: tag_name.value,
                    text: tag_text.value,
                    reg: tag_reg.value,
                    color: tag_color.value,
                    hide: tag_hide.checked
                });
                tag_name.value = '';
                tag_text.value = '';
                tag_reg.value = '';
                tag_hide.checked = false;
            } else {
                alert('请将标签信息补充完整');
            }
        };
        export_tag.onclick = () => {
            let exportData = {};
            let key_storage = GM_listValues();
            key_storage.forEach(i => {
                exportData[i] = GM_getValue(i, null);
            });
            GM_setClipboard(JSON.stringify(exportData));
            alert('已导出标签数据到剪切板!');
        };
        import_tag.onclick = () => {
            if (import_area.value) {
                try {
                    let importData = JSON.parse(import_area.value);
                    Object.keys(importData).forEach(i => {
                        GM_setValue(i, importData[i]);
                    });
                } catch (e) {
                    alert('导入配置出错,请检查配置项');
                    return;
                }
                import_area.value = '';
                ConfigInit();
            } else {
                alert('配置为空!请先在输入框粘贴配置并检查无误后点击【导入配置】');
            }
        };
        refresh_time.onchange = () => {
            refreshTime = Number(refresh_time.value) * 1000;
            GM_setValue('RefreshTime', refreshTime);
            document.querySelector("#show-time").innerText = refresh_time.value + 's';
        };
        const getTagSize = () => {
            for (let radio of tagSize_radio) {
                if (radio.checked) {
                    Style_tagSize.innerHTML = tagSizeDict[radio.value];
                    tagSize = radio.value;
                    GM_setValue('TagSize', tagSize);
                }
            }
        };
        tagSize_radio.forEach(radio => { radio.onclick = getTagSize; });
        add_tag_reg.onclick = () => {
            if (comment_reg.value) {
                addKeyWord(comment_reg.value);
                comment_reg.value = '';
            } else {
                alert('请将关键词正则信息补充完整');
            };
        };
        const addKeyWord = (reg_text) => {
            if (!keyword.includes(reg_text)) {
                let new_tag = insertTag(commentlist, reg_text);
                let keyword_index = Object.keys(comment_keyword).length;
                comment_keyword[keyword_index] = reg_text;
                keyword.push(reg_text);
                GM_setValue('Keyword', keyword);
                let deleteTag = () => {
                    commentlist.removeChild(new_tag);
                    delete comment_keyword[keyword_index];
                    keyword = [];
                    let keyword_index_new = Object.keys(comment_keyword);
                    keyword_index_new.map(key => keyword.push(comment_keyword[key]));
                    GM_setValue('Keyword', keyword);
                };
                new_tag.children[0].onclick = deleteTag;
                new_tag.children[1].ondblclick = () => {
                    comment_reg.value = reg_text;
                    deleteTag();
                };
            }
        };
        const addTag = (tag_dic) => {
            let title = `${tag_dic.tag}&#10;规则:${tag_dic.reg}&#10;隐藏评论:${tag_dic.hide}`;
            let new_tag = insertTag(taglist, tag_dic);
            let tag_index = Object.keys(tag).length;
            tag[tag_index] = tag_dic;
            tag_list.push(tag, tag_index);
            let deleteTag = () => {
                taglist.removeChild(new_tag);
                delete tag[tag_index];
                let tag1 = Object.assign({}, tag);
                tag = {};
                Object.values(tag1).forEach((value, i) => { tag[i] = value; });
                tag_list.pop(tag);
            };
            new_tag.children[0].onclick = deleteTag;
            new_tag.children[1].ondblclick = () => {
                tag_name.value = tag_dic.tag;
                tag_text.value = tag_dic.text;
                tag_reg.value = tag_dic.reg;
                tag_color.value = tag_dic.color;
                tag_hide.checked = tag_dic.hide;
                deleteTag();
            };
        };
        const insertTag = (parentNode, dic) => {
            let new_tag = document.createElement('div');
            let title = '';
            if (childTagReg.test(dic.reg)) {
                new_tag.style.border = 'solid 1px #4fc3f7';
                title = `分类:${dic.tag} (合并标签)&#10;子标签:${dic.reg}&#10;隐藏评论:${dic.hide}`;
            } else {
                title = `分类:${dic.tag}&#10;规则:${dic.reg}&#10;隐藏评论:${dic.hide}`;
            }
            new_tag.innerHTML = `<div class="delete-tag">x</div><p class="tag-info" title="${title}">${dic.text}</p>`;
            new_tag.classList.add('tags');
            new_tag.style.width = measureTextWidth("12px", dic.text) + 8 + 'px';
            new_tag.style.color = dic.color;
            parentNode.appendChild(new_tag);
            return new_tag;
        };
        const measureTextWidth = (fontSize, text) => {
            let fontFamily = "PingFang SC, HarmonyOS_Regular, Helvetica Neue, Microsoft YaHei, sans-serif";
            let canvas = document.createElement("canvas");
            let context = canvas.getContext("2d");
            context.font = fontSize + " " + fontFamily;
            let result = context.measureText(text);
            return Math.ceil(result.width);
        };
        class Tag {
            constructor(tag_dic) {
                this.tag = tag_dic.tag;
                this.child_tag = [];
                this.tag_class = this.Str2Hex(this.tag, 'class');
                this.text = tag_dic.text;
                this.tag_id = this.Str2Hex(this.text, 'id');
                this.reg = Tag.MultiReg(tag_dic.reg);
                this.hide = tag_dic.hide;
                this.color = tag_dic.color;
                this.tag_size = tagSize === 'middle' ? '15px' : '12px';
                this.tag_width = measureTextWidth(this.tag_size, this.tag);
                this.width = measureTextWidth(this.tag_size, this.text);
                this.list = new Set();
                this.nolist = new Set();
                this.ChildTag(tag_dic);
                this.tag_inner = `<div class='tag-name' style='color: ${this.color}; width:${this.width}px;'><div class='tag-font'>${this.text}</div></div>`;
                this.inner = `<div class='userTag ${this.tag_class} ${this.tag_id}' title="${this.child_tag.join(' ')}"><div class='tag-class' style='border-color:#8da8e8;color:#5e80c4; width:${this.tag_width}px'><div class='tag-font'>${this.tag}</div></div>${this.tag_inner}</div>`;
            }
            ChildTag(tag_dic) {
                if (childTagReg.test(tag_dic.reg)) {
                    this.child_tag = tag_dic.reg.match(/(?<=\[)(.*?)(?=\])/g);
                    let regs = [];
                    tag_list.list.filter(i => {
                        if (this.child_tag.includes(i.text)) {
                            return i;
                        }
                    }).forEach(e => {
                        let new_reg = String(e.reg).match(/\((.*?)\){1,2}/g);
                        if (new_reg) {
                            regs.splice(0, 0, ...new_reg);
                        } else {
                            regs.push(`(?=.*(${String(e.reg).replace(/\//g, '')}))`);
                        }
                    });
                    this.reg = new RegExp(`^${regs.join('')}.*`);
                }
            }
            Str2Hex(str, state) {
                let hex = '';
                for (let i = 0; i < str.length; i++) {
                    hex += str.charCodeAt(i).toString(16);
                }
                return 'tag-' + state + '-' + hex;
            }
            static MultiReg(query) {
                    let regStr = query.indexOf('&') !== -1 ? `^${query.split('&').map(q => `(?=.*${q})`).join('')}.*` : query;
            return new RegExp(regStr);
        }
        check(pid, c) {
            if (this.list.has(pid)) {
                if (this.hide) {
                    getCommentTextNode(c).innerText = '评论已屏蔽';
                }
                if (!c.querySelector('.' + this.tag_id)) {
                    if (c.querySelector('.' + this.tag_class) && tagMerge) {
                        c.querySelector('.' + this.tag_class).innerHTML += this.tag_inner;
                    }
                    else {
                        c.innerHTML += this.inner;
                    }
                }
            }
        }
        detect(pid, c, st) {
            if (this.reg.test(st)) {
                if (this.hide) {
                    getCommentTextNode(c).innerText = '评论已屏蔽';
                }
                if (!c.querySelector('.' + this.tag_id) && !this.list.has(pid) && !this.nolist.has(pid)) {
                    if (c.querySelector('.' + this.tag_class) && tagMerge) {
                        c.querySelector('.' + this.tag_class).innerHTML += this.tag_inner;
                    }
                    else {
                        c.innerHTML += this.inner;
                    }
                }
                this.combine(pid, c);
                this.list.add(pid);
            }
            else {
                this.nolist.add(pid);
            }
        }
        combine(pid, c) {
            if (this.child_tag.length != 0) {
                tag_list.list.forEach(e => {
                    if (this.child_tag.includes(e.text)) {
                        let child_tag = c.querySelector('.' + e.tag_id);
                        if (child_tag) {
                            c.removeChild(child_tag);
                        }
                        e.list.delete(pid);
                        e.nolist.add(pid);
                    }
                });
            }
        }
    }
    class TagList {
        constructor() {
            this.isDetect = false;
            this.detectConcerns = detect_concerns.checked;
            this.detectMedal = detect_medal.checked;
            this.list = [];
        }
        push(tag, index) {
            this.list.push(new Tag(tag[index]));
            GM_setValue('Tag', tag);
        }
        pop(tag) {
            this.list = [];
            Object.values(tag).map(i => this.list.push(new Tag(i)));
            GM_setValue('Tag', tag);
        }
        keyword(c) {
            if (keyword.length > 0) {
                let comment = getCommentTextNode(c);
                for (let reg of keyword) {
                    let Reg = Tag.MultiReg(reg);
                    if (Reg.test(comment.innerText)) {
                        comment.innerText = '评论已屏蔽';
                        break;
                    }
                }
            }
        }
        check(pid, c) {
            this.list.map(i => i.check(pid, c));
            let tag0 = this.list[0];
            this.isDetect = (tag0.list.has(pid) || tag0.nolist.has(pid)) ? true : false;
            if (this.isDetect && this.detectMedal) {
                this.MedalWall(pid, c);
            }
        }
        detect(pid, c) {
            let p = [];
            const p1 = (resolve) => { Requests(ApiUrl.blog + pid, (data) => { resolve(data); }); };
            const p2 = (resolve) => { Requests(ApiUrl.medal + pid, (data) => { resolve(data); }); };
            const p3 = (resolve) => { Requests(ApiUrl.concerns + pid + '&pn=1&ps=50', (data) => { resolve(data); }); };
            if (this.detectConcerns && this.detectMedal) {
                p = [p1, p2, p3];
            }
            else if (this.detectConcerns && !this.detectMedal) {
                p = [p1, p3];
            }
            else if (!this.detectConcerns && this.detectMedal) {
                p = [p1, p2];
            }
            else {
                p = [p1];
            }
            Promise.all(p.map(i => new Promise(i))).then((result) => {
                this.list.map(i => i.detect(pid, c, result.join('')));
                if (this.detectMedal) {
                    this.medal(pid, c, result[1]);
                }
            });
        }
        medal(pid, c, data) {
            let medal_list = JSON.parse(data).list;
            if (medal_list.length != 0) {
                let medalInfo = [];
                medal_list.forEach((e) => {
                    medalInfo.push({
                        targetName: e.target_name,
                        link: e.link,
                        medalName: e.medal_info.medal_name,
                        level: e.medal_info.level,
                        color: { start: '#' + e.medal_info.medal_color_start.toString(16).padStart(6, '0'),
                            end: '#' + e.medal_info.medal_color_end.toString(16).padStart(6, '0'),
                            border: '#' + e.medal_info.medal_color_border.toString(16).padStart(6, '0')
                        }
                    });
                });
                MedalDict[pid] = medalInfo;
                this.MedalWall(pid, c);
            }
        }
        MedalWall(pid, c) {
            if (c.querySelector('.medalTag')) {
                return;
            }
            RunOnce(() => {
                window.addEventListener('click', (event) => {
                    let e = event || window.event;
                    let targetClass = e.target ? e.target.classList : e.srcElement.classList;
                    if (!targetClass.contains('medal-font')) {
                        document.querySelectorAll('.medal-table').forEach(e => {
                            e.style.display = 'none';
                        });
                    }
                });
            });
            let medal = MedalDict[pid];
            if (medal) {
                let medal_list = '';
                medal.forEach((e) => {
                    medal_list += `
                    <div class="fans-tag">
                    <div class="tag-name" title="${e.targetName}" style="width:${measureTextWidth('15px', e.medalName)}px;background-image: linear-gradient(90deg, ${e.color.start}, ${e.color.end});">
                    <div class="tag-font"><a href="${e.link}" style="color:#fff;">${e.medalName}</a></div></div>
                    <div class="tag-class" style="color:${e.color.end};"><div class="tag-font">${e.level}</div></div>
                    </div>`;
                });
                let medalInner = `
                <div class="medalTag">
                    <div class='tag-name' style="color: #fff;width:28px;background-image: linear-gradient(90deg,#ffcaec,#a187ff);">
                    <div class='tag-font medal-font'>勋章</div></div>
                    <div class="medal-table">${medal_list}</div>
                </div>`;
                c.innerHTML += medalInner;
                let medalBtn = c.querySelector('.medalTag');
                let table = c.querySelector('.medal-table');
                medalBtn.onclick = () => {
                    let disp = table.style.display;
                    table.style.left = medalBtn.offsetLeft + 50 + 'px';
                    table.style.display = disp === 'block' ? 'none' : 'block';
                };
            }
        }
    }
    let RunOnce = function (func) {
        func.apply(arguments);
        RunOnce = () => { };
    };
    const IngredientDetection = () => {
        let commentlist = getCommentList();
        if (commentlist.length != 0) {
            commentlist.forEach(c => {
                let pid = getPid(c);
                tag_list.keyword(c);
                if (tag_list.list.length == 0) {
                    return;
                }
                tag_list.check(pid, c);
                if (tag_list.isDetect) {
                    return;
                }
                tag_list.detect(pid, c);
            });
        }
        if (link_delete.checked) {
            noJump();
        }
    };
    const Requests = (requestUrl, func) => {
        GM_xmlhttpRequest({
            method: "get",
            url: requestUrl,
            data: '',
            headers: {
                'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, Concerns Gecko) Chrome/104.0.0.0 Safari/537.36'
            },
            onload: function (res) {
                if (res.status === 200) {
                    let data = JSON.stringify(JSON.parse(res.response).data);
                    func(data);
                }
                else {
                    console.log('加载用户信息失败');
                    console.log(res);
                }
            },
        });
    };
    const getPid = (c) => {
        if (is_new) {
            return c.querySelector('.user-name,.sub-user-name').dataset.userId || c.querySelector('.name').dataset.usercardMid;
        }
        else {
            return c.querySelector('.name').getAttribute('data-usercard-mid') || c.children[0].href.replace(/[^\d]/g, "");
        }
    };
    const getCommentList = () => {
        if (is_new) {
            return document.querySelectorAll('.user-info,.sub-user-info') || document.querySelectorAll('.user');
        }
        else {
            return document.querySelectorAll('.user');
        }
    };
    const getCommentTextNode = (c) => {
        let comment;
        if (is_new) {
            if (c.classList.contains('user-info')) {
                comment = c.nextSibling.children[0];
            }
            else {
                comment = c.nextSibling;
            }
        }
        else {
            if (c.querySelector('.text-con')) {
                comment = c.querySelector('.text-con');
            }
            else {
                comment = c.nextSibling;
            }
        }
        return comment;
    };
    const noJump = () => {
        let jump_word = document.querySelectorAll('.jump-link,.search-word');
        for (let i of jump_word) {
            i.outerHTML = i.innerText;
        }
    };
    const closeComment = () => {
        if (!close_comment.checked) {
            return;
        }
        const commentBtn = document.querySelectorAll('.bili-dyn-action.comment:not(.active)');
        for (let Btn of commentBtn) {
            Btn.onclick = () => {
                let scroll = document.body.scrollTop || document.documentElement.scrollTop;
                setTimeout(() => {
                    const pls = document.querySelectorAll('.bb-comment');
                    for (let pl of pls) {
                        if (pl.querySelectorAll('.close-btn').length === 0) {
                            let close_btn = document.createElement('div');
                            close_btn.classList.add('close-btn');
                            close_btn.innerHTML = "<a class='close-text' style='color:#26902e'>收起评论</a>";
                            pl.appendChild(close_btn);
                            close_btn.style.cssText = "text-align: center; font-size: 14px; color: #99a2aa; border-top: 1px solid #e5e9ef; margin: 0; overflow: hidden; padding: 12px 0 10px; position: relative;";
                            close_btn.onclick = () => {
                                Btn.click();
                                window.scrollTo(0, scroll);
                            };
                        }
                    }
                }, 200);
            };
        }
    };
    function dynamic_click() {
        let likebtns = document.querySelectorAll('.like:not(.active)');
        let likebtnsiter = likebtns.entries();
        let clicktimer = setInterval(() => {
            let nextele = likebtnsiter.next();
            if (nextele.done) {
                clearInterval(clicktimer);
                return;
            }
            nextele.value[1].click();
        }, 600);
    }
    const throttle = (func, wait) => {
        let timeout, startTime = new Date();
        return function () {
            let context = this, args = arguments, curTime = new Date();
            clearTimeout(timeout);
            if (Number(curTime) - Number(startTime) >= refreshTime) {
                func.apply(context, args);
                startTime = curTime;
            }
            else {
                timeout = setTimeout(func, wait);
            }
        };
    };
    const wheel = () => {
        let btns = document.querySelectorAll('.btn-more,.paging-box,.view-more-pagination,.view-more-btn,.bili-dyn-action.comment:not(active)');
        for (let btn of btns) {
            btn.onclick = () => {
                setTimeout(() => {
                    IngredientDetection();
                }, 500);
            };
        }
        IngredientDetection();
        closeComment();
    };
    const ConfigInit = () => {
        refreshTime = GM_getValue('RefreshTime', 5000);
        refresh_time.value = String(refreshTime / 1000);
        document.querySelector("#show-time").innerText = refresh_time.value + 's';
        tagname_hide.checked = GM_getValue('TagNameHide', false);
        TagNameHide();
        detect_concerns.checked = GM_getValue('DetectConcerns', false);
        detect_medal.checked = GM_getValue('DetectMedal', false);
        tag_list.detectMedal = detect_medal.checked;
        tag_list.detectConcerns = detect_concerns.checked;
        tagMerge = GM_getValue('TagMerge', false);
        tag_merge.checked = tagMerge;
        link_delete.checked = GM_getValue('NoJump', false);
        close_comment.checked = GM_getValue('CloseComment', false);
        dynamic_btn.checked = GM_getValue('DynamicLike', false);
        script_like.style.display = dynamic_btn.checked ? 'block' : 'none';
        tagSize = GM_getValue('TagSize', 'middle');
        Style_tagSize.innerHTML = tagSizeDict[tagSize];
        tagSize_radio.forEach(radio => {
            if (radio.value == tagSize) {
                radio.checked = true;
            }
        });
        const key_storage = GM_getValue('Keyword', []);
        key_storage.map(key => addKeyWord(key));
        const tag_storage = GM_getValue('Tag', {});
        Object.values(tag_storage).forEach(i => { addTag(i); });
    };
    let tag = {};
    const tag_list = new TagList();
    const comment_keyword = {};
    const MedalDict = {};
    let keyword = [];
    let refreshTime = 5000;
    let tagSize = 'middle';
    let tagMerge = false;
    ConfigInit();
    window.addEventListener("scroll", throttle(wheel, 2000));
    const webType = [/https:\/\/(t|space).bilibili.com/, /https:\/\/www.bilibili.com\/video/];
    let local_href = location.href;
    if (webType[0].test(local_href)) {
        detect_medal.checked = false;
        detect_medal.disabled = true;
        tag_list.detectMedal = false;
        link_delete.checked = false;
        link_delete.disabled = true;
    }
    else if (webType[1].test(local_href)) {
        close_comment.checked = false;
        close_comment.disabled = true;
        dynamic_btn.checked = false;
        script_like.style.display = 'none';
        dynamic_btn.disabled = true;
    }
    else {
        Style_tagPlace.innerHTML = tagPlaceDict.sub;
        detect_medal.checked = false;
        detect_medal.disabled = true;
        tag_list.detectMedal = false;
        close_comment.checked = false;
        close_comment.disabled = true;
        dynamic_btn.checked = false;
        script_like.style.display = 'none';
        dynamic_btn.disabled = true;
    }
})();