斗鱼屏蔽ID消息(blockspeech)

根据ID屏蔽直播间的发言(持久化存储、傻瓜式使用/管理)

Instalar este script¿?
Script recomendado por el autor

Puede que también te guste 斗鱼(ClearAds)【去广告&&内容精简】.

Instalar este script
// ==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