优化Bilibili

优化Bilibili主页和文章页面

Fra 04.11.2024. Se den seneste versjonen.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         优化Bilibili
// @namespace    http://tampermonkey.net/
// @version      1.2
// @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 waitForPaletteButton = setInterval(() => {
            // 首先检查是否在主页上有adcard-content元素
            const adcardContent = document.querySelector('.adcard-content');
            if (adcardContent) {
                clearInterval(waitForPaletteButton);

                // 创建设置按钮
                const settingsButton = document.createElement('div');
                settingsButton.className = 'settings-button';
                settingsButton.innerHTML = `
                    <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" 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 = `
                    width: 40px;
                    height: 40px;
                    background: #fff;
                    border-radius: 6px;
                    margin-bottom: 12px;
                    cursor: pointer;
                    display: flex;
                    align-items: center;
                    justify-content: center;
                    color: #18191c;
                    box-shadow: 0 2px 4px rgba(0,0,0,.1);
                    transition: all .2s;
                `;

                // 添加悬停效果
                settingsButton.addEventListener('mouseover', function() {
                    this.style.color = '#00aeec';
                    this.style.backgroundColor = '#fff';
                });

                settingsButton.addEventListener('mouseout', function() {
                    this.style.color = '#18191c';
                    this.style.backgroundColor = '#fff';
                });

                // 替换adcard-content的内容
                adcardContent.innerHTML = '';
                adcardContent.appendChild(settingsButton);

                // 创建设置面板容器
                const toggleContainer = document.createElement('div');
                toggleContainer.id = 'settingsToggleContainer';
                toggleContainer.style.cssText = `
                    position: fixed;
                    top: 65%;
                    right: 1px;
                    transform: translateY(-50%);
                    z-index: 100000;
                    background-color: white;
                    padding: 15px;
                    border-radius: 8px;
                    box-shadow: 0 2px 10px rgba(0,0,0,0.2);
                    display: none;
                    min-width: 100px;
                `;

                // 添加设置面板内容
                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>
                `;

                // 添加点击事件
                settingsButton.addEventListener('click', function(e) {
                    e.preventDefault();
                    e.stopPropagation();
                    const container = document.getElementById('settingsToggleContainer');
                    if (container) {
                        const isVisible = container.style.display === 'block';
                        container.style.display = isVisible ? 'none' : 'block';
                    }
                });

                // 将设置面板添加到页面
                document.body.appendChild(toggleContainer);

                // 添加点击外部关闭面板的功能
                document.addEventListener('click', function(e) {
                    const container = document.getElementById('settingsToggleContainer');
                    if (container && !container.contains(e.target) && !settingsButton.contains(e.target)) {
                        container.style.display = 'none';
                    }
                });

                // 添加复选框的事件监听器
                toggleContainer.addEventListener('change', function(e) {
                    if (e.target.type === 'checkbox') {
                        switch(e.target.id) {
                            case 'adRemovalToggle':
                                isAdRemovalEnabled = e.target.checked;
                                GM_setValue('bilibiliAdRemovalEnabled', isAdRemovalEnabled);
                                break;
                            case 'swiperRemovalToggle':
                                isSwiperRemovalEnabled = e.target.checked;
                                GM_setValue('bilibiliSwiperRemovalEnabled', isSwiperRemovalEnabled);
                                break;
                            case 'nonVideoCardRemovalToggle':
                                isNonVideoCardRemovalEnabled = e.target.checked;
                                GM_setValue('bilibiliNonVideoCardRemovalEnabled', isNonVideoCardRemovalEnabled);
                                break;
                            case 'copySuffixRemovalToggle':
                                isCopySuffixRemovalEnabled = e.target.checked;
                                GM_setValue('bilibiliCopySuffixRemovalEnabled', isCopySuffixRemovalEnabled);
                                break;
                        }
                    }
                });
            }
        }, 500);
    }

    // 主页功能
    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();
                }
            });

            // 删除flexible-roll-btn中的span标签和内容
            const flexibleRollBtns = document.querySelectorAll('.flexible-roll-btn');
            flexibleRollBtns.forEach(btn => {
                const spans = btn.querySelectorAll('span');
                spans.forEach(span => {
                    span.remove();
                });
            });

            // 删除feed-roll-btn
            const feedRollBtns = document.querySelectorAll('.feed-roll-btn');
            feedRollBtns.forEach(btn => {
                btn.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);  // 每秒检查一次
    }
})();