Bilibili Live Enhancer

Stream filtering + Gift bar removal + Live counter for Bilibili

Dovrai installare un'estensione come Tampermonkey, Greasemonkey o Violentmonkey per installare questo script.

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

Dovrai installare un'estensione come Tampermonkey o Violentmonkey per installare questo script.

Dovrai installare un'estensione come Tampermonkey o Userscripts per installare questo script.

Dovrai installare un'estensione come ad esempio Tampermonkey per installare questo script.

Dovrai installare un gestore di script utente per installare questo script.

(Ho già un gestore di script utente, lasciamelo installare!)

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

(Ho già un gestore di stile utente, lasciamelo installare!)

// ==UserScript==
// @name         Bilibili Live Enhancer
// @namespace    http://tampermonkey.net/
// @version      1.4
// @description  Stream filtering + Gift bar removal + Live counter for Bilibili
// @author       Gavin Hon
// @match        https://live.bilibili.com/*
// @grant        none
// @run-at       document-idle
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    // Configuration - Stream Filtering
    const LIVE_FILTER_SELECTOR = '.face.living';
    const TARGET_CONTAINER_SELECTOR = '.single';
    const NAME_SELECTOR = '.name';
    const BLOCKED_NAME = '花芽荔枝';
    const COUNTER_SELECTOR = '.mount';
    const COUNTER_PREFIX = '(Live Streaming: ';

    // Configuration - Gift Bar Removal
    const GIFT_BAR_ID = 'gift-control-vm';

    let liveCount = 0;
    let counterElement = null;
    let timer = null;
    const THROTTLE_TIME = 0;

    // Core Functions
    function updateCounter() {
        if (!counterElement) {
            counterElement = document.querySelector(COUNTER_SELECTOR);
            if (!counterElement) return;
        }
        counterElement.textContent = `${COUNTER_PREFIX}${liveCount})`;
    }

    function filterStreamers() {
        liveCount = 0;
        document.querySelectorAll(TARGET_CONTAINER_SELECTOR).forEach(container => {
            // Name filter
            const nameElem = container.querySelector(NAME_SELECTOR);
            if (nameElem?.textContent.includes(BLOCKED_NAME)) {
                container.remove();
                return;
            }

            // Live status check
            const isLive = container.querySelector(LIVE_FILTER_SELECTOR);
            isLive ? liveCount++ : container.remove();
        });

        updateCounter();
    }

    function removeGiftBar() {
        const giftBar = document.getElementById(GIFT_BAR_ID);
        if (giftBar) giftBar.remove();
    }

    // Throttle function
    function throttle(func) {
        if (!timer) {
            func();
            timer = setTimeout(() => {
                timer = null;
            }, THROTTLE_TIME);
        }
    }

    // Unified observer for all DOM changes
    const mainObserver = new MutationObserver((mutations) => {
        throttle(() => {
            filterStreamers();
            removeGiftBar();
        });
    });

    // Initial setup
    function initialize() {
        // Run features immediately
        removeGiftBar();
        filterStreamers();

        // Start observing
        mainObserver.observe(document.body, {
            subtree: true,
            childList: true,
            attributes: false,
            characterData: false
        });

        // Handle SPA navigation
        window.addEventListener('popstate', initialize);
        window.addEventListener('pushstate', initialize);
    }

    // Start the script
    initialize();
})();