// ==UserScript== // @name 优化斗鱼web播放器 // @namespace https://www.liebev.site/monkey/better-douyu // @version 2.4 // @description douyu优化斗鱼web播放器(douyu.com),通过关闭直播间全屏时的背景虚化效果来解决闪屏卡顿的问题,屏蔽独立直播间的弹幕显示,移除文字水印,添加了一些快捷键。暴力隐藏页面元素,获得纯净观看体验 // @author LiebeV // @license MIT: Copyright (c) 2023-2025 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"; //更新日志,v2.4,匹配了更新后的新版web设计,将video背景重置为黑色,移除暴力隐藏相关代码,恢复了清晰度/线路相关快捷键 //**NOTE**:之于页面上其他不想要看到的东西,请搭配其他例如AdBlock之类的专业广告屏蔽器使用,本脚本仅提供暴力隐藏的功能 //**NOTE**:暴力隐藏无法撤销,请刷新网页以恢复 //已知问题,暴力重写导致的各种问题 //更新计划,无 // ********************一些有的没的的变量************************* const roomIds = GM_getValue("roomIds", []); const userRoomIds = roomIds; const listenerMap = new Map([ ["l", () => Danmu_control.rewrite_danmu_css()], ["u", () => Player_control.switch_full_mode()], ["w", () => Player_control.switch_wide_mode()], ["m", () => Better_multi.better_multi_mode()], ]); // 弹幕相关操作 class DanmuControl { constructor() { this.liebev = document.querySelector("#LiebeV"); } // 创建新的去背景虚化css(似乎现在只在某些分区保留了这个效果) with_danmu_css = () => { // 没有隐藏弹幕相关 return ` ._1Osm4fzGmcuRK9M8IVy3u6, .watermark-442a18, .is-ybHotDebate, .view-67255d.zoomIn-0f4645 { visibility: hidden !important; } #__video2 { background-color: rgb(0, 0, 0) !important; } .Barrage-main, .Barrage-topFloater, .comment-37342a { display: unset !important; } `; }; without_danmu_css = () => { // 隐藏了弹幕相关 return ` ._1Osm4fzGmcuRK9M8IVy3u6, .watermark-442a18, .is-ybHotDebate, .view-67255d.zoomIn-0f4645 { visibility: hidden !important; } #__video2 { background-color: rgb(0, 0, 0) !important; } .Barrage-main, .Barrage-topFloater, .comment-37342a { display: none !important; } `; }; /** * 将传入的 CSS 字符串解析后,直接以行内样式的方式应用到匹配到的元素上 * @param {string} cssText - 完整的 CSS 文本,例如:".foo{color:red !important} .bar{display:none !important}" */ applyInlineCss = (cssText) => { // 简易切分:先按 } 分割成多个规则片段 let ruleSegments = cssText.split("}"); ruleSegments.forEach(segment => { // 去掉首尾多余空白 segment = segment.trim(); if (!segment) return; // 再按 { 分割,前半部分是选择器(可能逗号分隔多组),后半部分是具体样式 let [selectorPart, stylePart] = segment.split("{"); if (!selectorPart || !stylePart) return; // 处理选择器,可能是多选择器逗号分隔 let selectors = selectorPart.split(","); // 处理style声明,可能有多条用 ; 分隔 let styleStr = stylePart.trim().replace(/;$/, ""); let styleArr = styleStr.split(";"); // 存储解析后的 [属性, 值, 是否important] let styleList = []; styleArr.forEach(s => { s = s.trim(); if (!s) return; // 以冒号切分 let [prop, val] = s.split(":"); if (!prop || !val) return; prop = prop.trim(); val = val.trim(); // 如果带了 !important 标记,就分离出来 let important = false; if (val.includes("!important")) { important = true; // 去除 !important val = val.replace(/!important\s*/i, "").trim(); } styleList.push({ prop, val, important }); }); // 将解析好的样式列表应用到匹配的每个元素的行内样式上 selectors.forEach(sel => { sel = sel.trim(); if (!sel) return; // querySelectorAll 找到该选择器对应的所有元素 let elements = document.querySelectorAll(sel); elements.forEach(el => { styleList.forEach(styleObj => { // 这里利用 style.setProperty(prop, val, priority) 来支持 !important el.style.setProperty(styleObj.prop, styleObj.val, styleObj.important ? "important" : ""); }); }); }); }); }; // 插入新的css(现改为调用 applyInlineCss,以提升优先级到行内样式) update_css = (tobe_css) => { // 可以保留或移除原有