// ==UserScript== // @name 【B站】评论区成分标签·关键词屏蔽 // @namespace lycoris // @version 1.9.3 // @description B站评论区可视化添加用户成分标签,用户评论关键词屏蔽 // @author Lyzoris // @match https://www.bilibili.com/video/* // @match https://t.bilibili.com/* // @match https://space.bilibili.com/* // @icon https://static.hdslb.com/images/favicon.ico // @connect bilibili.com // @grant unsafeWindow // @grant GM_xmlhttpRequest // @grant GM_setValue // @grant GM_getValue // @grant GM_setClipboard // @license MIT // @run-at document-end // @downloadURL none // ==/UserScript== (function () { "use surict"; const ApiBlog = 'https://api.bilibili.com/x/polymer/web-dynamic/v1/feed/space?&host_mid='; const ApiMedal = 'https://api.live.bilibili.com/xlive/web-ucenter/user/MedalWall?target_id='; const is_new = document.getElementsByClassName('item goback').length != 0; // 检测B站版本 const TAG_STYLE = document.createElement('style'); const TAGSIZE_STYLE = document.createElement('style'); const TAGBAR_STYLE = document.createElement('style'); const TAG_HTML = document.createElement('div'); TAGSIZE_STYLE.setAttribute('id', 'tag-size'); TAG_STYLE.setAttribute('id', 'tagname-style'); const tagSizeDict = { small: `.tag-text, .tag-name{height: 12px;line-height: 12px;}.tag-font{transform: scale(0.5) translate(-50%, -50%);}`, middle: `.tag-text, .tag-name{height: 16px;line-height: 16px;}.tag-font{transform: scale(0.6) translate(-40%, -30%);}` }; const tagHideDict = { true: `.tag-name {display:none;}`, false: `.tag-name {display:block;}` }; TAGSIZE_STYLE.innerHTML = tagSizeDict.middle; TAG_STYLE.innerHTML = tagHideDict.false; TAGBAR_STYLE.innerHTML = ` .userTag{display:inline-block;position:relative;text-align:center;border-width:0px;vertical-align:text-top;margin-left:4px;cursor:default}.tag-text{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-name{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} .tagbar-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}.tagbar-hide svg{width:100%;height:100%}.tagbar-hide:hover{background-color:#76cb9dc9;box-shadow:2px 0px 4px 0px #76cb9d91}.tagbar-hide:hover svg path{fill:#ffffff}.tagbar-active{background-color:#ab85d1c9;box-shadow:2px 0px 4px 0px #c893e291}.tagbar-active svg path{fill:#ffffff}.setbar{display:none;position:absolute;left:32px;top:30px;padding:10px;width:200px;border-radius:5px;background-color:#fffefd;box-shadow:0px 0px 4px 2px #00000036;z-index:2} .tagbar{display:none;position:fixed;z-index:999;right:65px;bottom:20px;background-color:#ffffff;color:#929292;height:350px;width:260px;border-radius:5px;box-shadow:0px 0px 4px 2px #0000002b;padding:10px}.tag-bar{width:100%;height:69%;margin-bottom:4px}.comment-bar{width:100%;height:32%}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}#tagbar-setting{right:0;top:0}#tagbar-setting svg:hover path{fill:#76b1ef}.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}.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:3px;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 10px;appearance:none;background:#b6b2b8;border-radius:4px}#refresh-time::-webkit-slider-thumb{-webkit-appearance:none;-moz-appearance:none;appearance:none;-webkit-box-shadow:0 0 2px;width:10px;height:10px;border-radius:50%;background-size:cover;background-color:#fff} .tagbar-taglist{margin-top:2px;width:98%;height:43%;bottom:0px;border-radius:4px;background-color:rgb(243,238,233);overflow-y:scroll;padding:4px}.tagbar-commentlist{margin-top:2px;width:98%;height:60%;bottom:0px;border-radius:4px;background-color:rgb(243,238,233);overflow-y:scroll;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-exit{right:0;top:0}#set-exit:hover svg path{fill:#cf2222}.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:195px;min-width:195px;height:30px;min-height:20px;max-height:100px;background-color:#f3f3f3;border-radius:5px}#import-area:focus{outline:none} `; TAG_HTML.innerHTML = `
`; const Head = document.head || document.querySelector('head'); const Body = document.body || document.querySelector('body'); Head.appendChild(TAG_STYLE); Head.appendChild(TAGBAR_STYLE); Head.appendChild(TAGSIZE_STYLE); Body.appendChild(TAG_HTML); const sideBar = document.querySelector('.tagbar-hide'); const tagBar = document.querySelector('.tagbar'); const setBar = document.querySelector('.setbar'); let set_exit = document.querySelector('#set-exit'); let setting_btn = document.querySelector('#tagbar-setting'); let tagname_hide = document.querySelector('#tagname-hide'); let medal_show = document.querySelector('#medal-show'); 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'); sideBar.onclick = () => { if (tagBar.style.display === 'block') { tagBar.style.display = 'none'; setBar.style.display = 'none'; sideBar.classList.remove('tagbar-active'); } else { tagBar.style.display = 'block'; sideBar.classList.add('tagbar-active'); } }; const TagNameHide = () => { if (tagname_hide.checked) { TAG_STYLE.innerHTML = tagHideDict.true; }else { TAG_STYLE.innerHTML = tagHideDict.false; } GM_setValue('TagNameHide', tagname_hide.checked); }; setting_btn.onclick = () => { setBar.style.display = 'block'; }; set_exit.onclick = () => { setBar.style.display = 'none'; }; tagname_hide.onclick = TagNameHide; medal_show.onclick = () => { tag_list.medalShow = medal_show.checked; GM_setValue('MedalShow', medal_show.checked); }; 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 = () => { GM_setClipboard(JSON.stringify({ refreshTime: refreshTime, TagNameHide: tagname_hide.checked, MedalShow: medal_show.checked, NoJump: link_delete.checked, CloseComment: close_comment.checked, tagSize: tagSize, keyword: keyword, tag: tag })); alert('已导出标签数据到剪切板!'); }; import_tag.onclick = () => { if (import_area.value) { try { let importData = JSON.parse(import_area.value); let key = Object.keys(importData); key.map(i => GM_setValue(i, importData[i])); } catch (e) { console.log(e); alert('导入配置出错,请检查配置项'); return; } import_area.value = ''; ConfigInit(); } }; 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) { TAGSIZE_STYLE.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} 规则:${tag_dic.reg} 隐藏评论:${tag_dic.hide}`; let new_tag = insertTag(taglist, tag_dic.text, tag_dic.color, title); let tag_index = Object.keys(tag).length; tag[tag_index] = tag_dic; tag_list.push(tag, tag_index); let deleteTag = () => { taglist.removeChild(new_tag); tag_list.pop(tag, tag_index); }; 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, text, color = "#49414b", title = "") => { let new_tag = document.createElement('div'); new_tag.innerHTML = `${text}
`; new_tag.classList.add('tags'); new_tag.style.width = measureTextWidth("12px", text) + 8 + 'px'; new_tag.style.color = 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.tag_class = this.Str2Hex(this.tag); this.text = tag_dic.text; this.tagReg = new RegExp(tag_dic.text); 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.tag_inner = `