Configurable Filter Verified Users - Whitelist, Blacklist (block alternative), Hide Checkmarks

Filter out verified user posts. Filter out also any user's posts at your whims using the blacklist. Whitelist verified users you don't want to filter. Hides blue checkmarks by default for whitelisted users, and doesn't work on profile pages by default so that the script doesn't just ravenously filter every single post on a verified user's page.

// ==UserScript==
// @name         Configurable Filter Verified Users - Whitelist, Blacklist (block alternative), Hide Checkmarks
// @namespace    https://www.threads.net/
// @version      1.0
// @description  Filter out verified user posts. Filter out also any user's posts at your whims using the blacklist. Whitelist verified users you don't want to filter. Hides blue checkmarks by default for whitelisted users, and doesn't work on profile pages by default so that the script doesn't just ravenously filter every single post on a verified user's page.
// @author       artificialsweetener.ai
// @match        https://www.threads.net/*
// @license      CC BY
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    // Configuration variables (1 = enabled, 0 = disabled)
    const ENABLE_FILTER_COUNT = 1; // Set to 0 to disable the count in the upper right hand corner and other information
    const ENABLE_HIDE_CHECKMARKS = 1; // Set to 0 to see blue checkmarks on whitelisted verified users' posts
    const ENABLE_NO_FILTER_ON_PROFILES = 1; // Set to 0 to enable filtering on profile pages. If you navigate to a non-whitelisted verified user's page, this gets weird!
    const NAVIGATION_DELAY_MS = 500; // Controls the delay (in milliseconds) before checking for changes after navigation. If you set this too low, filtering might break

    let filteredCount = 0;
    let counterDisplay;

    const whitelist = [
      // WHITELIST: Add your list of usernames here. This is everything after the @.
        'USERNAME1',
        'USERNAME2',
        // and so on, with line breaks and commas.
    ];

    const blacklist = [
      // BLACKLIST: Add your list of usernames here, just like the whitelist. These are non-verified users you want to filter, like an alternative to blocking.
        'BADPERSON1',
        'BADPERSON2',
        // and so on, with line breaks and commas.
    ];

    const myUsername = 'artificialsweetener.ai';

    function isProfilePage() {
        const pathname = window.location.pathname;
        return pathname.startsWith('/@');
    }

    function createDisplay() {
        if (ENABLE_FILTER_COUNT && !counterDisplay) {
            counterDisplay = document.createElement('div');
            counterDisplay.style.position = 'fixed';
            counterDisplay.style.top = '10px';
            counterDisplay.style.right = '10px';
            counterDisplay.style.backgroundColor = 'rgba(0, 0, 0, 0.8)';
            counterDisplay.style.color = 'white';
            counterDisplay.style.padding = '5px 10px';
            counterDisplay.style.borderRadius = '5px';
            counterDisplay.style.zIndex = '1000';

            const pathname = window.location.pathname;
            const currentUsername = pathname.split('/@')[1]?.split('/')[0];

            if (currentUsername === myUsername) {
                counterDisplay.innerText = "[you found me! don't forget to say hi~]";
            } else if (isProfilePage() && ENABLE_NO_FILTER_ON_PROFILES) {
                counterDisplay.innerText = `[filter disabled on profiles]`;
            } else {
                counterDisplay.innerText = `[filtered posts: ${filteredCount}]`;
            }

            document.body.appendChild(counterDisplay);
        }
    }

    function updateCounterDisplay() {
        if (ENABLE_FILTER_COUNT && counterDisplay && !isProfilePage()) {
            counterDisplay.innerText = `[filtered posts: ${filteredCount}]`;
        }
    }

    function removeDisplay() {
        if (counterDisplay) {
            counterDisplay.remove();
            counterDisplay = null;
        }
    }

    function filterVerifiedUsers() {
        const posts = document.querySelectorAll('div[data-interactive-id]');
        posts.forEach(post => {
            const verifiedBadge = post.querySelector('svg[aria-label="Verified"]');
            const usernameElement = post.querySelector('a[href^="/@"]'); // Selects the <a> tag with href starting with "/@"
            const username = usernameElement ? usernameElement.href.split('/@')[1].split('/')[0] : '';

            if (ENABLE_NO_FILTER_ON_PROFILES && isProfilePage()) {
                if (verifiedBadge && ENABLE_HIDE_CHECKMARKS) {
                    verifiedBadge.style.display = 'none'; // Optionally hide the verified badge on profiles
                }
            } else {
                if (blacklist.includes(username)) {
                    post.style.display = 'none';
                    filteredCount++;
                    updateCounterDisplay();
                } else if (whitelist.includes(username)) {
                    if (verifiedBadge && ENABLE_HIDE_CHECKMARKS) {
                        verifiedBadge.style.display = 'none';
                    }
                } else if (verifiedBadge && post.style.display !== 'none') {
                    post.style.display = 'none';
                    filteredCount++;
                    updateCounterDisplay();
                }
            }
        });
    }

    function initializeFiltering() {
        if (ENABLE_FILTER_COUNT) {
            removeDisplay();
            createDisplay();
        }
        filterVerifiedUsers();

        const observer = new IntersectionObserver((entries, observer) => {
            entries.forEach(entry => {
                if (entry.isIntersecting) {
                    filterVerifiedUsers();
                    observer.unobserve(entry.target);
                }
            });
        }, {
            root: null,
            rootMargin: '0px',
            threshold: 1.0
        });

        document.querySelectorAll('div[data-interactive-id]').forEach(post => {
            observer.observe(post);
        });

        const mutationObserver = new MutationObserver(() => {
            document.querySelectorAll('div[data-interactive-id]').forEach(post => {
                if (!post.getAttribute('data-observed')) {
                    observer.observe(post);
                    post.setAttribute('data-observed', 'true');
                }
            });
        });

        mutationObserver.observe(document.body, {
            childList: true,
            subtree: true,
        });
    }

    const mainContentObserver = new MutationObserver(() => {
        setTimeout(() => {
            if (!isProfilePage()) {
                initializeFiltering();
            } else {
                if (ENABLE_FILTER_COUNT) {
                    removeDisplay();
                    createDisplay();
                }
            }
        }, NAVIGATION_DELAY_MS);
    });

    mainContentObserver.observe(document.body, {
        childList: true,
        subtree: true,
    });

    initializeFiltering();

})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址