Search Engine Result Filter

Filters out specified domains from multiple search engines

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

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

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==UserScript==
// @name         Search Engine Result Filter
// @namespace    https://github.com/smed79/search-engine-result-filter
// @version      1.0
// @description  Filters out specified domains from multiple search engines
// @author       smed79
// @license      GPLv3
// @icon         https://raw.githubusercontent.com/smed79/search-engine-result-filter/refs/heads/main/icon.png
// @match        https://www.google.com/search*
// @match        https://www.bing.com/search*
// @match        https://yandex.com/search*
// @match        https://duckduckgo.com/?*
// @match        https://www.startpage.com/sp/search*
// @grant        none
// ==/UserScript==

// How to Use?
// https://github.com/smed79/search-engine-result-filter#how-to-use

(function() {
    'use strict';

    // Configuration: List of domains to block with wildcard support
    const BLOCKED_DOMAINS = [
        '*.example.com',
        'www.example.org'
        // Add more domains here
    ];

    // Search engine-specific result container selectors
    const SEARCH_ENGINES = {
        google: '.xpd',
        bing: '.b_algo',
        yandex: '.aR0S6LvzTmyFF',
        duckduckgo: '[id^="r1-"]',
        startpage: '.css-z73qjy'
        // Add more search engines here
    };

    // Function to detect current search engine
    function detectSearchEngine() {
        const hostname = window.location.hostname;
        if (hostname.includes('google.com')) return 'google';
        if (hostname.includes('bing.com')) return 'bing';
        if (hostname.includes('yandex.com')) return 'yandex';
        if (hostname.includes('duckduckgo.com')) return 'duckduckgo';
        if (hostname.includes('startpage.com')) return 'startpage';
        // Add more search engines as needed
        return null;
    }

    // Function to check if a hostname matches a domain pattern
    function matchesDomainPattern(hostname, pattern) {
        return hostname === pattern ||  // Exact match
               hostname === 'www.' + pattern ||  // www. subdomain
               hostname.endsWith('.' + pattern);  // Any subdomain
    }

    // Optimized function to check if a link matches blocked domains
    function isBlockedDomain(href) {
        try {
            const hostname = new URL(href).hostname;
            
            return BLOCKED_DOMAINS.some(pattern => 
                pattern.startsWith('*.') 
                    ? matchesDomainPattern(hostname, pattern.replace('*.', ''))
                    : hostname === pattern
            );
        } catch {
            return false;
        }
    }

    // Faster result hiding function
    function hideBlockedResults() {
        const currentEngine = detectSearchEngine();
        if (!currentEngine) return;

        const selector = SEARCH_ENGINES[currentEngine];
        const containers = document.querySelectorAll(selector);
        
        containers.forEach(container => {
            const links = container.querySelectorAll('a[href]');
            
            const shouldHide = Array.from(links).some(link => 
                isBlockedDomain(link.href)
            );

            if (shouldHide) {
                container.style.display = 'none';
            }
        });
    }

    // Optimization: Use requestAnimationFrame for smoother performance
    function efficientHideResults() {
        requestAnimationFrame(hideBlockedResults);
    }

    // Run on initial page load
    hideBlockedResults();

    // Set up a more efficient MutationObserver
    const observer = new MutationObserver((mutations) => {
        if (!observer.isProcessing) {
            observer.isProcessing = true;
            efficientHideResults();
            
            setTimeout(() => {
                observer.isProcessing = false;
            }, 100);
        }
    });

    // Configure the observer to watch for changes in the search results
    observer.observe(document.body, {
        childList: true,
        subtree: true
    });
})();