Gemini - Middle-click to open in new tab (Multi-language)

Allows middle-clicking on conversation history, "New Chat", and "Explore Gems" in Gemini to open them in a new background tab. Works across different UI languages.

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला Tampermonkey, Greasemonkey किंवा Violentmonkey यासारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

You will need to install an extension such as Tampermonkey to install this script.

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला Tampermonkey किंवा Violentmonkey यासारखे एक्स्टेंशन इंस्टॉल करावे लागेल..

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला Tampermonkey यासारखे एक्स्टेंशन इंस्टॉल करावे लागेल..

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्क्रिप्ट व्यवस्थापक एक्स्टेंशन इंस्टॉल करावे लागेल.

(माझ्याकडे आधीच युझर स्क्रिप्ट व्यवस्थापक आहे, मला इंस्टॉल करू द्या!)

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला Stylus सारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला Stylus सारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला Stylus सारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्टाईल व्यवस्थापक इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्टाईल व्यवस्थापक इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्टाईल व्यवस्थापक इंस्टॉल करावे लागेल.

(माझ्याकडे आधीच युझर स्टाईल व्यवस्थापक आहे, मला इंस्टॉल करू द्या!)

// ==UserScript==
// @name         Gemini - Middle-click to open in new tab (Multi-language)
// @name:zh-CN   Gemini - 中键点击在新标签页打开 (多语言支持)
// @namespace    http://tampermonkey.net/
// @version      1.6
// @description  Allows middle-clicking on conversation history, "New Chat", and "Explore Gems" in Gemini to open them in a new background tab. Works across different UI languages.
// @description:zh-CN  允许在 Gemini 的对话历史、"发起新对话"和"探索 Gem"上使用鼠标中键点击,从而在新的后台标签页中打开它们。此版本支持不同的界面语言。
// @author       Gemini & contributors
// @match        https://gemini.google.com/app*
// @match        https://gemini.google.com/gems*
// @match        https://gemini.google.com/gem/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=gemini.google.com
// @grant        GM_openInTab
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    // 预先移除所有"发起新对话"按钮的disabled状态
    function enableNewChatButtons() {
        const newChatButtons = document.querySelectorAll('button:has(mat-icon[fonticon="edit_square"])');
        newChatButtons.forEach(button => {
            if (button.disabled || button.hasAttribute('disabled')) {
                button.disabled = false;
                button.removeAttribute('disabled');
                console.log('已启用"发起新对话"按钮:', button);
            }
        });
    }

    // 等待页面完全加载完毕后执行
    window.addEventListener('load', function() {
        // 给Gemini的JS一点时间完成初始化,然后再修改按钮状态
        setTimeout(enableNewChatButtons, 1000);
    });

    // 监听DOM变化,处理动态加载的按钮
    const observer = new MutationObserver(function(mutations) {
        mutations.forEach(function(mutation) {
            if (mutation.type === 'childList') {
                enableNewChatButtons();
            }
        });
    });
    observer.observe(document.body, { childList: true, subtree: true });

    document.addEventListener('mousedown', function(event) {
        // event.button === 1 代表鼠标中键点击
        if (event.button !== 1) {
            return;
        }

        // 【重大更新】使用不依赖于语言的图标选择器
        // :has() 选择器可以找到包含特定子元素的父元素,非常适合此场景
        const newChatButton = event.target.closest('button:has(mat-icon[fonticon="edit_square"])');
        const exploreGemsButton = event.target.closest('button:has(mat-icon[fonticon="gem_spark"])');
        const conversationElement = event.target.closest('[data-test-id="conversation"]');
        // 处理单个Gem页面的按钮(情况3)
        const gemChatButton = event.target.closest('button.bot-new-conversation-button');
        

        let url = null;
        let logMessage = '';

        // 处理"发起新对话"按钮
        if (newChatButton) {
            url = 'https://gemini.google.com/app';
            logMessage = 'Opening New Chat in new background tab:';
        }
        // 处理"探索 Gem"按钮
        else if (exploreGemsButton) {
            url = 'https://gemini.google.com/gems/view';
            logMessage = 'Opening Explore Gems in new background tab:';
        }
        // 处理Gem聊天按钮(情况3和情况4)
        else if (gemChatButton) {
            let gemId = null;
            
            // 方法1:从当前URL提取gem ID(适用于 /gem/xxx 页面)
            const currentUrl = window.location.href;
            const gemMatch = currentUrl.match(/\/gem\/([a-f0-9]{12})/);
            if (gemMatch && gemMatch[1]) {
                gemId = gemMatch[1];
            } else {
                // 方法2:从DOM元素的jslog属性中提取gem ID(适用于 /app 页面等)
                // 先查找包含BardVeMetadataKey的父元素
                let botItem = gemChatButton.closest('[jslog*="BardVeMetadataKey"]');
                
                // 如果没找到,查找任何包含jslog的父元素
                if (!botItem) {
                    botItem = gemChatButton.closest('[jslog]');
                }
                
                // 从按钮本身的jslog中查找
                if (!botItem && gemChatButton.hasAttribute('jslog')) {
                    botItem = gemChatButton;
                }
                
                if (botItem) {
                    const jslog = botItem.getAttribute('jslog');
                    // 尝试多种格式提取gem ID
                    const match = jslog.match(/"([a-f0-9]{12})"/) || 
                                 jslog.match(/"([a-f0-9]{12})"/) ||
                                 jslog.match(/([a-f0-9]{12})/);
                    if (match && match[1]) {
                        gemId = match[1];
                    }
                }
            }
            
            if (gemId) {
                url = `https://gemini.google.com/gem/${gemId}`;
                logMessage = 'Opening Gem conversation in new background tab:';
            }
        }
        // 处理对话历史记录
        else if (conversationElement) {
            const jslog = conversationElement.getAttribute('jslog');
            if (jslog) {
                // 正则表达式匹配16位以上的十六进制字符作为ID
                const match = jslog.match(/([a-f0-9]{16,})/);
                if (match && match[1]) {
                    const conversationId = match[1];
                    url = `https://gemini.google.com/app/${conversationId}`;
                    logMessage = 'Opening Gemini conversation in new background tab:';
                }
            }
        }

        // 如果成功获取了URL,则阻止默认行为并在后台新标签页中打开
        if (url) {
            event.preventDefault();
            event.stopPropagation();
            console.log(logMessage, url);
            // 将 active 设置为 false,实现在后台打开新标签页
            GM_openInTab(url, { active: false });
        }

    }, { capture: true, passive: false }); // 使用捕获阶段,禁用passive模式以允许preventDefault

})();