Greasy Fork is available in English.

Gemini Model & Brain Switcher

Yeni arayüzdeki data-active (hover) tuzağı düzeltildi. 1. element dahil tüm modellere sorunsuz geçer.

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

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

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

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

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

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

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

Advertisement:

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

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

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

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

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

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

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

Advertisement:

// ==UserScript==
// @name         Gemini Model & Brain Switcher
// @namespace    https://github.com/FrknKoseoglu
// @version      4.3
// @description  Yeni arayüzdeki data-active (hover) tuzağı düzeltildi. 1. element dahil tüm modellere sorunsuz geçer.
// @author       frknkoseoglu
// @match        https://gemini.google.com/*
// @grant        none
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    let isProcessing = false;

    // Ana tetikleyici
    const MAIN_MENU_SELECTORS = `
        .model-picker-container,
        [data-test-id*="mode-switch"],
        [data-test-id*="model-switch"],
        [data-test-id*="chat-model"],
        [data-test-id="bard-mode-menu-button"],
        .gds-mode-switch-button
    `;

    const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));

    const hideUpgradeButton = () => {
        const style = document.createElement('style');
        style.type = 'text/css';
        style.textContent = `
            .upgrade-container, .g1-upsell-container, gem-menu-item[value="upgrade"] {
                display: none !important;
            }
        `;
        document.head.appendChild(style);
    };

    hideUpgradeButton();

    const waitForElements = async (selector, timeout = 1500) => {
        let elapsed = 0;
        const interval = 20;
        while (elapsed < timeout) {
            const elements = Array.from(document.querySelectorAll(selector)).filter(el => {
                return el.offsetParent !== null || el.getBoundingClientRect().width > 0;
            });
            if (elements.length > 0) return elements;
            await delay(interval);
            elapsed += interval;
        }
        throw new Error(`Element bulunamadı: ${selector}`);
    };

    const simulateClick = (element) => {
        if (!element) return;
        element.focus();
        element.click();
    };

    const closeMenu = () => {
        document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true, cancelable: true }));
        document.body.click();
    };

    // --------------------------------------------------------
    // 1. İŞLEM: TEKERLEK KAYDIRMA (Model Değişimi - Kesin Çözüm)
    // --------------------------------------------------------
    document.addEventListener('wheel', async function(e) {
        if (isProcessing) return;

        const modelContainer = e.target.closest(MAIN_MENU_SELECTORS);
        if (!modelContainer) return;

        e.preventDefault();
        e.stopPropagation();

        isProcessing = true;
        const direction = e.deltaY > 0 ? 1 : -1;

        try {
            const triggerButton = modelContainer.querySelector('button') || modelContainer;
            
            if (triggerButton.getAttribute('aria-expanded') !== 'true') {
                simulateClick(triggerButton);
                await delay(150); 
            }
            
            const buttons = await waitForElements('gem-menu-item[data-mode-id]');
            
            // KRİTİK DÜZELTME: data-active kontrolü kaldırıldı! 
            // Sadece gerçek seçili (selected) sınıflara ve check ikonuna bakılıyor.
            let currentIndex = buttons.findIndex(btn => 
                btn.classList.contains('selected') || 
                btn.querySelector('.selected') || 
                btn.querySelector('mat-icon[fonticon="check"]')
            );
            
            // Eğer hiçbir şey bulunamazsa varsayılan olarak 0 (ilk element) kabul et
            if (currentIndex === -1) currentIndex = 0;
            
            let nextIndex = currentIndex + direction;
            if (nextIndex >= buttons.length) nextIndex = 0;
            if (nextIndex < 0) nextIndex = buttons.length - 1;

            simulateClick(buttons[nextIndex]);

        } catch (err) {
            console.warn("Gemini Switcher Hatası (Model Scroll):", err);
            closeMenu();
        } finally {
            // Artçı scroll sinyallerini sönümlemek için 450ms soğuma
            await delay(450);
            isProcessing = false;
        }
    }, { passive: false, capture: true });

    // --------------------------------------------------------
    // 2. İŞLEM: BUTON RENGİNİ DÜZENLEME
    // --------------------------------------------------------
    const updateBrainButtonState = () => {
        const brainBtn = document.getElementById('gemini-brain-btn');
        const modelContainer = document.querySelector(MAIN_MENU_SELECTORS);
        
        if (brainBtn && modelContainer) {
            if (modelContainer.textContent.includes('Uzatılmış')) {
                brainBtn.style.filter = 'none';
                brainBtn.style.opacity = '1';
            } else {
                brainBtn.style.filter = 'grayscale(100%)';
                brainBtn.style.opacity = '0.7';
            }
        }
    };

    // --------------------------------------------------------
    // 3. İŞLEM: "🧠" BUTONU ENJEKSİYONU
    // --------------------------------------------------------
    const injectBrainButton = () => {
        let brainBtn = document.getElementById('gemini-brain-btn');
        const targetWrapper = document.querySelector('.trailing-actions-wrapper.with-model-picker');
        const modelContainer = document.querySelector('.model-picker-container'); 
        
        if (!brainBtn && targetWrapper && modelContainer) {
            brainBtn = document.createElement('button');
            brainBtn.id = 'gemini-brain-btn';
            brainBtn.textContent = '🧠';
            brainBtn.title = 'Düşünme Düzeyini Değiştir (Standart / Uzatılmış)';
            
            brainBtn.style.cssText = `
                background: transparent !important;
                border: none !important;
                font-size: 1.4rem !important;
                cursor: pointer !important;
                margin: 0 !important; 
                padding: 6px 10px !important;
                border-radius: 50% !important;
                display: flex !important;
                align-items: center !important;
                justify-content: center !important;
                transition: all 0.2s !important;
                user-select: none !important;
                flex-shrink: 0 !important;
                z-index: 9999 !important;
            `;

            brainBtn.onmouseenter = () => { brainBtn.style.backgroundColor = 'rgba(128, 128, 128, 0.1)'; };
            brainBtn.onmouseleave = () => { brainBtn.style.backgroundColor = 'transparent'; };
            brainBtn.onmousedown = () => { brainBtn.style.transform = 'scale(0.9)'; };
            brainBtn.onmouseup = () => { brainBtn.style.transform = 'scale(1)'; };

            brainBtn.onclick = async (e) => {
                e.preventDefault();
                e.stopPropagation();

                if (isProcessing) return;
                isProcessing = true;

                try {
                    const clickableMenu = document.querySelector(MAIN_MENU_SELECTORS);
                    const mainTriggerButton = clickableMenu.querySelector('button') || clickableMenu;

                    if (mainTriggerButton.getAttribute('aria-expanded') !== 'true') {
                        simulateClick(mainTriggerButton);
                        await delay(150); 
                    }

                    const thinkingHeaders = await waitForElements('gem-menu-item[value="thinking_level"]');
                    const headerButton = thinkingHeaders[0];
                    
                    if (headerButton.getAttribute('aria-expanded') !== 'true') {
                        simulateClick(headerButton);
                        await delay(150); 
                    }

                    const thinkingOptions = await waitForElements('gem-menu-item:not([data-mode-id]):not([value="thinking_level"])');
                    
                    // Aynı düzeltme kuralı buradaki seçici için de uygulandı
                    let currentIndex = thinkingOptions.findIndex(btn => 
                        btn.classList.contains('selected') || 
                        btn.querySelector('.selected') || 
                        btn.querySelector('mat-icon[fonticon="check"]')
                    );
                    if (currentIndex === -1) currentIndex = 0;
                    
                    let nextIndex = currentIndex + 1;
                    if (nextIndex >= thinkingOptions.length) nextIndex = 0;

                    simulateClick(thinkingOptions[nextIndex]);
                    await delay(150); 

                    closeMenu();

                } catch (err) {
                    console.warn("Gemini Switcher Hatası (Brain Butonu):", err);
                    closeMenu();
                } finally {
                    await delay(300);
                    isProcessing = false;
                }
            };

            modelContainer.after(brainBtn);
        }

        updateBrainButtonState();
    };

    const init = () => {
        injectBrainButton();
        setInterval(injectBrainButton, 1000);
    };

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }

})();