B站云顶之弈内容过滤

优化版:B站视频播放页检测到云顶之弈内容直接关闭,其他页面屏蔽相关内容

// ==UserScript==
// @license      MIT
// @name         B站云顶之弈内容过滤
// @namespace    http://tampermonkey.net/
// @version      0.2
// @description  优化版:B站视频播放页检测到云顶之弈内容直接关闭,其他页面屏蔽相关内容
// @author       You
// @match        *://*.bilibili.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=bilibili.com
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    // 配置项
    const config = {
        // 检查间隔(毫秒),避免过于频繁的检查
        checkInterval: 1000,
        // 防抖延迟(毫秒)
        debounceDelay: 300,
        // 最大同时处理元素数量
        maxProcessElements: 20
    };

    // 云顶之弈相关关键词列表 - 优化为正则表达式提高效率
    const keywords = [
        "云顶之奕", "云顶", "云顶弈", "云顶之弈",
        "TFT", "Teamfight Tactics", "金铲铲", "金铲铲之战",
        "九五", "九五至尊", "九四", "八四", "七三",
        "D牌", "升本", "刷牌", "搜牌", "抽牌",
        "羁绊", "特质", "职业", "种族", "星系",
        "选秀", "装备", "海克斯", "拼多多", "赌狗",
        "恰分", "烂分", "天胡", "锁血", "三星"
    ];

    // 编译为正则表达式,提高匹配效率
    const keywordRegex = new RegExp(keywords.join('|'), 'i');

    // 检查文本是否包含任何关键词(优化版)
    function hasRelatedContent(text) {
        if (!text || typeof text !== 'string') return false;
        return keywordRegex.test(text);
    }

    // 防抖函数 - 减少重复执行
    function debounce(func, delay) {
        let timeout;
        return function(...args) {
            clearTimeout(timeout);
            timeout = setTimeout(() => func.apply(this, args), delay);
        };
    }

    // 尝试关闭页面(优化版)
    function closePage() {
        try {
            // 只在非顶级窗口中尝试关闭,减少浏览器安全限制影响
            if (window.top === window.self) {
                // 对于顶级窗口,使用更温和的方式
                window.location.replace("about:blank");
            } else {
                window.close();
                setTimeout(() => {
                    if (!window.closed) {
                        window.location.replace("about:blank");
                    }
                }, 100);
            }
        } catch (e) {
            console.log("关闭页面失败:", e);
        }
    }

    // 屏蔽元素(优化版)
    function blockElement(element) {
        // 避免重复屏蔽
        if (element.dataset.yundingBlocked) return;
        element.dataset.yundingBlocked = "true";

        // 简化屏蔽层样式,减少渲染负担
        const blockDiv = document.createElement('div');
        blockDiv.style.cssText = `
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: #f5f5f5;
            display: flex;
            align-items: center;
            justify-content: center;
            border: 1px solid #ddd;
            z-index: 9999;
            font-size: 14px;
        `;
        blockDiv.textContent = '已屏蔽云顶之弈相关内容';

        // 只在需要时修改定位
        if (!['absolute', 'fixed', 'relative'].includes(element.style.position)) {
            element.style.position = 'relative';
        }

        // 使用insertBefore而不是appendChild,避免被内部元素覆盖
        if (element.firstChild) {
            element.insertBefore(blockDiv, element.firstChild);
        } else {
            element.appendChild(blockDiv);
        }

        // 禁用交互
        element.style.pointerEvents = 'none';
    }

    // 处理视频播放页面(优化版)
    function handleVideoPage() {
        try {
            // 只检查一次标题,如果有则关闭,避免重复检查
            const titleElement = document.querySelector('h1.video-title');
            if (titleElement && hasRelatedContent(titleElement.innerText)) {
                closePage();
                return true;
            }

            // 简介内容检查(防抖处理)
            const checkDesc = debounce(() => {
                const descElement = document.querySelector('.video-desc');
                if (descElement && hasRelatedContent(descElement.innerText)) {
                    closePage();
                }
            }, config.debounceDelay);

            // 监控简介区域变化
            const descObserver = new MutationObserver(checkDesc);
            const descContainer = document.querySelector('.video-desc-container') || document.body;
            descObserver.observe(descContainer, {
                childList: true,
                subtree: true,
                characterData: true
            });

            // 初始检查简介
            checkDesc();

            // 5秒后停止监控,避免长期运行
            setTimeout(() => descObserver.disconnect(), 5000);

        } catch (e) {
            console.log("视频页面处理错误:", e);
        }
    }

    // 处理非视频页面内容(优化版)
    function processNonVideoContent() {
        try {
            // 更精确的选择器,减少匹配范围
            const contentSelectors = [
                '.bili-video-card:not([data-yunding-blocked])',
                '.article-item:not([data-yunding-blocked])',
                '.live-card:not([data-yunding-blocked])',
                '.video-item:not([data-yunding-blocked])'
            ];

            const elements = [];
            contentSelectors.forEach(selector => {
                // 限制每次查询的数量,避免一次性处理过多元素
                const nodes = Array.from(document.querySelectorAll(selector));
                elements.push(...nodes.slice(0, config.maxProcessElements));
            });

            // 批量处理元素
            elements.forEach(item => {
                if (hasRelatedContent(item.innerText)) {
                    blockElement(item);
                }
            });
        } catch (e) {
            console.log("内容处理错误:", e);
        }
    }

    // 主处理函数
    function main() {
        const url = window.location.href;

        // 判断是否为视频播放页面
        if (url.includes('/video/') || url.includes('/bangumi/') || url.includes('/movie/')) {
            if (handleVideoPage()) return;
        } else {
            // 初始处理
            processNonVideoContent();

            // 优化监控范围:只监控内容列表容器,而非整个页面
            const contentContainers = [
                '#i_cecream', // 首页内容区
                '.container', // 通用容器
                '.list-box',  // 列表容器
                '.video-list' // 视频列表
            ];

            const observeTargets = [];
            contentContainers.forEach(selector => {
                const el = document.querySelector(selector);
                if (el) observeTargets.push(el);
            });

            // 如果没有找到特定容器,才监控body
            const target = observeTargets.length > 0 ? observeTargets[0] : document.body;

            // 优化监控配置,减少触发次数
            const observer = new MutationObserver(debounce(() => {
                processNonVideoContent();
            }, config.debounceDelay));

            observer.observe(target, {
                childList: true,
                subtree: true,
                attributes: false,
                characterData: false
            });

            // 定时检查作为补充,但降低频率
            const checkInterval = setInterval(() => {
                processNonVideoContent();
            }, config.checkInterval);

            // 页面离开时清理资源
            window.addEventListener('beforeunload', () => {
                observer.disconnect();
                clearInterval(checkInterval);
            });
        }
    }

    // 确保页面加载到一定阶段再执行,避免过早运行
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', () => {
            // 再延迟一点执行,让页面主要内容加载完成
            setTimeout(main, 1000);
        });
    } else {
        setTimeout(main, 500);
    }
})();