您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
(Advanced_Bilibili_Danmaku_Manager)目前支持的功能:去除B站彩色弹幕样式
// ==UserScript== // @name [ADM]更丰富的B站弹幕管理功能(去除B站彩色弹幕样式) // @namespace http://www.tampermonkey.com/ // @namespace https://greasyfork.org/zh-CN/scripts/467997 // @version Alpha1.03 // @description (Advanced_Bilibili_Danmaku_Manager)目前支持的功能:去除B站彩色弹幕样式 // @author Tinyblack_QvQ // @license GPL-3.0 // @match *://www.bilibili.com/video/av* // @match *://www.bilibili.com/video/BV* // @match *://www.bilibili.com/list/* // @match *://www.bilibili.com/bangumi/play/ep* // @match *://www.bilibili.com/bangumi/play/ss* // @match *://www.bilibili.com/cheese/play/ep* // @match *://www.bilibili.com/cheese/play/ss* // @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== // @grant GM_setValue // @grant GM_getValue // ==/UserScript== (function () { 'use strict'; // DEBUG使用内容 // var GM_dic = {}; // function GM_getValue(k) { // return GM_dic[k]; // } // function GM_setValue(k, v) { // GM_dic[k] = v; // } // 字符串字典 var string = { "bili-dm": "bili-dm", "bili-roll": "bili-roll", "bili-show": "bili-show", "bili-vip-dm": "bili-dm-vip", "bili-comment-container-class": "comment-container", "bili-container-vue-id": "video-container-v1", // 用于获取vue产生的随机id的元素 "right-panel-inject-element-id": "danmukuBox", // 被注入的元素id "injected-element-class": "danmaku-warp", // 注入的元素class,用于直接适用css "ADM": { "test-text": "userscript-ADM-testtext", "style-sheet": "userscript-ADM-stylesheet", "header-box": "userscript-ADM-cfgpanel-header", "header-arrow-icon": "usercript-ADM-cfgpanel-arrow-icon", "panel-box": "userscript-ADM-cfgpanel-box", "alert": "userscript-ADM-alert-icon", "error": "userscript-ADM-error-icon", "save-button": "userScript-cfg-save", "cancel-button": "userScript-cfg-cancel" }, "config": { "script-initialized": "scriptInitialized", "search-danmu-limit": "searchDanmuLimit", "remove-vip-danmu-style": "removeVipDanmuStyle", "refresh-time": "refreshTime", "alert-wait-time": "alertWaitTime", "error-wait-time": "errorWaitTime", "initialize-refresh-time": "initializeRefreshTime" }, "input": { "remove-vip-danmu-style": "remove_vip_danmu", "refresh-time": "refresh_time" }, "style": { "font-family": "fontFamily", "font-size": "fontSize", "font-weight": "fontWeight", "text-shadow": "textShadow", "--webkit--text-stroke": "webkitTextStroke", "background": "background" } }; // 脚本初始配置 var defaultconfig = { "scriptInitialized": false, // 脚本是否初始化(第一次使用) "removeVipDanmuStyle": true, // 是否清除vip弹幕样式 "searchDanmuLimit": 100, // 在获取初始弹幕样式函数中,搜寻弹幕数量的上限 "initializeRefreshTime": 300, // 当脚本处于初始化状态时,每次刷新间隔的时间 "refreshTime": 1000, // 监测弹幕刷新时间 "alertWaitTime": 3000, // 发现问题直到出现警告的等待时间 "errorWaitTime": 20000 // 发现问题直到出现报错的等待时间 }; // 存储初始弹幕样式 var defaultStyle = {}; // 脚本样式表 var styleSheet = ` .userScript-debug-text { color: red; } .userScript-invisible { visibility: hidden; } .userScript-ADM-icon { position: absolute; } .userscript-ADM-cfgpanel-header { position: relative; background-color: #f1f2f3; cursor: pointer; display: flex; vertical-align: middle; align-items: center; box-sizing: border-box; border-radius: 6px; font-size: 15px; font-family: PingFang SC, HarmonyOS_Regular, Helvetica Neue, Microsoft YaHei, sans-serif; font-weight: 400; padding: 15px; padding-top: 10px; padding-bottom: 10px; margin-bottom: 18px; transition: 0.3s; } .userscript-ADM-cfgpanel-icon { position: relative; left: 3%; } .usercript-ADM-cfgpanel-arrow-icon { position: absolute; right: 17px; transition: 0.3s; user-select: none; } .usercript-ADM-cfgpanel-arrow-icon>svg { position: relative; height: 16px; width: 16px; transition: 0.3s; transform: rotate(90deg); } .userscript-ADM-cfgpanel-dev-info { position: absolute; right: 2%; bottom: 6%; opacity: 40%; color: grey; font-size: 4px; font-weight: 200; user-select: none; } .userscript-ADM-cfgpanel-box { overflow: hidden; position: relative; display: flex; border-radius: 6px; padding: 0px 15px 0px 15px; height: 0px; transition: 0.3s; } .userScript-ADM-cfgpanel-form-grid { position: relative; display: grid; grid-template-columns: 1fr 5fr; grid-template-rows: 1fr 1fr; align-items: center; column-gap: 12px; row-gap: 4px; } .userScript-ADM-cfgpanel-form-input { max-width: 50px; border: solid 1px; text-indent: 2px; } .userScript-ADM-cfgPanel-submit-area>input { border: solid 1px; height: 24px; } .userScript-ADM-cfgPanel-submit-area { position: relative; display: flex; flex-direction: row; align-items: center; } #userScript-cfg-save { flex: 1; border-radius: 0px 0px 0px 6px; transition: 0.3s; background-color: #ffffff; } #userScript-cfg-save:hover { flex: 1.5; background-color: aquamarine; } #userScript-cfg-cancel { border-radius: 0px 0px 6px 0px; flex: 1; transition: 0.3s; background-color: #ffffff; } #userScript-cfg-cancel:hover { flex: 1.5; background-color: rgb(236, 150, 150); } `; // 脚本配置面板html var cfgPanelHtml = ` <div class="userscript-ADM-cfgpanel-header" id="userscript-ADM-cfgpanel-header"> <p> 弹幕管理 </p> <div class="userscript-ADM-cfgpanel-icon"> <span class="userScript-invisible userScript-ADM-icon" id="userscript-ADM-alert-icon">⚠</span> <span class="userScript-invisible userScript-ADM-icon" id="userscript-ADM-error-icon">🚫</span> <span class="userScript-invisible userScript-ADM-icon" id="userscript-ADM-loading-icon">🔷</span> <span class="userScript-invisible userScript-ADM-icon" id="userscript-ADM-complete-icon">✅</span> <!--占位符--><span style="visibility: hidden;">space</span> </div> <span class="userscript-ADM-cfgpanel-dev-info">Powered by Advanced Danmaku Manager</span> <span class="usercript-ADM-cfgpanel-arrow-icon" > <svg id="usercript-ADM-cfgpanel-arrow-icon" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" data-pointer="none" viewBox="0 0 16 16"> <path d="m9.188 7.999-3.359 3.359a.75.75 0 1 0 1.061 1.061l3.889-3.889a.75.75 0 0 0 0-1.061L6.89 3.58a.75.75 0 1 0-1.061 1.061l3.359 3.358z"> </path> </svg> </span> <p class="userScript-invisible" id="userscript-ADM-testtext">This is a test text</p> </div> <div class="userscript-ADM-cfgpanel-box" id="userscript-ADM-cfgpanel-box"> <form> <div class="userScript-ADM-cfgpanel-form-grid"> <input class="userScript-ADM-cfgpanel-form-input" type="checkbox" check="checked" name="remove_vip_danmu"> <p class="userScript-ADM-cfgpanel-form-passage">移除彩色弹幕样式</p> <input class="userScript-ADM-cfgpanel-form-input" type="number" name="refresh_time"> <p class="userScript-ADM-cfgpanel-form-passage">弹幕检测更新时间 (ms)</p> </div> <br> <div class="userScript-ADM-cfgPanel-submit-area"> <input id="userScript-cfg-save" type="button" value="保存"> <input id="userScript-cfg-cancel" type="button" value="取消"> </div> </form> </div> `; // 脚本加载进程 // 0:未开始 // 1:成功注入样式表和配置面板 // 2:成功加载本地配置 // 3:成功获取默认弹幕样式(完成) var loadProgress = 0; // 配置功能,静态模块 var cfg = { // 配置的临时保存位置 content: {}, // 设置配置值,结果保存于content setValue(k, v) { this.content[k] = v; }, // 通过key值获取配置值,来源于content getValue(k) { return this.content[k]; }, // 从本地加载配置 // 先从预设配置找到key值,之后尝试访问,并将结果放至content中 // 若autoLoadDefault为true,则检测到脚本第一次打开时,将自动加载默认配置并保存至gm loadCfgFromLocalSave(autoLoadDefault) { for (const key in defaultconfig) { if (Object.hasOwnProperty.call(defaultconfig, key)) { this.content[key] = GM_getValue(key); } } if (this.getValue(string.config["script-initialized"]) != true && autoLoadDefault) { this.loadCfgFromDefault(); this.setValue(string.config["script-initialized"], true); this.applyChange(); } }, // 将配置保存到本地 applyChange() { for (const key in this.content) { if (Object.hasOwnProperty.call(this.content, key)) { const ele = this.content[key]; GM_setValue(key, ele); } } }, // 加载默认配置 loadCfgFromDefault() { this.content = defaultconfig; } }; function refreshCfgPanelFromLocalCfg() { var input_rmVipDm = document.getElementsByName(string.input["remove-vip-danmu-style"])[0]; var input_refreshTime = document.getElementsByName(string.input["refresh-time"])[0]; input_rmVipDm.checked = cfg.getValue(string.config["remove-vip-danmu-style"]); input_refreshTime.value = cfg.getValue(string.config["refresh-time"]); } // 将函数插入元素中 function addFunc() { // 添加在 id:userscript-ADM-cfgpanel-header 上,用于控制面板开合 function headerFold() { if (panelFold) { panel.style.height = "90px"; panel.style.marginBottom = "18px"; panel.style.paddingTop = "15px"; panel.style.paddingBottom = "15px"; header.style.marginBottom = "6px"; arrow.style.transform = "rotate(-90deg)"; panelFold = false; } else { panel.style.height = "0px"; panel.style.marginBottom = "0px"; panel.style.paddingTop = "0px"; panel.style.paddingBottom = "0px"; header.style.marginBottom = "18px"; arrow.style.transform = "rotate(90deg)"; panelFold = true; } } function saveConfig() { cfg.setValue(string.config["remove-vip-danmu-style"], input_rmVipDm.checked); if (input_refreshTime.value < 100) { cfg.setValue(string.config["refresh-time"], 100); } else { cfg.setValue(string.config["refresh-time"], input_refreshTime.value); } cfg.applyChange(); //重启主循环 clearInterval(mainInterval); setTimeout(() => { mainCirculation(); }, 1000); } var panelFold = true; var panel = document.getElementById(string.ADM["panel-box"]); var header = document.getElementById(string.ADM["header-box"]); var arrow = document.getElementById(string.ADM["header-arrow-icon"]); var input_rmVipDm = document.getElementsByName(string.input["remove-vip-danmu-style"])[0]; var input_refreshTime = document.getElementsByName(string.input["refresh-time"])[0]; var input_save = document.getElementById(string.ADM["save-button"]); var input_cancel = document.getElementById(string.ADM["cancel-button"]); header.addEventListener("click", headerFold); input_save.addEventListener("click", saveConfig); input_cancel.addEventListener("click", refreshCfgPanelFromLocalCfg); } // 倒计时检测脚本是否出现运行问题,时间到后出现图标提醒 function alertCountdown() { setTimeout(() => { if (loadProgress != 3) { document.getElementById(string.ADM.alert).style.visibility = "visible"; setTimeout(() => { if (loadProgress != 3) { document.getElementById(string.ADM.alert).style.visibility = "hidden"; document.getElementById(string.ADM.error).style.visibility = "visible"; } }, defaultconfig[string.config["error-wait-time"]]); } }, defaultconfig[string.config["alert-wait-time"]]); } // 初始化脚本 function initializeScript() { // 向网页中注入css和配置html function inject() { // 获取vue元素随机id var randomVueContainerId = document.getElementsByClassName(string["bili-container-vue-id"])[0].attributes[1].name; if (document.getElementById(string.ADM["test-text"]) == undefined) { document.getElementById(string["right-panel-inject-element-id"]).insertAdjacentHTML("afterend", cfgPanelHtml); // 添加vue元素随机id document.getElementById(string.ADM["header-box"]).setAttribute(randomVueContainerId, randomVueContainerId); document.getElementById(string.ADM["panel-box"]).setAttribute(randomVueContainerId, randomVueContainerId); } if (document.getElementById(string.ADM["style-sheet"]) == undefined) { var e = document.createElement("style"); e.id = string.ADM["style-sheet"]; e.innerText = styleSheet; document.head.appendChild(e); } addFunc(); } // 检测初始化进度 function checkProgress(pro) { switch (pro) { case 0: return 1; case 1: // 检测html和css是否注入网页 return !(document.getElementById(string.ADM["test-text"]) == undefined || document.getElementById(string.ADM["style-sheet"]) == undefined); case 2: // 检测配置是否加载 return cfg.getValue(string.config["script-initialized"]) != undefined; case 3: // 检测默认弹幕样式是否已获取 return defaultStyle[string.style["text-shadow"]] != undefined; } } // 注入css/html if (loadProgress == 0) { inject(); if (checkProgress(1)) loadProgress = 1; } // 加载配置 else if (loadProgress == 1) { cfg.loadCfgFromLocalSave(true); if (checkProgress(2)) { refreshCfgPanelFromLocalCfg(); loadProgress = 2; } } // 获取默认弹幕样式 else if (loadProgress == 2) { getDefaultStyle(); if (checkProgress(3)) loadProgress = 3; } } // 检测页面是否加载完成 function checkPageLoaded() { return document.getElementsByClassName(string["bili-comment-container-class"]).length != 0; } // 解释csstext function interpretCsstext(csstext) { var cssList = csstext.split(';'); var style = {}; cssList.forEach(key => { var k = key.split(':')[0].replace("--", "").replace(" ", ""); var v = key.split(':')[1]; style[k] = v; }); return style; } // 获取初始弹幕样式 function getDefaultStyle() { var dmList = document.getElementsByClassName(string["bili-roll"]); if (dmList.length >= 1) { // 获取弹幕样例,保存样式 for (let i = 0; i < dmList.length && i < cfg.getValue(string.config["search-danmu-limit"]); i++) { // 由于b站第一个弹幕没有直接设置textShadow,所以使用循环来强制获取 var example = interpretCsstext(dmList[i].style.cssText); defaultStyle = { "fontFamily": example.fontFamily, "fontWeight": example.fontWeight, "textShadow": example.textShadow }; // 获取到后即可跳出 if (defaultStyle.textShadow != undefined) break; } } } // 清除vip弹幕样式 function clearVipDanmuStyle(element) { if (element.style.background != "none") { // 清除特殊样式 element.style.background = "none"; element.style.webkitTextStroke = ""; // 设置初始样式 element.style.fontFamily = defaultStyle["fontFamily"]; element.style.fontWeight = defaultStyle["fontWeight"]; element.style.textShadow = defaultStyle["textShadow"]; } } // 代码运行入口如下 // —————————————————————————————— // alertCountdown(); // 先检测页面是否加载完成(存在评论区) // 之后进入初始化循环,等待加载 // 加载完成后进入主循环 var mainInterval; var checkInterval = setInterval( () => { // 检测页面是否加载完成 if (checkPageLoaded()) { clearInterval(checkInterval); var initializeInterval = setInterval(() => { initializeScript(); //当加载完成后,启动正常循环 if (loadProgress == 3) { clearInterval(initializeInterval); mainCirculation(); } }, defaultconfig[string.config["initialize-refresh-time"]]); } } , 200); function mainCirculation() { mainInterval = setInterval(() => { if (cfg.getValue(string.config["remove-vip-danmu-style"])) { document.getElementsByClassName(string["bili-vip-dm"]).forEach(element => { clearVipDanmuStyle(element); }); } }, cfg.getValue(string.config["refresh-time"])); } })();