Mastodon Search External Link Filter

Hides Mastodon Search posts with external links (skipping virtual‑scroll placeholders)

Vous devrez installer une extension telle que Tampermonkey, Greasemonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Userscripts pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey pour installer ce script.

Vous devrez installer une extension de gestionnaire de script utilisateur pour installer ce script.

(J'ai déjà un gestionnaire de scripts utilisateur, laissez-moi l'installer !)

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

(J'ai déjà un gestionnaire de style utilisateur, laissez-moi l'installer!)

// ==UserScript==
// @name         Mastodon Search External Link Filter
// @description  Hides Mastodon Search posts with external links (skipping virtual‑scroll placeholders)
// @match        https://mastodon.social/search?*
// @version 0.0.1.20250502160211
// @namespace https://greasyfork.org/users/1435046
// ==/UserScript==

(function () {
    // 1) Grab every <article> in the search results panel
    function getPosts() {
        return document.querySelectorAll('.explore__search-results article');
    }

    // 2) Detect links not pointing to this Mastodon instance
    function isExternalLink(a) {
        return a.href && !a.href.includes(location.hostname);
    }

    // 3) Detect virtual‑scroll placeholder articles
    function isPlaceholder(article) {
        const style = getComputedStyle(article);
        return parseFloat(style.opacity) === 0;
    }

    // 4) Hide any fully rendered article containing at least one external link
    function hidePostsWithExternalLinks() {
        getPosts().forEach(article => {
            if (isPlaceholder(article)) return;             // skip placeholders
            const links = article.querySelectorAll('a[href]');
            if (Array.from(links).some(isExternalLink)) {
                article.style.display = 'none';
            }
        });
    }

    // 5) Observe the search-results container for new articles (infinite scroll)
    function observeSearchResults() {
        const container = document.querySelector('.explore__search-results');
        if (!container) return;
        new MutationObserver(hidePostsWithExternalLinks)
            .observe(container, { childList: true, subtree: true });
        hidePostsWithExternalLinks();
    }

    // 6) Kick off: watch the body for the panel to appear, then observe it
    new MutationObserver(observeSearchResults)
        .observe(document.body, { childList: true, subtree: true });
    observeSearchResults();
})();