微博荐读屏蔽脚本

屏蔽最新微博分组页面的荐读推广

// ==UserScript==
// @name         微博荐读屏蔽脚本
// @namespace    https://github.com/catscarlet/weibo-selection-killer
// @description  屏蔽最新微博分组页面的荐读推广
// @version      0.0.2
// @author       catscarlet
// @license      GNU Affero General Public License v3.0
// @match        https://weibo.com/*
// @run-at       document-end
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    // 防抖函数 - 控制URL变化处理频率
    function debounce(func, wait) {
        let timeout;
        return function(...args) {
            clearTimeout(timeout);
            timeout = setTimeout(() => func.apply(this, args), wait);
        };
    }

    // 节流函数 - 控制DOM变化处理频率
    function throttle(func, limit) {
        let lastCall = 0;
        return function(...args) {
            const now = Date.now();
            if (now - lastCall >= limit) {
                lastCall = now;
                return func.apply(this, args);
            }
        };
    }

    // 检查URL是否符合目标模式
    function isTargetUrl() {
        return window.location.href.startsWith('https://weibo.com/mygroups');
    }

    // 创建并添加覆盖层,确保不会重复添加
    function createOverlay(articleElement) {
        // 检查是否已添加过覆盖层,避免重复执行
        if (articleElement.classList.contains('has-custom-overlay')) {
            //console.log(articleElement);
            //console.log('覆盖层已添加,跳过。');
            return;
        }

        console.log(articleElement);
        console.log('添加覆盖层');
        // 标记元素已添加覆盖层
        articleElement.classList.add('has-custom-overlay');

        // 设置元素定位方式
        const style = window.getComputedStyle(articleElement);
        if (style.position === 'static') {
            articleElement.style.position = 'relative';
        }

        // 创建SVG覆盖层
        const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
        svg.setAttribute('class', 'custom-overlay');
        svg.style.position = 'absolute';
        svg.style.top = '0';
        svg.style.left = '0';
        svg.style.width = '100%';
        svg.style.height = '100%';
        svg.style.pointerEvents = 'auto'; // 阻止点击穿透
        svg.style.zIndex = '100'; // 确保覆盖在上方

        // 创建深灰色矩形(opacity=0.99)
        const rectElement = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
        rectElement.setAttribute('width', '100%');
        rectElement.setAttribute('height', '100%');
        rectElement.setAttribute('fill', 'gray');
        rectElement.setAttribute('opacity', '0.99');

        svg.appendChild(rectElement);
        articleElement.appendChild(svg);

        // 额外确保元素无法被点击
        articleElement.style.pointerEvents = 'none';
    }

    // 移除所有覆盖层并清除标记
    function removeAllOverlays() {
        document.querySelectorAll('.custom-overlay').forEach(overlay => {
            const article = overlay.closest('article');
            if (article) {
                article.classList.remove('has-custom-overlay');
                article.style.pointerEvents = '';
            }
            overlay.remove();
        });
    }

    // 处理元素变化的节流版本
    const handleElementChanges = throttle(function() {
        const container = document.querySelector('.Scroll_wrap_ObsGW');
        if (!container) {
            return;
        }

        // 查找所有包含目标图标的元素
        const targetIcons = container.querySelectorAll('.morepop_cross_1Q1PF');

        targetIcons.forEach(icon => {
            const article = icon.closest('article');
            if (article) {
                //console.log('发现 article');
                //console.log(article);
                createOverlay(article);
            } else {
                //console.log('未检测到 article');
            }
        });
    }, 300); // 300ms内最多执行一次

    let domObserver;

    // 启动DOM变化监控
    function startDomObserver() {
        if (domObserver) {
            console.log('停止已有的 .Scroll_wrap_ObsGW 监视');
            domObserver.disconnect();
        }

        const container = document.querySelector('.Scroll_wrap_ObsGW');
        if (container) {
            console.log('检测到 .Scroll_wrap_ObsGW,开始监视');
            domObserver = new MutationObserver(handleElementChanges);

            const config = {
                childList: true,
                subtree: true,
                attributes: false,
                characterData: false,
            };

            domObserver.observe(container, config);
            handleElementChanges(); // 初始检查
        } else {
            // 容器不存在时重试
            console.log('未检测到 .Scroll_wrap_ObsGW');
            setTimeout(startDomObserver, 1000);
        }
    }

    // 停止DOM变化监控
    function stopDomObserver() {
        if (domObserver) {
            domObserver.disconnect();
            domObserver = null;
            //removeAllOverlays();
        }
    }

    // 处理URL变化的防抖版本
    const handleUrlChange = debounce(function() {
        if (isTargetUrl()) {
            startDomObserver();
        } else {
            console.log('分组不匹配,startsWith(https://weibo.com/mygroups) false');
            stopDomObserver();
        }
    }, 400); // 400ms防抖

    // 初始化URL变化监控
    function initUrlMonitor() {
        console.log('加载 weibo-selection-killer');
        handleUrlChange(); // 初始检查

        // 监听浏览器历史变化
        window.addEventListener('popstate', handleUrlChange);

        // 重写history方法以监控URL变化
        const originalPushState = history.pushState;
        history.pushState = function(...args) {
            originalPushState.apply(this, args);
            handleUrlChange();
        };

        const originalReplaceState = history.replaceState;
        history.replaceState = function(...args) {
            originalReplaceState.apply(this, args);
            handleUrlChange();
        };

        // 监控hash变化
        window.addEventListener('hashchange', handleUrlChange);
    }

    // 启动脚本
    initUrlMonitor();
})();