Google Search Enhancer

Adds a collapsible Google Enhancer panel with optional AI result filter, new tab option, and saved links with better star placement and popup UI.

Bu betiği kurabilmeniz için Tampermonkey, Greasemonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

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

Bu betiği kurabilmeniz için Tampermonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği kurabilmeniz için Tampermonkey ya da Userscripts gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği indirebilmeniz için ayrıca Tampermonkey gibi bir eklenti kurmanız gerekmektedir.

Bu komut dosyasını yüklemek için bir kullanıcı komut dosyası yöneticisi uzantısı yüklemeniz gerekecek.

(Zaten bir kullanıcı komut dosyası yöneticim var, kurmama izin verin!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(Zateb bir user-style yöneticim var, yükleyeyim!)

// ==UserScript==
// @name Google Search Enhancer
// @namespace https://codymkw.nekoweb.org/
// @version 4.4
// @description Adds a collapsible Google Enhancer panel with optional AI result filter, new tab option, and saved links with better star placement and popup UI.
// @author Cody
// @match https://www.google.com/search*
// @match https://www.google.*.*/search*
// @grant GM_getValue
// @grant GM_setValue
// @license MIT
// ==/UserScript==
(function () {
    'use strict';
    const STORAGE_KEY = 'googleEnhancerSettings';
    const LINKS_KEY = 'googleSavedLinks';
    const DEFAULT_SETTINGS = {
        hideAI: true,
        newTab: false
    };
    const loadSettings = () => JSON.parse(GM_getValue(STORAGE_KEY, JSON.stringify(DEFAULT_SETTINGS)));
    const saveSettings = (settings) => GM_setValue(STORAGE_KEY, JSON.stringify(settings));
    const settings = loadSettings();
    const loadLinks = () => JSON.parse(GM_getValue(LINKS_KEY, '[]'));
    const saveLinks = (links) => GM_setValue(LINKS_KEY, JSON.stringify(links));
    // === HANDLE FILTER ===
    const params = new URLSearchParams(window.location.search);
    const q = params.get('q');
    // If hideAI enabled, ensure "-ai" is added
    if (settings.hideAI && q && !q.toLowerCase().includes('-ai')) {
        params.set('q', `${q} -ai`);
        window.location.replace(`${window.location.pathname}?${params.toString()}`);
        return;
    }
    // If hideAI disabled but "-ai" is in query, remove it
    if (!settings.hideAI && q && q.toLowerCase().includes('-ai')) {
        const cleaned = q.replace(/\s*-ai\s*/gi, ' ').trim();
        params.set('q', cleaned);
        window.location.replace(`${window.location.pathname}?${params.toString()}`);
        return;
    }
    // === NEW TAB OPTION ===
    if (settings.newTab) {
        const observer = new MutationObserver(() => {
            document.querySelectorAll('a').forEach(a => {
                if (a.href && !a.target) a.target = '_blank';
            });
        });
        observer.observe(document.body, { childList: true, subtree: true });
    }
    // === ADD SAVE ICONS TO RESULTS ===
    const addSaveIcons = () => {
        document.querySelectorAll('a h3').forEach(h3 => {
            const link = h3.closest('a');
            if (!link || h3.dataset.hasSaveIcon) return;
            h3.dataset.hasSaveIcon = true;
            const wrapper = document.createElement('span');
            wrapper.style.position = 'relative';
            wrapper.style.display = 'inline-block';
            h3.parentNode.insertBefore(wrapper, h3);
            wrapper.appendChild(h3);
            const star = document.createElement('span');
            star.textContent = '⭐';
            star.style.cursor = 'pointer';
            star.style.position = 'absolute';
            star.style.right = '-24px';
            star.style.top = '2px';
            star.style.opacity = '0.6';
            star.style.fontSize = '16px';
            star.title = 'Save for later';
            star.style.transition = 'opacity 0.2s, transform 0.2s';
            const savedLinks = loadLinks();
            if (savedLinks.find(l => l.url === link.href)) {
                star.style.opacity = '1';
                star.style.filter = 'drop-shadow(0 0 2px gold)';
            }
            star.addEventListener('mouseenter', () => {
                star.style.transform = 'scale(1.2)';
            });
            star.addEventListener('mouseleave', () => {
                star.style.transform = 'scale(1)';
            });
            star.addEventListener('click', (e) => {
                e.stopPropagation();
                e.preventDefault();
                const links = loadLinks();
                const existing = links.find(l => l.url === link.href);
                if (existing) {
                    saveLinks(links.filter(l => l.url !== link.href));
                    star.style.opacity = '0.6';
                    star.style.filter = 'none';
                } else {
                    links.push({ title: h3.innerText, url: link.href });
                    saveLinks(links);
                    star.style.opacity = '1';
                    star.style.filter = 'drop-shadow(0 0 2px gold)';
                }
            });
            wrapper.appendChild(star);
        });
    };
    const resultObserver = new MutationObserver(addSaveIcons);
    resultObserver.observe(document.body, { childList: true, subtree: true });
    addSaveIcons();
    // === CONTROL PANEL ===
    const panel = document.createElement('div');
    panel.innerHTML = `
        <div id="ge-toggle" style="
            position: fixed;
            bottom: 20px;
            right: 20px;
            background: var(--bg);
            color: var(--text);
            border: 1px solid var(--border);
            border-radius: 50%;
            width: 40px;
            height: 40px;
            text-align: center;
            line-height: 38px;
            font-size: 18px;
            cursor: pointer;
            box-shadow: 0 2px 8px rgba(0,0,0,0.3);
            z-index: 99999;
        ">⚙️</div>
        <div id="ge-panel" style="
            position: fixed;
            bottom: 70px;
            right: 20px;
            z-index: 9999;
            background: var(--bg);
            color: var(--text);
            border: 1px solid var(--border);
            border-radius: 10px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.2);
            padding: 10px 12px;
            font-family: sans-serif;
            font-size: 13px;
            min-width: 190px;
            display: none;
        ">
            <strong>⚙️ Google Enhancer</strong>
            <div style="margin-top: 8px;">
                <label><input type="checkbox" id="hideAI" ${settings.hideAI ? 'checked' : ''}> Hide AI Results</label><br>
                <label><input type="checkbox" id="newTab" ${settings.newTab ? 'checked' : ''}> Open results in new tab</label>
            </div>
            <button id="showSavedLinks" style="
                margin-top: 10px;
                width: 100%;
                border: none;
                border-radius: 6px;
                padding: 6px;
                background: var(--button-bg);
                color: var(--button-text);
                cursor: pointer;
            ">📁 Saved Links</button>
        </div>
    `;
    document.body.appendChild(panel);
    // === DARK/LIGHT THEME ===
    const dark = window.matchMedia('(prefers-color-scheme: dark)').matches;
    const vars = dark
        ? { bg: '#222', text: '#eee', border: '#555', buttonBg: '#333', buttonText: '#fff' }
        : { bg: '#fff', text: '#222', border: '#ccc', buttonBg: '#f5f5f5', buttonText: '#000' };
    for (const [k, v] of Object.entries(vars)) {
        panel.querySelector('#ge-panel').style.setProperty(`--${k}`, v);
        panel.querySelector('#ge-toggle').style.setProperty(`--${k}`, v);
    }
    // === TOGGLE PANEL ===
    const toggleBtn = document.getElementById('ge-toggle');
    const mainPanel = document.getElementById('ge-panel');
    toggleBtn.addEventListener('click', () => {
        mainPanel.style.display = mainPanel.style.display === 'none' ? 'block' : 'none';
    });
    // === SETTINGS ===
    ['hideAI', 'newTab'].forEach(key => {
        document.getElementById(key).addEventListener('change', e => {
            settings[key] = e.target.checked;
            saveSettings(settings);
            location.reload();
        });
    });
    // === SAVED LINKS POPUP ===
    const makeSavedPopup = () => {
        const popup = document.createElement('div');
        popup.innerHTML = `
            <div id="savedLinksPopup" style="
                position: fixed;
                top: 50%;
                left: 50%;
                transform: translate(-50%, -50%);
                background: ${vars.bg};
                color: ${vars.text};
                border: 1px solid ${vars.border};
                border-radius: 10px;
                box-shadow: 0 4px 20px rgba(0,0,0,0.4);
                padding: 15px;
                z-index: 100000;
                width: 320px;
                max-height: 400px;
                overflow-y: auto;
            ">
                <div style="display: flex; justify-content: space-between; align-items: center;">
                    <strong>📁 Saved Links</strong>
                    <button id="closePopup" style="
                        background: transparent;
                        color: ${vars.text};
                        border: none;
                        font-size: 16px;
                        cursor: pointer;
                    ">❎</button>
                </div>
                <div id="linksContainer" style="margin-top: 10px;"></div>
                <button id="clearAllLinks" style="
                    margin-top: 10px;
                    width: 100%;
                    border: none;
                    border-radius: 6px;
                    padding: 6px;
                    background: ${vars.buttonBg};
                    color: ${vars.buttonText};
                    cursor: pointer;
                ">🗑️ Clear All</button>
            </div>
        `;
        document.body.appendChild(popup);
        const container = popup.querySelector('#linksContainer');
        const links = loadLinks();
        if (links.length === 0) {
            container.innerHTML = `<p style="opacity: 0.7;">No saved links yet.</p>`;
        } else {
            links.forEach((l, i) => {
                const div = document.createElement('div');
                div.style.marginBottom = '6px';
                div.innerHTML = `
                    <a href="${l.url}" target="_blank" style="color: ${vars.text}; text-decoration: none;">${l.title}</a>
                    <button data-index="${i}" style="margin-left: 8px; font-size: 12px;">❌</button>
                `;
                container.appendChild(div);
            });
            container.querySelectorAll('button[data-index]').forEach(btn => {
                btn.addEventListener('click', e => {
                    const idx = +e.target.dataset.index;
                    const links = loadLinks();
                    links.splice(idx, 1);
                    saveLinks(links);
                    popup.remove();
                    makeSavedPopup();
                });
            });
        }
        popup.querySelector('#clearAllLinks').addEventListener('click', () => {
            if (confirm('Clear all saved links?')) {
                saveLinks([]);
                popup.remove();
            }
        });
        popup.querySelector('#closePopup').addEventListener('click', () => {
            popup.remove();
        });
    };
    document.getElementById('showSavedLinks').addEventListener('click', makeSavedPopup);
})();