// ==UserScript==
// @name 优化斗鱼web播放器
// @namespace https://www.liebev.site/monkey/better-douyu
// @version 2.3.1
// @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 https://update.greasyfork.icu/scripts/461630/%E4%BC%98%E5%8C%96%E6%96%97%E9%B1%BCweb%E6%92%AD%E6%94%BE%E5%99%A8.user.js
// @updateURL https://update.greasyfork.icu/scripts/461630/%E4%BC%98%E5%8C%96%E6%96%97%E9%B1%BCweb%E6%92%AD%E6%94%BE%E5%99%A8.meta.js
// ==/UserScript==
"use strict";
//更新日志,v2.3.1,提高了弹幕屏蔽css优先级
//**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()],
["k", () => Force_hide.force_clean_hide()],
["m", () => Better_multi.better_multi_mode()],
]);
const target_xpath = "/html/body/section/main/div[4]/div[1]/div[4]";
const TBN = "疑似金色悬停骑士团开播提醒:div.broadcastDiv-af5699/疑似周活跃榜提醒:div.DanmuEffectDom-container#douyu_room_normal_player_danmuDom>";
//
//
本房勇士团完成勇士团补给任务,获得1.2万流量卡(1天)X1,额外4500点战力点
//
// 

最强勇士团礼物冠名主播过载十五岁的涛妹开播了!点击围观吧!
// **************************************************************
// 弹幕相关操作
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;
}
.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;
}
.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) => {
// 可以保留或移除原有