您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
根据ID屏蔽直播间的发言(持久化存储、傻瓜式使用/管理)
// ==UserScript== // @name 斗鱼屏蔽ID消息(blockspeech) // @namespace http://tampermonkey.net/ // @version 1.0.1 // @description 根据ID屏蔽直播间的发言(持久化存储、傻瓜式使用/管理) // @author Ginyang // @match *://www.douyu.com/* // @icon https://www.douyu.com/favicon.ico // @run-at document-start // @grant GM_setValue // @grant GM_getValue // @grant GM_registerMenuCommand // @license MIT // ==/UserScript== /************************* v1.0.1 更新内容************************* * 1、【新增/优化】新增消息提示,现在不用进入控制台查看信息了,直接会在页面上方给出提示消息 2、【修复】进入直播间可能会因为页面未加载完全导致插件加载失败(现在添加了window.onload判断) 3、【修复】Firefox中input输入框的宽度超出设置页面 4、【优化】Firefox中的滚动条样式不起作用(这是火狐的内核导致的,提供的样式美化太少了,我又懒得自己覆盖) 5、【优化】代码结构优化 *************************************************************** */ (function () { 'use strict'; window.onload = function () { console.log("bs load success"); // 全局变量 var bs_observer = null; // 定义消息为全局对象 var message = null; function bsStyleInit() { let bs_style_css = ` /***************************遮罩层overlay、对话框dialog***************************/ #bs_overlay { display: block; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.5); z-index: 9999; } @keyframes show { 0% { transform: rotateX(30deg); } 58% { opacity: 1; transform: rotateX(-12deg); } 100% { opacity: 1; } } #bs_dialog { display: block; position: fixed; top: 50%; left: 50%; margin-top: -160px; margin-left: -160px; width: 320px; height: 330px; background-color: #fff; color: #333; font-size: 16px; border-radius: 5px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.3); padding: 20px; transition: all 0.3s ease-in-out; /* transform-style: preserve-3d; */ transform-origin: center center; animation: show 0.3s ease-in-out; } #bs_dialog h2{ font-size: 24px; display: block; margin-bottom: 12px; font-weight: bold; } /***************************关闭close***************************/ #bs_btn_close { position: absolute; top: 20px; right: 20px; margin: 3px; width: 24px; height: 24px; background: white; cursor: pointer; box-sizing: border-box; transition: all 0.3s ease-in-out; } #bs_btn_close:hover::before, #bs_btn_close:hover::after { background: red; } #bs_btn_close:before { position: absolute; content: ''; width: 1px; height: 25px; background: #999; transform: rotate(45deg); top: -3px; left: 11px; } #bs_btn_close:after { content: ''; position: absolute; width: 1px; height: 25px; background: #999; transform: rotate(-45deg); top: -3px; left: 11px; } /*************** 表格样式 *************/ #bs_table { display: block; width: 300px; height: 220px; margin: auto; border-collapse: collapse; overflow-y: scroll; scrollbar-width: thin; } #bs_table td { border-bottom: 1px solid #ddd; font-size: 16px; padding: 5px 10px; } #bs_table td:first-child { width: 250px; text-align: left; max-width: 250px; word-break: break-all; } #bs_table td:last-child { width: 50px; text-align: right; } #bs_table tr:last-child td { border-bottom: none; } /* ****************插入行table ******************/ #row_insert { margin: auto; margin-bottom: 10px; } /*****************滚动条******************/ #bs_dialog ::-webkit-scrollbar { width: 5px; height: 10px; } #bs_dialog ::-webkit-scrollbar-track { width: 6px; background: rgba(#101F1C, 0.1); -webkit-border-radius: 2em; -moz-border-radius: 2em; border-radius: 2em; } #bs_dialog ::-webkit-scrollbar-thumb { background-color: rgba(144, 147, 153, .3); background-clip: padding-box; min-height: 28px; -webkit-border-radius: 2em; -moz-border-radius: 2em; border-radius: 2em; transition: background-color .3s; cursor: pointer; } #bs_dialog ::-webkit-scrollbar-thumb:hover { background-color: rgba(144, 147, 153, .5); } /**************底部按钮*****************/ #bs_tool_row { width: 300px; display:flex; justify-content: center; align-items: center; margin: auto; margin-top: 10px; } #bs_tool_row button { width: 50px; padding: auto; margin: 0 5px; } #bs_overlay button:focus { outline: none; } #bs_overlay button { border: none; background-color: rgba(23, 171, 227, .8); color: #eee; border-radius: 5px; cursor: pointer; line-height: 28px; height: 28px; padding: 0 5px; } #bs_overlay button:hover { background-color: rgba(23, 171, 227, 1); } /******************输入框input*******************/ #bs_input { width: 200px; border-radius: 5px; border: 1px solid; padding-left: 5px; } #bs_input:focus { box-shadow: 0 0 6px #2993e9; } /**********************************message_css********************************/ #message-container { position: fixed; left: 0; top: 0; right: 0; display: flex; flex-direction: column; align-items: center; z-index: 10000; pointer-events: none; /* 允许鼠标事件穿透 */ } #message-container .message { background: #fff; margin: 10px 0; padding: 0 10px; height: 40px; box-shadow: 0 0 10px 0 #eee; font-size: 14px; border-radius: 3px; display: flex; align-items: center; transition: height 0.2s ease-in-out, margin 0.2s ease-in-out } #message-container .message .text { color: #333; padding: 0 20px 0 5px } #message-container .message .close { cursor: pointer; color: #999 } #message-container .message .icon-info { color: #0482f8 } #message-container .message .icon-error { color: #f83504 } #message-container .message .icon-success { color: #06a35a } #message-container .message .icon-warning { color: #ceca07 } #message-container .message .icon-loading { color: #0482f8 } @keyframes message-move-in { 0% { opacity: 0; transform: translateY(-100%) } 100% { opacity: 1; transform: translateY(0) } } #message-container .message.move-in { animation: message-move-in 0.3s ease-in-out } @keyframes message-move-out { 0% { opacity: 1; transform: translateY(0) } 100% { opacity: 0; transform: translateY(-100%) } } #message-container .message.move-out { animation: message-move-out 0.3s ease-in-out; animation-fill-mode: forwards } /************************外部样式***************************/ @font-face {font-family: "icon"; src: url('//at.alicdn.com/t/font_1117508_wxidm5ry7od.eot?t=1554098097778'); /* IE9 */ src: url('//at.alicdn.com/t/font_1117508_wxidm5ry7od.eot?t=1554098097778#iefix') format('embedded-opentype'), /* IE6-IE8 */ url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAASwAAsAAAAACXAAAARhAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCDXgqFdIUpATYCJAMcCxAABCAFhD0HXBtNCFGUL0qC7GuMwfUModQ5d89yCS2IguQlYTzox9H5PfHlpWFpEC0ubQKL/QJcYxBBtFZWz/RCiEgotIBChV2EASSXCBX5xofBiPtz7s0nnCJ450fACtP2peU0NJSTZudnZywngIyp2Q4m293vbjhIKItjihNIZS3s4mx2bTEk1jI8gciSLJCwesNvAaBfaMOve98XmEY5wnfz3a39QU5QZFVbdF5i+gcD/3G/4l/jK/C2ASA6KCowynZ8xxew8qJK+MQORO8xnOLqb1h0n09guNkGZLZsHVyQsoTLAnHcdykpB7QygxR6RZuwN8VNUNCXS/jGDev347+CKZoKj7Pj4KZDVn79eUjAP1zXN0C85syQD6JiJSKJ84nWk3JOYKWc4Z+/mbcHMVqvaH/98v5qf3X63Pk8/P8Eq3EwjKZ4qhS9/c/TEi0uHQnEAUm7kDyNSeXXO5Pkt51J8NuJSeH/DpOG/4cyi4p1i0djFD4DsZ8RG81VIUlYY9YzIfBOsZLGd25VXu8jbXf6O5mXeVhHN3GEsYVtgIyXm9AHradeL9uATxQOXxaLRydnjMJbK6L0zDFsY6Jt8bFHRO6RB/FTztgwMNYuFWkR8SNHnjiJz5JGGDLNn6gcgzdXhWUVo8vr46LysuGJDUxSWT6CbcHi0jX9JpvoOrSRi+KG10H6vQ0GY25JMkc36XmPmdEouyf9E33O07RhdBOWZPYHx3yQMC19ZCzZWkLAR35/5xmxDLYu9AqejrN5PTy2lgc0d06bS6k1uX9wWvJPVHBJZp7qnXWdMCJ3gR5WVL//cZmeBgxOanWDbCXDjsu4WzpKRUciLwh3CYkhh/Y3byXAmC7LvYr4Hs70do3p3dBqyD5xPqoJ9l+te2FzLY0T/svpCG1o9hqPZHJ33jEGNEMzFch0HfRQKdIox2/yaAiNEun5XePlysEZfBnivwZ9vTqLA8PGZXIbZLU687F4Dc46J/785DmxDLYu9IYAhKBE8yY+gOzpaGSIjSCNxyPLQad7CAZzBLGO9++/I0k9Awh1e/aHQUxK4TEZBN9kz/LCloUvZiR4c3V9wKqrB3uFwrz7bFSSASAVAeq6fPO1voHgXIHOGjnOkNpw6uHuco731Zx8UuFUQprkQdGZBlWaiySxEBojLIVW2gDDrTB98AgTWHIih2E5wyD0XkAx2iuoeq+RJIagMdkntHrvYbh9/o85wuJo9C6RanTAegbf5glTNbpqx5+hayIqFY7mvUKpfPDA6NCIP7yNCcoqG9SDO6Y1AyZ5DFulL4ZRxCGVPEBbD3lap3PDwyzpjYZsHpOqzSREacgBLM+Az8YlmOHUqpHVZ5DLiFAyQWCZryCIlcKBTDBqyEgGsi1NMut2Fas8cI0JJI0tYiQuBrY6N6OIAhxIk2cFkE0b4lXwpeYM80asqHSoW3m8P4dgODxBFyVqZDTRRhe9PDL/tykpY9uoVCni1PETt2BHXGHpkcokEI9SckkIAAAA') format('woff2'), url('//at.alicdn.com/t/font_1117508_wxidm5ry7od.woff?t=1554098097778') format('woff'), url('//at.alicdn.com/t/font_1117508_wxidm5ry7od.ttf?t=1554098097778') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */ url('//at.alicdn.com/t/font_1117508_wxidm5ry7od.svg?t=1554098097778#icon') format('svg'); /* iOS 4.1- */ } .icon { font-family: "icon" !important; font-size: 16px; font-style: normal; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } .icon-info:before { content: "\\e72a"; } .icon-success:before { content: "\\e730"; } .icon-loading:before { content: "\\e6a6"; } .icon-close:before { content: "\\e6e9"; } .icon-warning:before { content: "\\ebad"; } .icon-error:before { content: "\\ebb2"; } `; let bs_style_sheet = document.createElement('style'); bs_style_sheet.innerHTML = bs_style_css; document.body.appendChild(bs_style_sheet); }; /*****************************配置对话框函数*************************/ var isButtonClicked = false; function openConfigDialog() { if (isButtonClicked) { return; // 如果按钮已被点击,则忽略后续点击事件 } isButtonClicked = true; // 创建一个遮罩层及其内部的对话框 const bs_overlay_html = ` <div id="bs_dialog"> <h2 style="margin-top: -4px;">BlockSpeech <a title="前往插件详情页面查看更多插件信息"style="font-size: 8px; color: #17abe3; text-decoration: underline;"target="_blank"href="https://greasyfork.org/zh-CN/scripts/472846">插件信息</a> </h2> <table id="row_insert"> <tr> <td>ID:</td> <td><input id="bs_input" type="text" placeholder="请输入需要屏蔽的ID"></td> <td><button id="bs_btn_insert">添加</button></td> </tr> </table> <table id="bs_table"></table> <div id="bs_tool_row"><button id="bs_btn_save">保存</button><button id="bs_btn_clear">清空</button></div> <div id="bs_btn_close"></div> </div> `; let bs_overlay = document.createElement('div'); bs_overlay.id = 'bs_overlay'; bs_overlay.innerHTML = bs_overlay_html; document.body.appendChild(bs_overlay); /****************************************各个function*****************************************/ // 获取全局变量bs_table let bs_table = document.getElementById('bs_table'); // 清空表格 function bs_tableClear() { bs_table.innerHTML = ''; } // 保存表格到GM_value function bs_tableSave() { let bs_list = []; document.querySelectorAll('.bs_user_id').forEach(function (item) { bs_list.unshift(item.textContent); }) GM_setValue("bs_list", bs_list); console.log("【blockspeech】list:" + bs_list); console.log("【blockspeech】save ok"); stopObserver(); startObserver(bs_list); } // 删除行 function bs_deleteRow(btn_del) { // 获取按钮的父元素<tr> let row_del = btn_del.parentNode.parentNode; // 从表格中删除该行 row_del.parentNode.removeChild(row_del); } // 插入行 function bs_insertRow(userid) { let new_row = bs_table.insertRow(0); let cell1 = new_row.insertCell(0); cell1.className = 'bs_user_id'; cell1.innerHTML = userid; let cell2 = new_row.insertCell(1); let bs_btn_del = document.createElement("button"); bs_btn_del.innerText = "删除"; // 添加点击事件 bs_btn_del.addEventListener("click", function () { bs_deleteRow(this); }); cell2.appendChild(bs_btn_del); } // 判断input内容 function judgeIfok(new_id) { if (new_id == '') { console.log("【blockspeech】user id can not be null"); message.show({ type: 'warning', text: 'ID内容不能为空', }); return false; } let user_id_objlist = document.querySelectorAll('.bs_user_id'); let user_id_list = []; user_id_objlist.forEach(function (obj) { user_id_list.push(obj.innerHTML); }) if (user_id_list.includes(new_id)) { console.log("【blockspeech】user id had been added"); message.show({ type: 'info', text: '此ID已被添加,请勿重复添加', }); return false; } return true; } bs_Init(); // 初始化表格 function bs_Init() { bs_tableClear(); let bs_list = GM_getValue("bs_list"); if (bs_list) { bs_list.forEach(function (item) { bs_insertRow(item); }); } } /****************************************添加点击事件*****************************************/ // 给插入按钮添加点击事件 document.getElementById('bs_btn_insert').addEventListener("click", function () { let bs_input = document.getElementById('bs_input'); if (judgeIfok(bs_input.value.trim())) { bs_insertRow(bs_input.value.trim()); message.show({ type: 'success', text: '添加"' + bs_input.value.trim() + '"成功', }); } bs_input.value = ''; }); // 给保存按钮添加点击事件 document.getElementById('bs_btn_save').addEventListener("click", () => { bs_tableSave(); message.show({ type: 'success', text: '保存成功', }); }); // 给清空按钮添加点击事件 document.getElementById('bs_btn_clear').addEventListener("click", () => { bs_tableClear(); message.show({ type: 'success', text: '清空列表成功', }); }); // 给关闭按钮添加点击事件 let bs_btn_close = document.getElementById('bs_btn_close'); bs_btn_close.addEventListener('click', function () { bs_overlay.remove(); isButtonClicked = false; }); } function bs_startMonitor() { // 直播间内执行 if (document.querySelector('.layout-Player-aside')) {// 如果页面有侧边栏则该页面为直播间 console.log("【blockspeech】Is live room."); let bs_list = GM_getValue('bs_list'); if (bs_list) { setTimeout(() => startObserver(bs_list), 8000); } } } function startObserver(bs_list = GM_getValue('bs_list')) { let chat_list = document.querySelector("#js-barrage-list"); if (chat_list) { // 创建 MutationObserver 对象 bs_observer = new MutationObserver(function (mutations) { // 遍历每个变化 mutations.forEach(function (mutation) { // 遍历每个被添加的元素 mutation.addedNodes.forEach(function (node) { // 判断节点元素 if (node.nodeType === 1 && node.nodeName === 'LI' && node.classList.contains('Barrage-listItem')) { // 获取用户昵称对象 let userchat = node.querySelector(".Barrage-nickName"); // 获取第用户昵称 文本内容 let userid = userchat.title; if (bs_list.includes(userid)) { node.remove(); console.log("【blockspeech】remove chat from " + userid + " ok"); } } }); }); }); // 配置 MutationObserver 对象 let config = { childList: true, subtree: true }; // 在聊天信息列表上开始监视变化 bs_observer.observe(chat_list, config); console.log("【blockspeech】strat observer success..."); message.show({ type: 'success', text: '屏蔽ID消息开启成功', }); } else { console.log("【blockspeech】因网络原因屏蔽失败,请刷新页面或者点击设置页面的保存按钮重新加载屏蔽"); } } // startObserver -- funciton function stopObserver() { if (bs_observer) { bs_observer.disconnect(); bs_observer = null; console.log('【blockspeech】Stop observer ok'); } else { console.log('【blockspeech】there is no observer task'); } } /********************************** message_js****************************/ class Message { constructor() { const containerId = 'message-container'; this.containerEl = document.getElementById(containerId); if (!this.containerEl) { this.containerEl = document.createElement('div'); this.containerEl.id = containerId; document.body.appendChild(this.containerEl) } } show({ type = 'info', text = '', duration = 2000, closeable = false }) { let messageEl = document.createElement('div'); messageEl.className = 'message move-in'; messageEl.innerHTML = `<span class="icon icon-${type}"></span><div class="text">${text}</div>`; if (closeable) { let closeEl = document.createElement('div'); closeEl.className = 'close icon icon-close'; messageEl.appendChild(closeEl); closeEl.addEventListener('click', () => { this.close(messageEl) }) } this.containerEl.appendChild(messageEl); if (duration > 0) { setTimeout(() => { this.close(messageEl) }, duration) } } close(messageEl) { messageEl.className = messageEl.className.replace('move-in', ''); messageEl.className += 'move-out'; messageEl.addEventListener('animationend', () => { messageEl.setAttribute('style', 'height: 0; margin: 0') }); messageEl.addEventListener('transitionend', () => { messageEl.remove() }) } } // 主函数main function main() { // 初始化css bsStyleInit(); // 消息对象实例化 message = new Message(); // 添加配置选项 GM_registerMenuCommand('配置屏蔽ID', openConfigDialog); // 启动监听 window.onload = function () { console.log("【blockspeech】window.onload..."); bs_startMonitor(); } } // 进入main main(); } // window.onload })(); // 主function -- function