// ==UserScript== // @name bilibili直播净化 // @namespace https://github.com/lzghzr/GreasemonkeyJS // @version 2.0.17 // @author lzghzr // @description 屏蔽聊天室礼物以及关键字, 净化聊天室环境 // @supportURL https://github.com/lzghzr/GreasemonkeyJS/issues // @include /^http:\/\/live\.bilibili\.com\/\d.*$/ // @require https://greasyfork.org/scripts/23961-commentcorelibrary/code/CommentCoreLibrary.js?version=152310 // @license MIT // @grant none // @run-at document-end // @downloadURL none // ==/UserScript== /// /** * 屏蔽B站直播间聊天室内容 * * @class BiLiveNoVIP */ var BiLiveNoVIP = (function () { function BiLiveNoVIP() { this._W = window; this._D = document; this._tempWord = []; this._defaultConfig = { version: 1481883398389, menu: { noKanBanMusume: { name: '看  板  娘', enable: false }, noHDIcon: { name: '活动标识', enable: false }, noVIPIcon: { name: '老爷标识', enable: false }, noMedalIcon: { name: '粉丝勋章', enable: false }, noUserLevelIcon: { name: '用户等级', enable: false }, noLiveTitleIcon: { name: '成就头衔', enable: false }, noSystemMsg: { name: '系统公告', enable: false }, noGiftMsg: { name: '礼物信息', enable: false }, fixTreasure: { name: '下移宝箱', enable: false }, replaceDanmaku: { name: '替换弹幕', enable: false }, closeDanmaku: { name: '  ┣关闭弹幕', enable: false }, popularWords: { name: '  ┣屏蔽热词', enable: false }, beatStorm: { name: '  ┗节奏风暴', enable: false } } }; // 加载设置 var config = JSON.parse(localStorage.getItem('blnvConfig') || '{}'); var defaultConfig = this._defaultConfig; if (config.version === undefined || config.version < defaultConfig.version) { for (var x in defaultConfig.menu) { try { defaultConfig.menu[x].enable = config.menu[x].enable; } catch (error) { console.error(error); } } this._config = defaultConfig; } else { this._config = config; } } /** * 开始 * * @memberOf BiLiveNoVIP */ BiLiveNoVIP.prototype.Start = function () { var _this = this; this._AddUI(); this._ChangeCSS(); // flash加载完成后的回调函数 var flashCallback = this._W['flash_on_ready_callback']; this._W['flash_on_ready_callback'] = function () { flashCallback(); _this._AddDanmaku(); if (_this._config.menu.replaceDanmaku.enable) { _this._ReplaceDanmaku(true); if (_this._config.menu.popularWords.enable) _this._PopularWords(true); if (_this._config.menu.beatStorm.enable) _this._BeatStorm(true); } }; }; /** * 模拟实时屏蔽 * * @private * @memberOf BiLiveNoVIP */ BiLiveNoVIP.prototype._ChangeCSS = function () { // 获取或者插入style var elmStyle = this._D.querySelector('#gunCSS'); if (elmStyle === null) { elmStyle = this._D.createElement('style'); elmStyle.id = 'gunCSS'; this._D.body.appendChild(elmStyle); } //css内容 var cssText = ''; if (this._config.menu.noKanBanMusume.enable) cssText += "\n .live-haruna-ctnr {\n display: none !important;\n }"; if (this._config.menu.noHDIcon.enable) cssText += "\n #chat-msg-list a[href^=\"/hd/\"], #chat-msg-list .system-msg.guard-sys, #chat-msg-list .guard-msg:after, .guard-lv1:before, .guard-lv2:before, #santa-hint-ctnr {\n display: none !important;\n }\n #chat-msg-list .guard-msg {\n margin: auto !important;\n padding: 4px 5px !important;\n }\n #chat-msg-list .user-name.color {\n color: #4fc1e9 !important;\n }\n #chat-msg-list .msg-content {\n color: #646c7a !important;\n }"; if (this._config.menu.noVIPIcon.enable) cssText += "\n #chat-msg-list a[href=\"/i#to-vip\"], #chat-msg-list .system-msg .square-icon, #chat-msg-list .system-msg .v-middle {\n display: none !important;\n }\n #chat-msg-list .system-msg {\n padding:0 10px;\n height:auto;\n }"; if (this._config.menu.noMedalIcon.enable) cssText += "\n #chat-msg-list .medal-icon {\n display: none !important;\n }"; if (this._config.menu.noUserLevelIcon.enable) cssText += "\n #chat-msg-list .user-level-icon {\n display: none !important;\n }"; if (this._config.menu.noLiveTitleIcon.enable) cssText += "\n #chat-msg-list .check-my-title {\n display: none !important;\n }"; if (this._config.menu.noSystemMsg.enable) cssText += "\n #chat-msg-list .announcement-container {\n display: none !important;\n }"; if (this._config.menu.noGiftMsg.enable) cssText += "\n #chat-msg-list .gift-msg, #chat-list-ctnr > .super-gift-ctnr, #chat-list-ctnr > #gift-msg-1000, #super-gift-ctnr-haruna {\n display: none !important;\n }\n #chat-list-ctnr > #chat-msg-list {\n height: 100% !important;\n }"; if (this._config.menu.fixTreasure.enable) cssText += "\n #player-container > .treasure-box-ctnr {\n margin: -160px 0 !important;\n }"; elmStyle.innerHTML = cssText; }; /** * 添加按钮 * * @private * @memberOf BiLiveNoVIP */ BiLiveNoVIP.prototype._AddUI = function () { var _this = this; // 添加按钮相关的css this._AddCSS(); // 获取按钮插入的位置 var elmDivBtns = this._D.querySelector('.btns'); // 传说中的UI, 真的很丑 var elmDivGun = this._D.createElement('div'); elmDivGun.id = 'gunBut'; var html = '滚
'; // 循环插入内容 for (var x in this._config.menu) { html += "\n
\n \n \t\n " + this._config.menu[x].name + "\n
"; } html += '
'; elmDivGun.innerHTML = html; // 插入菜单按钮 elmDivBtns.appendChild(elmDivGun); // 获取刚刚插入的DOM var elmDivMenu = this._D.querySelector('#gunMenu'); // 为了和b站更搭, 所以监听body的click this._D.body.addEventListener('click', function (ev) { var evt = ev.target; if (elmDivGun.contains(evt)) { if (evt === elmDivGun) elmDivMenu.classList.toggle('gunHide'); } else { elmDivMenu.classList.add('gunHide'); } }); // 循环设置监听插入的DOM var replaceDanmakuCheckbox = this._D.querySelector('#replaceDanmaku'); var closeDanmakuCheckbox = this._D.querySelector('#closeDanmaku'); var popularWordsCheckbox = this._D.querySelector('#popularWords'); var beatStormCheckbox = this._D.querySelector('#beatStorm'); for (var x in this._config.menu) { var checkbox = this._D.getElementById(x); checkbox.checked = this._config.menu[x].enable; checkbox.addEventListener('change', function (ev) { var evt = ev.target; _this._config.menu[evt.id].enable = evt.checked; localStorage.setItem('blnvConfig', JSON.stringify(_this._config)); switch (evt.id) { case 'replaceDanmaku': _this._ReplaceDanmaku(evt.checked); if (!evt.checked) { // 关闭热词和节奏风暴选项 if (closeDanmakuCheckbox.checked = true) closeDanmakuCheckbox.click(); if (popularWordsCheckbox.checked = true) popularWordsCheckbox.click(); if (beatStormCheckbox.checked = true) beatStormCheckbox.click(); } break; case 'closeDanmaku': _this._CM.clear(); if (evt.checked && !replaceDanmakuCheckbox.checked) replaceDanmakuCheckbox.click(); break; case 'popularWords': _this._PopularWords(evt.checked); if (evt.checked && !replaceDanmakuCheckbox.checked) replaceDanmakuCheckbox.click(); break; case 'beatStorm': _this._BeatStorm(evt.checked); if (evt.checked && !replaceDanmakuCheckbox.checked) replaceDanmakuCheckbox.click(); break; default: _this._ChangeCSS(); break; } }); } }; /** * 添加弹幕层 * * @private * @memberOf BiLiveNoVIP */ BiLiveNoVIP.prototype._AddDanmaku = function () { var _this = this; // 获取播放器节点 this._playerObject = this._D.querySelector('#player_object'); // 创建弹幕层 var danmaku = this._D.createElement('div'); danmaku.className = 'gunDanmaku'; var danmakuContainer = this._D.createElement('div'); danmakuContainer.className = 'gunDanmakuContainer'; // 插入弹幕层 danmaku.appendChild(danmakuContainer); this._playerObject.parentNode.appendChild(danmaku); this._CM = new CommentManager(danmakuContainer); // CommentCoreLibrary (//github.com/jabbany/CommentCoreLibrary) - Licensed under the MIT license this._CM.init(); // 透明度 this._CM.options.scroll.opacity = parseInt(localStorage.getItem('danmuAlpha') || '100') / 100; // 存在时间7s this._CM.options.scroll.scale = 1.75; // 弹幕密度 this._CM.options.limit = parseDensity(localStorage.getItem('danmuDensity') || '30'); // 监听视频窗口大小 var bodyObserver = new MutationObserver(function (ev) { _this._CM.width = danmaku.clientWidth; _this._CM.height = danmaku.clientHeight; // 排行榜 var evt = ev[0]; var elmDivRand = _this._D.querySelector('#rank-list-ctnr'); var elmDivChat = _this._D.querySelector('#chat-list-ctnr'); if (evt.oldValue && evt.oldValue.indexOf('player-full-win') === -1) { elmDivRand.style.cssText = 'display: none'; elmDivChat.style.cssText = 'height: calc(100% - 150px)'; } else { elmDivRand.style.cssText = ''; elmDivChat.style.cssText = ''; } }); bodyObserver.observe(this._D.body, { attributes: true, attributeOldValue: true, attributeFilter: ['class'] }); this._W.addEventListener('resize', function () { _this._CM.width = danmaku.clientWidth; _this._CM.height = danmaku.clientHeight; }); // 控制条 this._D.querySelector('#danmu-alpha-ctrl').addEventListener('input', function (ev) { _this._CM.options.scroll.opacity = parseInt(ev.target.value) / 100; }); this._D.querySelector('#danmu-density-ctrl').addEventListener('input', function (ev) { _this._CM.options.limit = parseDensity(ev.target.value); }); /** * 计算弹幕密度 * * @param {string} density * @returns */ function parseDensity(density) { var limit; switch (density) { case '81': limit = 100; break; case '82': limit = 200; break; case '83': limit = 300; break; case '84': limit = 400; break; case '85': limit = 500; break; case '86': limit = 0; break; default: limit = parseInt(density); break; } return limit; } }; /** * 替换弹幕 * * @private * @param {boolean} enable * @memberOf BiLiveNoVIP */ BiLiveNoVIP.prototype._ReplaceDanmaku = function (enable) { var _this = this; if (enable) { this._CM.start(); // 替换弹幕 this._playerObject.showComments(false); var masterID_1 = this._W.MASTERID; // 获取聊天信息 this._DANMU_MSG = this._W.protocol.DANMU_MSG; this._W.protocol.DANMU_MSG = function (json) { // 屏蔽关键词 if (_this._tempWord.indexOf(json.info[1]) !== -1) return; if (!_this._config.menu.closeDanmaku.enable) { // 添加弹幕 var danmuColor = 16777215; // 主播与管理员特殊颜色 if (json.info[2][2] === 1) danmuColor = (json.info[2][0] === masterID_1) ? 6737151 : 16750592; var danmu = { mode: 1, text: json.info[1], size: 0.25 * parseInt(localStorage.getItem('danmuSize') || '100'), color: danmuColor, shadow: true }; _this._CM.send(danmu); } // 添加到聊天列表 _this._DANMU_MSG(json); }; } else { this._W.protocol.DANMU_MSG = this._DANMU_MSG; this._W.msg_history = { get: function () { } }; this._CM.stop(); this._CM.clear(); this._playerObject.showComments(true); } }; /** * 屏蔽热词 * * @private * @param {boolean} disable * @memberOf BiLiveNoVIP */ BiLiveNoVIP.prototype._PopularWords = function (disable) { this._tempWord = (disable) ? this._W.flash_popularWords() : []; }; /** * 屏蔽节奏风暴 * * @private * @param {boolean} disable * @memberOf BiLiveNoVIP */ BiLiveNoVIP.prototype._BeatStorm = function (disable) { var _this = this; if (disable) { this._SPECIAL_GIFT = this._W.protocol.SPECIAL_GIFT; this._W.protocol.SPECIAL_GIFT = function (json) { if (json.data['39'] && json.data['39'].content != null) _this._tempWord.push(json.data['39'].content); }; } else this._W.protocol.SPECIAL_GIFT = this._SPECIAL_GIFT; }; /** * 添加样式 * * @private * @memberOf BiLiveNoVIP */ BiLiveNoVIP.prototype._AddCSS = function () { var cssText = "\n #chat-ctrl-panel .chat-ctrl-btns .btn {\n margin: 0 3px;\n }\n .gunHide {\n display: none;\n }\n #gunBut {\n border: 1px solid #999;\n border-radius: 50%;\n cursor: pointer;\n display: inline-block;\n font-size: 13px;\n height: 18px;\n margin: -3px 3px;\n text-align: center;\n width: 18px;\n vertical-align: text-top;\n }\n #gunBut > #gunMenu {\n animation:move-in-right cubic-bezier(.22,.58,.12,.98) .4s;\n background-color: #fff;\n border-radius: 5px;\n box-shadow: 0 0 2em .1em rgba(0,0,0,0.15);\n cursor: default;\n font-size: 12px;\n height: 275px;\n margin: -250px -125px;\n padding: 10px;\n position: absolute;\n width: 100px;\n z-index: 10;\n }\n #gunBut > #gunMenu > div {\n \tbackground: darkgray;\n \tborder-radius: 5px;\n \theight: 10px;\n \tmargin: 0 0 12px 0;\n \tposition: relative;\n \twidth: 20px;\n }\n #gunBut > #gunMenu > div > label {\n \tbackground: dimgray;\n \tborder-radius: 50%;\n \tcursor: pointer;\n \tdisplay: block;\n \theight: 16px;\n \tleft: -3px;\n \tposition: absolute;\n \ttop: -3px;\n \ttransition: all .5s ease;\n \twidth: 16px;\n }\n #gunBut > #gunMenu > div > input[type=checkbox]:checked + label {\n background: #4fc1e9;\n \tleft: 7px;\n }\n #gunBut > #gunMenu > div > span {\n left: 0;\n margin: -3px 0 0 20px;\n position: absolute;\n width: 80px;\n }\n .gunDanmaku {\n position:absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 93%;\n overflow: hidden;\n z-index: 1;\n cursor: pointer;\n pointer-events: none;\n }\n .gunDanmaku .gunDanmakuContainer {\n transform: matrix3d(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1);\n position: absolute;\n display: block;\n overflow: hidden;\n margin: 0;\n border: 0;\n top: 0;\n left: 0;\n bottom: 0;\n right: 0;\n z-index: 9999;\n touch-callout: none;\n user-select: none;\n }\n .gunDanmaku .gunDanmakuContainer .cmt {\n transform: matrix3d(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1);\n transform-origin: 0% 0%;\n position: absolute;\n padding: 3px 0 0 0;\n margin: 0;\n color: #fff;\n font-family: \"Microsoft YaHei\", SimHei;\n font-size: 25px;\n text-decoration: none;\n text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black;\n text-size-adjust: none;\n line-height: 100%;\n letter-spacing: 0;\n word-break: keep-all;\n white-space: pre;\n }\n .gunDanmaku .gunDanmakuContainer .cmt.noshadow {\n text-shadow: none;\n }\n .gunDanmaku .gunDanmakuContainer .cmt.rshadow {\n text-shadow: -1px 0 white, 0 1px white, 1px 0 white, 0 -1px white;\n }"; // 插入css var elmStyle = this._D.createElement('style'); elmStyle.innerHTML = cssText; this._D.body.appendChild(elmStyle); }; return BiLiveNoVIP; }()); var gun = new BiLiveNoVIP(); gun.Start();