Greasy Fork

Greasy Fork is available in English.

优化Bilibili

优化Bilibili主页和文章页面

当前为 2024-08-12 提交的版本,查看 最新版本

// ==UserScript==
// @name         优化Bilibili
// @namespace    http://tampermonkey.net/
// @version      1.1
// @description  优化Bilibili主页和文章页面
// @match        https://www.bilibili.com/
// @match        *://www.bilibili.com/read/*
// @grant        GM_setValue
// @grant        GM_getValue
// ==/UserScript==

(function() {
    'use strict';

    // 从GM_getValue获取保存的状态,如果没有保存过,默认为false(关闭状态)
    let isAdRemovalEnabled = GM_getValue('bilibiliAdRemovalEnabled', false);
    let isSwiperRemovalEnabled = GM_getValue('bilibiliSwiperRemovalEnabled', false);
    let isNonVideoCardRemovalEnabled = GM_getValue('bilibiliNonVideoCardRemovalEnabled', false);
    let isCopySuffixRemovalEnabled = GM_getValue('bilibiliCopySuffixRemovalEnabled', false);

    // 创建设置按钮和开关控件
    function createSettingsButton() {
        const settingsButton = document.createElement('button');
        settingsButton.innerHTML = `
            <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                <circle cx="12" cy="12" r="3"></circle>
                <path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path>
            </svg>
        `;
        settingsButton.style.cssText = `
            position: fixed;
            bottom: 20px;
            right: 20px;
            z-index: 10000;
            width: 40px;
            height: 40px;
            background-color: #00a1d6;
            color: white;
            border: none;
            border-radius: 50%;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            box-shadow: 0 2px 5px rgba(0,0,0,0.3);
        `;
        document.body.appendChild(settingsButton);

        const toggleContainer = document.createElement('div');
        toggleContainer.style.cssText = `
            position: fixed;
            bottom: 70px;
            right: 20px;
            z-index: 9999;
            background-color: white;
            padding: 10px;
            border-radius: 5px;
            box-shadow: 0 0 5px rgba(0,0,0,0.3);
            display: none;
        `;
        toggleContainer.innerHTML = `
            <label style="display: block; margin-bottom: 10px;">
                <input type="checkbox" id="adRemovalToggle" ${isAdRemovalEnabled ? 'checked' : ''}>
                移除广告
            </label>
            <label style="display: block; margin-bottom: 10px;">
                <input type="checkbox" id="swiperRemovalToggle" ${isSwiperRemovalEnabled ? 'checked' : ''}>
                移除轮播图
            </label>
            <label style="display: block; margin-bottom: 10px;">
                <input type="checkbox" id="nonVideoCardRemovalToggle" ${isNonVideoCardRemovalEnabled ? 'checked' : ''}>
                移除视频以外的其他卡片
            </label>
            <label style="display: block;">
                <input type="checkbox" id="copySuffixRemovalToggle" ${isCopySuffixRemovalEnabled ? 'checked' : ''}>
                去除文章复制引用后缀
            </label>
        `;
        document.body.appendChild(toggleContainer);

        settingsButton.addEventListener('click', function() {
            toggleContainer.style.display = toggleContainer.style.display === 'none' ? 'block' : 'none';
        });

        // 添加广告移除开关事件监听器
        const adCheckbox = document.getElementById('adRemovalToggle');
        adCheckbox.addEventListener('change', function() {
            isAdRemovalEnabled = this.checked;
            GM_setValue('bilibiliAdRemovalEnabled', isAdRemovalEnabled);
            if (isAdRemovalEnabled) {
                removeAds();
            } else {
                location.reload();
            }
        });

        // 添加轮播图移除开关事件监听器
        const swiperCheckbox = document.getElementById('swiperRemovalToggle');
        swiperCheckbox.addEventListener('change', function() {
            isSwiperRemovalEnabled = this.checked;
            GM_setValue('bilibiliSwiperRemovalEnabled', isSwiperRemovalEnabled);
            if (isSwiperRemovalEnabled) {
                removeSwiper();
            } else {
                location.reload();
            }
        });

        // 添加非视频卡片移除开关事件监听器
        const nonVideoCardCheckbox = document.getElementById('nonVideoCardRemovalToggle');
        nonVideoCardCheckbox.addEventListener('change', function() {
            isNonVideoCardRemovalEnabled = this.checked;
            GM_setValue('bilibiliNonVideoCardRemovalEnabled', isNonVideoCardRemovalEnabled);
            if (isNonVideoCardRemovalEnabled) {
                removeNonVideoCards();
            } else {
                location.reload();
            }
        });

        // 添加去除文章复制引用后缀开关事件监听器
        const copySuffixCheckbox = document.getElementById('copySuffixRemovalToggle');
        copySuffixCheckbox.addEventListener('change', function() {
            isCopySuffixRemovalEnabled = this.checked;
            GM_setValue('bilibiliCopySuffixRemovalEnabled', isCopySuffixRemovalEnabled);
            removeCopySuffix();
        });
    }

    // 主页功能
    if (window.location.href === 'https://www.bilibili.com/') {
        function removeAds() {
            if (!isAdRemovalEnabled) return;

            // 处理被feed-card包裹的情况
            const feedCards = document.querySelectorAll('.feed-card');
            feedCards.forEach(card => {
                const videoCard = card.querySelector('.bili-video-card.is-rcmd');
                if (videoCard && !videoCard.classList.contains('enable-no-interest')) {
                    card.remove();
                }
            });

            // 处理直接的bili-video-card
            const directVideoCards = document.querySelectorAll('.bili-video-card.is-rcmd:not(.enable-no-interest)');
            directVideoCards.forEach(card => {
                if (!card.parentElement.classList.contains('feed-card')) {
                    card.remove();
                }
            });
        }

        function removeSwiper() {
            if (!isSwiperRemovalEnabled) return;

            // 删除轮播图
            const swiper = document.querySelector('.recommended-swipe.grid-anchor');
            if (swiper) {
                swiper.remove();
            }

            // 删除特定的CSS规则
            const style = document.createElement('style');
            style.textContent = `
                .recommended-container_floor-aside .container>*:nth-of-type(n + 8) {
                    margin-top: 0 !important;
                }
                .recommended-container_floor-aside .container.is-version8>*:nth-of-type(n + 13) {
                    margin-top: 0 !important;
                }
            `;
            document.head.appendChild(style);
        }

        function removeNonVideoCards() {
            if (!isNonVideoCardRemovalEnabled) return;

            // 删除 floor-single-card 类的元素
            const nonVideoCards = document.querySelectorAll('.floor-single-card');
            nonVideoCards.forEach(card => {
                card.remove();
            });

            // 删除 bili-live-card 类的元素(直播卡片)
            const liveCards = document.querySelectorAll('.bili-live-card');
            liveCards.forEach(card => {
                card.remove();
            });
        }

        // 初始执行
        createSettingsButton();
        if (isAdRemovalEnabled) {
            removeAds();
        }
        if (isSwiperRemovalEnabled) {
            removeSwiper();
        }
        if (isNonVideoCardRemovalEnabled) {
            removeNonVideoCards();
        }

        // 创建一个MutationObserver来监视DOM变化
        const observer = new MutationObserver((mutations) => {
            mutations.forEach((mutation) => {
                if (mutation.type === 'childList') {
                    removeAds();
                    removeSwiper();
                    removeNonVideoCards();
                }
            });
        });

        // 配置观察选项
        const config = { childList: true, subtree: true };

        // 开始观察文档主体
        observer.observe(document.body, config);
    }

    // 文章页面功能
    if (window.location.href.includes('www.bilibili.com/read/')) {
        // 创建设置按钮
        createSettingsButton();

        // 移除文本复制后缀
        function removeCopySuffix() {
            if (isCopySuffixRemovalEnabled) {
                window.addEventListener('copy', function(e) {
                    e.stopPropagation();
                }, true);
            } else {
                window.removeEventListener('copy', function(e) {
                    e.stopPropagation();
                }, true);
            }
        }

        // 在页面加载完成后执行removeCopySuffix
        window.addEventListener('load', removeCopySuffix);

        // 监听设置变化并重新应用removeCopySuffix
        const checkInterval = setInterval(() => {
            const currentSetting = GM_getValue('bilibiliCopySuffixRemovalEnabled', false);
            if (currentSetting !== isCopySuffixRemovalEnabled) {
                isCopySuffixRemovalEnabled = currentSetting;
                removeCopySuffix();
            }
        }, 1000);  // 每秒检查一次
    }
})();