Greasy Fork

Greasy Fork is available in English.

Gemini 自动化工具箱

自动化 Gemini 操作:模型选择、切换临时对话、自动填充提示词,并支持經由 URL 参数自动发送。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name                Gemini Toolkit
// @name:zh-TW          Gemini 自動化工具箱
// @name:zh-CN          Gemini 自动化工具箱
// @author              WellsTsai
// @namespace           wellstsai.com
// @version             v20251218
// @description         Automates Gemini: Model selection, temporary chat toggling, prompt auto-filling, and optional auto-sending via URL parameters.
// @description:zh-TW   自動化 Gemini 操作:模型選擇、切換臨時對話、自動填入提示詞,並支援經由 URL 參數自動發送。
// @description:zh-CN   自动化 Gemini 操作:模型选择、切换临时对话、自动填充提示词,并支持經由 URL 参数自动发送。
// @match               https://gemini.google.com/*
// @grant               none
// @run-at              document-end
// @license             MIT
// ==/UserScript==

/**
 * === Usage Examples ===
 *
 * 1. Auto-fill text only (Draft mode):
 * https://gemini.google.com/app?q=Hello+World
 *
 * 2. Auto-fill and SEND immediately:
 * https://gemini.google.com/app?q=Hello+World&send=true
 *
 * 3. Switch to specific model (e.g., Gemini Advanced) and fill text:
 * https://gemini.google.com/app?q=Analyze+this&model=2
 *
 * 4. Use Temporary Chat + Model 2 + Auto-send:
 * https://gemini.google.com/app?q=Code+review&model=2&temporary-chat=true&send=true
 *
 * 5. Enable Temporary Chat ONLY (No text, no model switch):
 * https://gemini.google.com/app?temporary-chat=true
 */

(function() {
    'use strict';

    // --- Configuration ---
    const CONFIG = {
        START_DELAY: 0,
        TEMP_CHAT_DELAY: 0,
        MODEL_SWITCH_DELAY: 0,
        TYPE_TO_SEND_DELAY: 0,
        WAIT_TIMEOUT: 10000
    };

    // --- Parse URL Parameters ---
    const params = new URLSearchParams(window.location.search);
    const query = params.get('q');
    const modelParam = parseInt(params.get('model'), 10);
    const modelIndex = (isNaN(modelParam) || modelParam < 1) ? null : modelParam;
    const isTempChat = params.get('temporary-chat') === 'true';
    const shouldAutoSend = params.get('send') === 'true';

    // Exit early if nothing to do
    if (!query && !modelIndex && !isTempChat) return;

    // --- Helpers ---
    const wait = (selector) => {
        return new Promise((resolve) => {
            const timer = setInterval(() => {
                const el = document.querySelector(selector);
                if (el) {
                    clearInterval(timer);
                    resolve(el);
                }
            }, 100);
            setTimeout(() => clearInterval(timer), CONFIG.WAIT_TIMEOUT);
        });
    };

    const sleep = (ms) => new Promise(r => setTimeout(r, ms));

    const aggressiveClick = (el) => {
        ['pointerdown', 'pointerup', 'mousedown', 'click'].forEach(type => {
            const eventClass = type.startsWith('pointer') ? PointerEvent : MouseEvent;
            el.dispatchEvent(new eventClass(type, { bubbles: true, cancelable: true }));
        });
    };

    const cleanUrl = () => {
        const newUrl = `${window.location.origin}${window.location.pathname}`;
        window.history.replaceState({}, '', newUrl);
    };

    // --- Actions ---

    const toggleTempChat = async () => {
        if (!isTempChat) return false;
        try {
            const tempBtn = await wait('button[data-test-id="temp-chat-button"]');
            console.log("[Gemini Enhancement] Activating Temporary Chat...");
            aggressiveClick(tempBtn);
            return true;
        } catch (e) {
            console.warn("[Gemini Enhancement] Temp Chat toggle failed", e);
            return false;
        }
    };

    const switchModel = async () => {
        if (!modelIndex) return false;
        try {
            const menuTrigger = await wait('[data-test-id="bard-mode-menu-button"]');
            menuTrigger.click();
            await sleep(500);

            const overlay = document.querySelector('.cdk-overlay-container');
            if (!overlay) return false;

            const options = overlay.querySelectorAll('button[role="menuitemradio"]');
            const targetBtn = options[modelIndex - 1];

            if (!targetBtn || targetBtn.getAttribute('aria-checked') === 'true') {
                document.body.click(); // Close menu
                return false;
            }

            console.log(`[Gemini Enhancement] Switching to Model Index: ${modelIndex}`);
            aggressiveClick(targetBtn);
            return true;
        } catch (e) {
            console.warn("[Gemini Enhancement] Model switch failed", e);
            return false;
        }
    };

    const fillAndSend = async () => {
        if (!query) return;

        console.log("[Gemini Enhancement] Inputting text...");
        const promptBox = await wait('div[contenteditable="true"]');
        promptBox.focus();

        document.execCommand('insertText', false, query);
        promptBox.dispatchEvent(new Event('input', { bubbles: true }));

        if (!shouldAutoSend) {
            console.log("[Gemini Enhancement] Draft created. Waiting for manual send.");
            cleanUrl();
            return;
        }

        await sleep(CONFIG.TYPE_TO_SEND_DELAY);
        const sendButton = document.querySelector('.send-button');

        if (sendButton && sendButton.getAttribute('aria-disabled') !== 'true') {
            console.log("[Gemini Enhancement] Auto-sending...");
            aggressiveClick(sendButton);
            cleanUrl();
        }
    };

    // --- Main ---
    const main = async () => {
        await sleep(CONFIG.START_DELAY);

        if (await toggleTempChat()) {
            await sleep(CONFIG.TEMP_CHAT_DELAY);
        }

        if (await switchModel()) {
            await sleep(CONFIG.MODEL_SWITCH_DELAY);
        }

        await fillAndSend();
    };

    if (document.readyState === 'complete') {
        main();
    } else {
        window.addEventListener('load', main);
    }

})();