Search with Gemini

Lets you use Gemini as a custom search engine. Reads 'prompt' parameter from URL and automatically submits it to Gemini chat.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Search with Gemini
// @namespace    https://github.com/alexey-kudryavtsev/
// @version      2025.07.27.1
// @description  Lets you use Gemini as a custom search engine. Reads 'prompt' parameter from URL and automatically submits it to Gemini chat.
// @author       Alexey Kudryavtsev
// @match        https://gemini.google.com/*
// @grant        none
// @run-at       document-start
// @license      Apache-2.0
// @homepageURL  https://github.com/alexey-kudryavtsev/search-with-gemini
// @supportURL   https://github.com/alexey-kudryavtsev/search-with-gemini/issues
// ==/UserScript==


(function() {
    'use strict';

    // --- Configuration ---
    const log = (message) => console.log(`[Gemini Userscript] ${message}`);
    const PROMPT_SELECTOR = '.ql-editor[contenteditable="true"] > p';
    const SUBMIT_BUTTON_SELECTOR = 'button[aria-label="Send message"]';

    log('Script initialized (document-start).');

    // Ensure window.geminiScript object exists
    if (typeof window.geminiScript === 'undefined') {
        window.geminiScript = {};
    }

    // --- Early Execution: Extract prompt and clean URL ---
    const currentUrl = new URL(window.location.href);
    const promptValue = currentUrl.searchParams.get('prompt');

    if (promptValue) {
        log(`Found 'prompt' URL parameter during early execution: "${promptValue}"`);
        window.geminiScript.currentPrompt = promptValue; // Store the prompt
        currentUrl.searchParams.delete('prompt'); // Remove the 'prompt' parameter

        // Replace the URL in the browser's history without reloading
        const cleanUrl = currentUrl.pathname + currentUrl.search + currentUrl.hash;
        history.replaceState(null, '', cleanUrl);
        log(`🧹 URL cleaned. New URL: ${cleanUrl}`);
    } else {
        log("No 'prompt' URL parameter found during early execution. Script is idle for prefill.");
        window.geminiScript.currentPrompt = null; // Ensure it's explicitly null if not found
    }

    /**
     * Finds the prompt input, fills it, finds the submit button, and clicks it.
     * This function will be called AFTER the document is ready.
     * @param {string} textToFill - The prompt text to inject.
     */
    function prefillThenSubmit(textToFill) {
        log('🕵️‍♂️ Starting observer for the input field...');
        const inputObserver = new MutationObserver((mutations, inputObs) => {
            const promptInput = document.querySelector(PROMPT_SELECTOR);
            if (promptInput) {
                log('✅ Step 1: Input field found.');
                inputObs.disconnect();

                // Inject prompt text
                promptInput.textContent = textToFill;
                log(`📝 Text set to: "${textToFill}"`);

                // Now, wait for the submit button to become available
                const submitObserver = new MutationObserver((mutations, submitObs) => {
                    const submitButton = document.querySelector(SUBMIT_BUTTON_SELECTOR);
                    // Also check that it's not disabled
                    if (submitButton && !submitButton.disabled) {
                        log('✅ Step 2: Submit button found and enabled.');
                        submitObs.disconnect();

                        submitButton.click();
                        log('🚀 Prompt submitted!');
                    }
                });

                submitObserver.observe(document.body, {
                    childList: true,
                    subtree: true,
                    attributes: true // Also watch for attribute changes like 'disabled'
                });
            }
        });

        inputObserver.observe(document.body, {
            childList: true,
            subtree: true
        });
    }

    // --- Main Execution (after document is ready) ---
    // Wait for the DOM to be fully loaded before trying to interact with elements
    document.addEventListener('DOMContentLoaded', () => {
        log('DOMContentLoaded fired. Executing main logic.');
        if (window.geminiScript.currentPrompt) {
            prefillThenSubmit(window.geminiScript.currentPrompt);
        } else {
            log("No prompt stored from early execution. No prefill action needed.");
        }
    });

})();