Open current page in Gemini and summarize. with moveable Button v1.0

Adds a smaller, draggable button to all web pages that opens Gemini with a prompt to summarize the current page.

// ==UserScript==
// @name        Open current page in Gemini and summarize. with moveable Button v1.0
// @namespace   http://tampermonkey.net/
// @version     1.0
// @description Adds a smaller, draggable button to all web pages that opens Gemini with a prompt to summarize the current page.
// @author      Gemini (Modified)
// @license MIT
// @match       *://*/*
// @grant       GM_addStyle
// @grant       GM_setValue
// @grant       GM_getValue
// @grant       GM_setClipboard
// @run-at      document-idle
// ==/UserScript==

(function() {
    'use strict';

    console.log("Link to Gemini Button script (v2.4) is loading.");
    if (typeof GM_info !== 'undefined') {
        console.log("GM_info:", GM_info);
    } else {
        console.log("GM_info is not available. Script might not be running in a UserScript manager.");
    }

    const BUTTON_ID = 'gemini-button-draggable';
    const POSITION_KEY_X = 'geminiButtonPosX';
    const POSITION_KEY_Y = 'geminiButtonPosY';

    // --- Styling for the button ---
    GM_addStyle(`
        #${BUTTON_ID} {
            position: fixed;
            background-color: #4285F4; /* Google Blue */
            color: white;
            border: none;
            padding: 5px 10px; /* Smaller padding */
            border-radius: 3px; /* Slightly less rounded */
            cursor: grab; /* Indicate it's draggable */
            z-index: 99999;
            font-family: Arial, sans-serif;
            font-size: 12px; /* Smaller font size */
            font-weight: bold;
            box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2); /* Smaller shadow */
            transition: background-color 0.2s ease, box-shadow 0.2s ease;
            min-width: unset; /* Ensure no conflicting min-width */
            line-height: normal; /* Ensure text fits */
            text-align: center;
        }
        #${BUTTON_ID}:hover {
            background-color: #3367D6; /* Darker blue on hover */
            box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3);
        }
        #${BUTTON_ID}.copied {
            background-color: #28a745; /* Green when copied */
        }
        #${BUTTON_ID}.dragging {
            cursor: grabbing;
            box-shadow: 0 0 0 2px #DB4437; /* Red outline when dragging */
        }
    `);

    // --- Function to create and add the button ---
    async function addGeminiButton() {
        console.log("Attempting to add Gemini button...");

        // Prevent adding multiple buttons
        if (document.getElementById(BUTTON_ID)) {
            console.log("Gemini button already exists. Skipping re-creation.");
            return;
        }

        const button = document.createElement('button');
        button.id = BUTTON_ID;
        button.className = 'gemini-button';
        button.textContent = 'Open Gemini'; // More general text

        // --- Load saved position ---
        const savedX = await GM_getValue(POSITION_KEY_X, null);
        const savedY = await GM_getValue(POSITION_KEY_Y, null);

        if (savedX !== null && savedY !== null) {
            button.style.left = savedX + 'px';
            button.style.top = savedY + 'px';
            button.style.right = 'unset'; // Clear right if left is set
            button.style.bottom = 'unset'; // Clear bottom if top is set
        } else {
            // Default position if no saved position
            button.style.right = '20px';
            button.style.top = '100px';
        }

        // --- Draggable Logic ---
        let isDragging = false;
        let offsetX, offsetY;
        let lastClickX, lastClickY; // To detect if a drag happened vs. a click

        button.addEventListener('mousedown', (e) => {
            isDragging = true;
            button.classList.add('dragging');
            offsetX = e.clientX - button.getBoundingClientRect().left;
            offsetY = e.clientY - button.getBoundingClientRect().top;
            lastClickX = e.clientX;
            lastClickY = e.clientY;
            button.style.userSelect = 'none'; // Prevent text selection during drag
            e.preventDefault(); // Prevent default drag behavior (e.g., image drag)
        });

        document.addEventListener('mousemove', (e) => {
            if (!isDragging) return;
            // Clear right/bottom styles as we're setting left/top
            button.style.right = 'unset';
            button.style.bottom = 'unset';
            button.style.left = (e.clientX - offsetX) + 'px';
            button.style.top = (e.clientY - offsetY) + 'px';
        });

        document.addEventListener('mouseup', async (e) => {
            if (!isDragging) return;
            isDragging = false;
            button.classList.remove('dragging');
            button.style.userSelect = 'auto'; // Restore user-select

            // Save new position
            const finalX = button.getBoundingClientRect().left;
            const finalY = button.getBoundingClientRect().top;
            await GM_setValue(POSITION_KEY_X, finalX);
            await GM_setValue(POSITION_KEY_Y, finalY);
            console.log(`Saved button position: X=${finalX}, Y=${finalY}`);

            // If a significant drag occurred, prevent the click event from firing
            const dx = Math.abs(e.clientX - lastClickX);
            const dy = Math.abs(e.clientY - lastClickY);
            if (dx > 5 || dy > 5) {
                console.log("Mouse up after drag, preventing click.");
                e.stopImmediatePropagation(); // Prevent subsequent click event on the button
            }
        });

        // --- Button Click Logic ---
        button.addEventListener('click', async () => {
            const currentUrl = window.location.href;
            const textToCopy = `Summarize this page: ${currentUrl}`; // The prompt text

            try {
                // Use GM_setClipboard if available. We don't need a fallback since we are not displaying the "Copied!" message based on clipboard success anymore.
                if (typeof GM_setClipboard === 'function') {
                    GM_setClipboard(textToCopy);
                    console.log("Prompt copied to clipboard using GM_setClipboard:", textToCopy);
                }

                // Open Gemini in a new tab with the desired URL structure
                // ***************************************************************
                // ** THIS IS THE MODIFIED LINE TO MATCH YOUR REQUESTED SYNTAX **
                // ***************************************************************
                const geminiUrl = `https://gemini.google.com/app/54299f6f7b8a6a75?q=${encodeURIComponent(textToCopy)}`;
                window.open(geminiUrl, '_blank');
                console.log("Opening Gemini tab:", geminiUrl);

                // Flash a confirmation on the button
                button.textContent = 'Opened!';
                button.classList.add('copied'); // Using 'copied' class for green color

                // Revert button text after a delay
                setTimeout(() => {
                    button.textContent = 'Open Gemini';
                    button.classList.remove('copied');
                }, 2000);

            } catch (error) {
                console.error('Failed to perform action:', error);
                button.textContent = 'Error!';
                button.style.backgroundColor = 'red';
                setTimeout(() => {
                    button.textContent = 'Open Gemini';
                    button.style.backgroundColor = '#4285F4'; // Revert to Google Blue
                }, 2000);
                alert("Failed to open Gemini. Check browser console (F12) for details.");
            }
        });

        // Append the button to the body
        if (document.body) {
            document.body.appendChild(button);
            console.log("Gemini button successfully added to the page.");
        } else {
            console.error("Document body not found. Could not add Gemini button.");
            // If body isn't ready yet, try again after a short delay
            setTimeout(addGeminiButton, 100);
        }
    }

    // Run the main logic after the window has fully loaded
    window.addEventListener('load', addGeminiButton);
    // Also run on DOMContentLoaded for faster injection on some pages
    window.addEventListener('DOMContentLoaded', addGeminiButton);

})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址