Hide Members Only Filter and whitelist for youtube

Auto-hide "Members only" videos from untrusted channels on YouTube with a toggle to re-show/hide them

// ==UserScript==
// @name         Hide Members Only Filter and whitelist for youtube
// @namespace    http://tampermonkey.net/
// @version      2.1
// @description  Auto-hide "Members only" videos from untrusted channels on YouTube with a toggle to re-show/hide them
// @author       Aonnymous
// @match        https://www.youtube.com/*
// @grant        GM_registerMenuCommand
// @license MIT
// ==/UserScript==

(function () {
    'use strict';

    // === Config ===
    const WHITELIST = [
        'channel name 1',
        'Some Channel',
        'Trusted Creator'
    ];

    const SCAN_INTERVAL_FAST = 2000;              // Every 2s for first minute
    const FAST_SCAN_DURATION = 60000;             // Fast mode for 1 minute
    const MAX_RUNS_PER_MINUTE = 4;                // Slow mode limit
    const DEBUG_BORDER_STYLE = '2px solid red';   // Red border on hidden
    const AUTO_ENABLE_DELAY_MS = 4500;            // Auto-start 4.5s in

    // === State ===
    let scanInterval = null;
    let filteringEnabled = false;
    let scanStartTime = null;
    let lastRunTimestamp = 0;
    let runsThisMinute = 0;

    // === Utilities ===
    const CLEANED_WHITELIST = WHITELIST.map(name => name.trim().toLowerCase());

    function log(...args) {
        console.log('[YT-MembersFilter]', ...args);
    }

    function isWhitelisted(name) {
        const lc = name.trim().toLowerCase();
        return CLEANED_WHITELIST.some(w => lc.indexOf(w) !== -1);
    }

    function getTopLevelVideoElements() {
        const sidebarVideos = Array.from(document.querySelectorAll('ytd-compact-video-renderer'))
            .filter(el => el.closest('ytd-compact-video-renderer') === el);
        const richItems = Array.from(document.querySelectorAll('div#content.style-scope.ytd-rich-item-renderer'));
        return [...sidebarVideos, ...richItems];
    }

    function scanAndHide() {
        const now = Date.now();
        const inFastMode = now - scanStartTime < FAST_SCAN_DURATION;

        if (!inFastMode) {
            if (now - lastRunTimestamp > 60000) {
                runsThisMinute = 0;
                lastRunTimestamp = now;
            }

            if (runsThisMinute >= MAX_RUNS_PER_MINUTE) {
                log('Throttled: max scans this minute reached.');
                return;
            }

            runsThisMinute++;
        }

        const videos = getTopLevelVideoElements();

        if (!videos.length) {
            log('No video elements found.');
            return;
        }

        let hiddenCount = 0;

        videos.forEach(vid => {
            if (vid.dataset._ytMembersFiltered === 'true') return; // Already processed

            const text = vid.textContent || '';
            if (!text.includes('Members only')) return;

            const channelElem = vid.querySelector('.ytd-channel-name');
            const channelName = channelElem?.textContent?.trim() || '';

            if (!isWhitelisted(channelName)) {
                vid.style.display = 'none';
                vid.style.border = DEBUG_BORDER_STYLE;
                vid.dataset._ytMembersFiltered = 'true';
                hiddenCount++;
                log(`Hid video from: "${channelName}"`);
            } else {
                log(`Whitelisted video from: "${channelName}"`);
            }
        });

        if (hiddenCount) {
            log(`Hidden videos this scan: ${hiddenCount}`);
        }
    }

    function startScanning() {
        if (scanInterval) clearInterval(scanInterval);
        scanStartTime = Date.now();
        runsThisMinute = 0;
        lastRunTimestamp = 0;

        scanInterval = setInterval(scanAndHide, SCAN_INTERVAL_FAST);
        log('Started scanning every 2s for 1 minute...');

        setTimeout(() => {
            if (scanInterval) clearInterval(scanInterval);
            log('Fast scan finished. Throttled scanning active.');
            scanInterval = setInterval(scanAndHide, 15000);
        }, FAST_SCAN_DURATION);
    }

    function stopScanningAndShowAll() {
        if (scanInterval) clearInterval(scanInterval);
        scanInterval = null;

        const hidden = document.querySelectorAll('[data-_yt-members-filtered="true"]');
        hidden.forEach(el => {
            el.style.display = '';
            el.style.border = '';
            delete el.dataset._ytMembersFiltered;
        });

        log('Stopped scanning and revealed previously hidden videos.');
    }

    function toggleFiltering() {
        filteringEnabled = !filteringEnabled;

        if (filteringEnabled) {
            log('Filtering ENABLED.');
            startScanning();
        } else {
            log('Filtering DISABLED.');
            stopScanningAndShowAll();
        }
    }

    // === Menu Button ===
    GM_registerMenuCommand('Toggle Member Filter On/Off', toggleFiltering);

    // === Auto Start After Delay ===
    setTimeout(() => {
        if (!filteringEnabled) {
            filteringEnabled = true;
            log('Auto-starting filtering after delay...');
            startScanning();
        }
    }, AUTO_ENABLE_DELAY_MS);

    log('YouTube Member Filter script loaded. Will auto-start in ~4.5s. Toggle anytime via Tampermonkey menu.');
})();