Yeni arayüzdeki data-active (hover) tuzağı düzeltildi. 1. element dahil tüm modellere sorunsuz geçer.
// ==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();
}
})();