// ==UserScript== // @name 斗鱼全等级弹幕屏蔽 // @namespace https://www.liebev.site // @version 1.1 // @description douyu斗鱼,高级弹幕屏蔽,突破30级等级屏蔽限制,房管模拟器 // @author LiebeV // @license MIT: Copyright (c) 2023 LiebeV // @match https://www.douyu.com/* // @icon https://www.google.com/s2/favicons?sz=64&domain=douyu.com // @grant GM_registerMenuCommand // @grant GM_getValue // @grant GM_setValue // @downloadURL none // ==/UserScript== "use strict"; // v1.1,更新了代码逻辑。添加了一个“模”按钮,用于取代GM_registerMenuCommand。添加了移除id的功能 // 已知问题,弹幕瞬间过多时,rightMO会挂(无解) // 更新计划,添加快速添加id的功能 let userBannedIds = GM_getValue("bannedIds", []); let bannedIds = userBannedIds; let dmCache = []; //尝试获取弹幕区 async function getRightList() { // console.log('高级弹幕屏蔽初始化成功'); let ulList; let count = 0; while (!ulList && count < 20) { ulList = document.getElementById("js-barrage-list"); console.log("尝试获取弹幕区..."); if (!ulList) { console.log(`失败,等待1秒钟再尝试获取,剩余重试:${20 - count}`); await new Promise((resolve) => setTimeout(resolve, 1000)); count++; } } if (!ulList) { console.log("无法获取Right弹幕区,请刷新网页"); } else { console.log("已获Right取弹幕区,准备开启rightMO感知"); console.log(ulList); } return ulList; } // 右侧 mutation observer async function rightMO() { const ulList = await getRightList(); // console.log('Right感知准备完成'); const rightObserver = new MutationObserver(function (mutations) { mutations.forEach(function (mutation) { mutation.addedNodes.forEach(function (righNode) { if (righNode.nodeName === "LI") { // console.log('\x1b[32m%s\x1b[0m', 'Right弹幕区感知到新弹幕:'); // console.log(righNode); rightCheck(righNode); } }); }); }); const config = { childList: true }; rightObserver.observe(ulList, config); console.log("Right感知挂载完成,等待新弹幕..."); } // 检查id,获取发言内容,right2mid async function rightCheck(righNode) { const userId = righNode.querySelector("span.Barrage-nickName[title]").getAttribute("title"); if (userBannedIds.includes(userId)) { righNode.style.display = "none"; const danmu = righNode.querySelector("span.Barrage-content").textContent.trim(); // console.log("rightcheck:" + danmu); if (dmCache.includes(danmu)) { const xpath = `//div[contains(text(), "${danmu}")]`; // const midDivElement = document.evaluate(xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; const snapshotResult = document.evaluate( xpath, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null ); for (let i = 0; i < snapshotResult.snapshotLength; i++) { const midDivElement = snapshotResult.snapshotItem(i); midDivElement.parentElement.style.display = "none"; } } console.log(`"${userId}" 的发言已被屏蔽!`); } } // 获取飘屏弹幕区 async function getMainList() { let divList; let count = 0; // 尝试等待页面加载 20s while (!divList && count < 20) { divList = document.querySelector(".danmu-e7f029"); if (!divList) { await new Promise((resolve) => setTimeout(resolve, 1000)); count++; } } if (!divList) { console.log("无法获取飘屏弹幕区,请刷新网页"); } else { console.log("已获取飘屏弹幕区,准备开启Mutation感知"); console.log(divList); } return divList; } // 飘屏mutation observer async function midMO() { const middivList = await getMainList(); // console.log('mid感知准备完成'); const midObserver = new MutationObserver(function (mutations) { mutations.forEach(function (mutation) { mutation.addedNodes.forEach(function (midNode) { if (midNode.nodeName === "DIV") { // console.log('\x1b[32m%s\x1b[0m', '飘屏区感知到新弹幕:'); // console.log(midNode); getMidText(midNode); } }); }); }); const midConfig = { childList: true }; midObserver.observe(middivList, midConfig); console.log("mid感知挂载完成,等待新弹幕..."); } // 获取飘屏区弹幕内容,存入临时数组,等待比对 async function getMidText(midNode) { const midText = midNode.querySelector("div.text-edf4e7").textContent; // console.log(midText); dmCache.push(midText); // console.log(dmCache); if (dmCache.length > 10) { dmCache.splice(0, dmCache.length); } } //通过setValue像存储器添加id async function addId(userIdInput) { // console.log('addId接收到传入'); if (!bannedIds.includes(userIdInput)) { bannedIds.push(userIdInput); console.log(`已添加屏蔽用户: ${userIdInput}`); GM_setValue("bannedIds", bannedIds); } else { const index = bannedIds.indexOf(userIdInput); if (index !== -1) { bannedIds.splice(index, 1); console.log(`已移除屏蔽用户 ${userIdInput}`); GM_setValue("bannedIds", bannedIds); } } } async function showSettings() { let message = "当前被您屏蔽的用户ID列表:\n"; const idList = GM_getValue("bannedIds", []); for (let i = 0; i < idList.length; i++) { message += `${i + 1}. ${idList[i]}\n`; } const userIdInput = prompt(`${message}\n请输入要屏蔽发言的用户id`); if (userIdInput) { console.log("接收到用户id"); addId(userIdInput); } } GM_registerMenuCommand("添加屏蔽用户", showSettings); async function menu() { await rightMO(); await midMO(); const container = document.querySelector(".ChatToolBar"); const mnq = document.createElement("div"); mnq.classList.add("liebevmnq"); mnq.style.display = "inline-block"; mnq.style.verticalAlign = "middle"; mnq.style.width = "18px"; mnq.style.height = "18px"; mnq.style.marginRight = "8px"; const inner = document.createElement("div"); inner.classList.add("liebevmnqInner"); inner.style.width = "100%"; inner.style.height = "100%"; const btn = document.createElement("div"); btn.classList.add("liebevmnqBtn"); btn.style.position = "relative"; btn.style.color = "#fff"; btn.style.background = "#bbb"; btn.style.borderRadius = "4px"; btn.style.cursor = "pointer"; btn.style.textAlign = "center"; btn.style.userSelect = "none"; const moniqi = document.createElement("span"); moniqi.innerText = "模"; container.appendChild(mnq); mnq.appendChild(inner); inner.appendChild(btn); btn.appendChild(moniqi); btn.addEventListener("click", showmenu); } async function showmenu() { const btn = document.querySelector("div.liebevmnq"); const checker = document.querySelector("div.mnqHeader"); if (checker) { checker.remove(); } else { const commandmenu = document.createElement("div"); commandmenu.classList.add("mnqHeader"); Object.assign(commandmenu.style, { position: "absolute", left: "-8px", right: "-8px", bottom: "32px", boxShadow: "0 -3px 6px rgba(0,0,0,.1)", border: "1px solid #e5e5e5", borderTopRightRadius: "8px", borderTopLeftRadius: "8px", animation: "slideUp .3s cubic-bezier(.22,.58,.12,.98) forwards", backgroundColor: "#fff", }); const head = document.createElement("div"); head.classList.add("Header-head"); Object.assign(head.style, { height: "45px", lineHeight: "45px", color: "#333", fontSize: "16px", padding: "0 38px 0 16px", backgroundColor: "#f4f4f4", position: "relative", borderTopLeftRadius: "8px", borderTopRightRadius: "8px", userSelect: "none", }); head.innerText = "LiebeV房管模拟器"; const panel = document.createElement("div"); panel.classList.add("mnqPanel"); Object.assign(panel.style, { padding: "0 0 0 16px", height: "206px", boxSizing: "border-box", overflowY: "auto", }); const idList = GM_getValue("bannedIds", []); panel.innerText = `${idList.map((id, i) => `${i + 1}. ${id}`).join("\n")}`; const input = document.createElement("div"); input.classList.add("mnqinput"); Object.assign(input.style, { position: "relative", margin: "0 16px", borderTop: "1px solid #e8e8e8", height: "46px", background: "#fff", lineHeight: "46px", }); const textInput = document.createElement("input"); textInput.type = "text"; textInput.placeholder = "请输入您要屏蔽/移除的用户ID"; Object.assign(textInput.style, { width: "80%", height: "100%", border: "none", outline: "none", paddingLeft: "10px", fontSize: "16px", }); textInput.addEventListener("keydown", function (event) { if (event.key === "Enter") { addId(event.target.value); event.target.value = ""; } }); btn.appendChild(commandmenu); commandmenu.appendChild(head); commandmenu.appendChild(panel); commandmenu.appendChild(input); input.appendChild(textInput); } } (function () { menu(); })();