Greasy Fork

Greasy Fork is available in English.

优化Bilibili

优化Bilibili主页和文章页面

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

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==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);  // 每秒检查一次
    }
})();