油猴脚本:给 Gemini 加个顺手的「新标签页」按钮

Vibe UserScripts 有点上头,有了 chrome-devtools MCP 的加持,开发太快乐了,又来一个新的

习惯了 ChatGPT 的多开标签页跑任务,Gemini 竟然不支持:enraged_face:

每次都要新开一个标签页,有点断思路。

后续有关于 Gemini 的新点子也会更新到这里,目前支持:

  • 宽屏显示:点击油猴扩展图标,点击宽屏显示即可。
  • 思维链斜体:点击油猴扩展图标,点击思维链斜体即可。

更新记录

展开
25 个赞

强呀,大佬!

这个好这个好,感谢分享

“习惯了 ChatGPT 的多开标签页跑任务,Gemini 竟然不支持:enraged_face:
每次都要新开一个标签页,有点断思路。”

没有太懂什么意思,是同一个对话里跑多个并行任务吗

比如你在做 A 时,想到要做 B,那么就需要新开一个标签页(网页页面)做 B,因为 B 可能不适合放到 A 对话中。

比如你和 ChatGPT 沟通一个方案,它的回复中有一些东西你需要确认,但又不适合在当前对话中问(可能回答还没结束,可能问的问题偏离了最初的方案),那么就需要再开新对话。而你需要在 A 和 B 的回答中来回切,同一个标签页下就不适合了。

1 个赞

感谢分享。

噢噢我懂了,以前确实有过这个困扰,但没多想,确实帮了一个大忙 :+1:

1 个赞

黑暗主题下找半天,屏幕还有点反光终于找到了

非常好,不错

不好意思 :bili_017: 忘记暗色模式了,已更新

在大佬的基础上调了一下,可以选择谷歌账号,默认按照登录的邮箱顺序从0开始 :joy:

// ==UserScript==
// @name         Gemini Enhancement
// @namespace    https://loongphy.com
// @version      1.1
// @description  Adds a button to open new Gemini tab and squircle input (second Google account)
// @author       loongphy
// @match        https://gemini.google.com/*
// @grant        none
// @run-at       document-idle
// @downloadURL  https://update.greasyfork.org/scripts/556845/Gemini%20Enhancement.user.js
// @updateURL    https://update.greasyfork.org/scripts/556845/Gemini%20Enhancement.meta.js
// ==/UserScript==

(function() {
    'use strict';

    // 想用第几个账号就改这里,0=第一个,1=第二个,以此类推
    const GEMINI_ACCOUNT_INDEX = 0;
    const GEMINI_URL = `https://gemini.google.com/app?authuser=${GEMINI_ACCOUNT_INDEX}`;

    // ==================== Styles ====================
    const STYLES = `
        /* Squircle for input box */
        input-area-v2 { corner-shape: squircle; }

        /* New tab button - positioned next to Gemini logo */
        .gemini-new-tab-btn {
            position: fixed;
            width: 32px;
            height: 32px;
            border-radius: 50%;
            background: transparent;
            border: none;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            transition: background-color 0.2s ease;
            z-index: 1000;
            visibility: hidden;
        }
        .gemini-new-tab-btn.visible {
            visibility: visible;
        }
        .gemini-new-tab-btn:hover {
            background-color: rgba(68, 71, 70, 0.08);
        }
        .gemini-new-tab-btn:active {
            background-color: rgba(68, 71, 70, 0.12);
        }
        .gemini-new-tab-btn svg {
            width: 18px;
            height: 18px;
            fill: #444746;
        }
    `;

    function injectStyles() {
        const styleEl = document.createElement('style');
        styleEl.textContent = STYLES;
        document.head.appendChild(styleEl);
    }

    function createNewTabButton() {
        const button = document.createElement('button');
        button.className = 'gemini-new-tab-btn';
        button.title = 'Open Gemini in New Tab (Account 2)';

        // SVG icon (open in new tab) using DOM APIs
        const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
        svg.setAttribute('viewBox', '0 0 24 24');
        const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
        path.setAttribute('d', 'M19 19H5V5h7V3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z');
        svg.appendChild(path);
        button.appendChild(svg);

        button.addEventListener('click', () => {
            // 这里改成带 authuser 的地址,固定用第二个账号
            window.open(GEMINI_URL, '_blank');
        });

        // Position button dynamically next to Gemini text
        function positionButton() {
            const geminiText = document.querySelector('.bard-text');
            if (geminiText) {
                const rect = geminiText.getBoundingClientRect();
                // Only position if element has valid dimensions
                if (rect.width > 0 && rect.left > 0) {
                    button.style.top = (rect.top + (rect.height - 32) / 2) + 'px';
                    button.style.left = (rect.right + 2) + 'px';
                    button.classList.add('visible');
                    return true;
                }
            }
            return false;
        }

        // Wait for element to be properly positioned
        function waitAndPosition() {
            if (!positionButton()) {
                requestAnimationFrame(waitAndPosition);
            }
        }

        document.body.appendChild(button);
        waitAndPosition();
        window.addEventListener('resize', positionButton);
    }

    // ==================== Initialize ====================
    function init() {
        injectStyles();
        createNewTabButton();
    }

    init();
})();

1 个赞

感谢,用上了

这个不错,不过GPT好像也不能多开吧

感谢分享

佬,你的可以截个图吗,为什么我的没有效果呢

这个数字需要改一下哈,你是不是忘记改数字了,记得和谷歌邮箱上面的登录顺序是保持一致的,默认是0,即第一个谷歌默认的账号,如果你想登录第二个号的gemini,这个数字需要换成1

每次要改脚本的话,不如切换账号快一点 :rofl:
如果有个按钮还可以(但应该实现不了)

// ==UserScript==
// @name         Gemini Enhancement - Account Picker (Editable Labels)
// @namespace    https://loongphy.com
// @version      1.3
// @description  Adds a button to open new Gemini tab with account picker, editable labels and squircle input
// @author       loongphy (modified by ChatGPT)
// @match        https://gemini.google.com/*
// @grant        none
// @run-at       document-idle
// @downloadURL  https://update.greasyfork.org/scripts/556845/Gemini%20Enhancement.user.js
// @updateURL    https://update.greasyfork.org/scripts/556845/Gemini%20Enhancement.meta.js
// ==/UserScript==

(function() {
    'use strict';

    // ==================== 可配置区域 ====================
    // 想在菜单里列出哪些账号,就在这里改
    // 0 = 第一个账号,1 = 第二个,以此类推
    const GEMINI_ACCOUNTS = [
        { index: 0, label: '账号 1' },
        { index: 1, label: '账号 2' },
        { index: 2, label: '账号 3' },
        { index: 3, label: '账号 4' },
        { index: 4, label: '账号 5' },
        { index: 5, label: '账号 6' }
    ];
    const GEMINI_BASE_URL = 'https://gemini.google.com/app';

    // 存账号自定义名称的 key
    const LABEL_STORAGE_KEY = 'geminiAccountLabels';

    function loadLabelOverrides() {
        try {
            const raw = localStorage.getItem(LABEL_STORAGE_KEY);
            return raw ? JSON.parse(raw) : {};
        } catch (e) {
            console.warn('Gemini Enhancement: failed to load label overrides', e);
            return {};
        }
    }

    function saveLabelOverrides(overrides) {
        try {
            localStorage.setItem(LABEL_STORAGE_KEY, JSON.stringify(overrides));
        } catch (e) {
            console.warn('Gemini Enhancement: failed to save label overrides', e);
        }
    }

    // ==================== Styles ====================
    const STYLES = `
        /* Squircle for input box */
        input-area-v2 { corner-shape: squircle; }

        /* New tab button - positioned next to Gemini logo */
        .gemini-new-tab-btn {
            position: fixed;
            width: 32px;
            height: 32px;
            border-radius: 50%;
            background: transparent;
            border: none;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            transition: background-color 0.2s ease;
            z-index: 1000;
            visibility: hidden;
        }
        .gemini-new-tab-btn.visible {
            visibility: visible;
        }
        .gemini-new-tab-btn:hover {
            background-color: rgba(68, 71, 70, 0.08);
        }
        .gemini-new-tab-btn:active {
            background-color: rgba(68, 71, 70, 0.12);
        }
        .gemini-new-tab-btn svg {
            width: 18px;
            height: 18px;
            fill: #444746;
        }

        /* Account picker menu */
        .gemini-account-menu {
            position: fixed;
            min-width: 180px;
            padding: 6px 0;
            border-radius: 12px;
            background-color: #fff;
            box-shadow: 0 4px 16px rgba(0, 0, 0, 0.16);
            border: 1px solid rgba(0, 0, 0, 0.08);
            z-index: 1001;
            display: none;
            font-size: 13px;
        }
        .gemini-account-menu.visible {
            display: block;
        }
        .gemini-account-menu__item {
            width: 100%;
            padding: 8px 16px;
            background: none;
            border: none;
            text-align: left;
            cursor: pointer;
            display: flex;
            align-items: center;
            gap: 8px;
            font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
        }
        .gemini-account-menu__item:hover {
            background-color: rgba(68, 71, 70, 0.06);
        }
        .gemini-account-menu__item-index {
            min-width: 18px;
            opacity: 0.7;
        }
        .gemini-account-menu__item-label {
            flex: 1;
        }
        .gemini-account-menu__item-authuser {
            font-size: 11px;
            opacity: 0.6;
        }
        .gemini-account-menu__item-hint {
            font-size: 10px;
            opacity: 0.5;
            margin-left: auto;
        }
    `;

    function injectStyles() {
        const styleEl = document.createElement('style');
        styleEl.textContent = STYLES;
        document.head.appendChild(styleEl);
    }

    function openGeminiWithAccount(index) {
        const url = `${GEMINI_BASE_URL}?authuser=${index}`;
        window.open(url, '_blank');
    }

    function createAccountMenu(anchorButton) {
        const menu = document.createElement('div');
        menu.className = 'gemini-account-menu';

        const labelOverrides = loadLabelOverrides();

        GEMINI_ACCOUNTS.forEach(acc => {
            const item = document.createElement('button');
            item.className = 'gemini-account-menu__item';

            const spanIndex = document.createElement('span');
            spanIndex.className = 'gemini-account-menu__item-index';
            spanIndex.textContent = acc.index;

            const spanLabel = document.createElement('span');
            spanLabel.className = 'gemini-account-menu__item-label';
            const resolvedLabel = labelOverrides[acc.index] || acc.label;
            spanLabel.textContent = resolvedLabel;

            const spanAuth = document.createElement('span');
            spanAuth.className = 'gemini-account-menu__item-authuser';
            spanAuth.textContent = `authuser=${acc.index}`;

            const spanHint = document.createElement('span');
            spanHint.className = 'gemini-account-menu__item-hint';
            spanHint.textContent = '右键重命名';

            item.appendChild(spanIndex);
            item.appendChild(spanLabel);
            item.appendChild(spanAuth);
            item.appendChild(spanHint);

            // 左键:直接打开
            item.addEventListener('click', (e) => {
                e.stopPropagation();
                menu.classList.remove('visible');
                openGeminiWithAccount(acc.index);
            });

            // 右键:重命名
            item.addEventListener('contextmenu', (e) => {
                e.preventDefault();
                e.stopPropagation();

                const currentOverrides = loadLabelOverrides();
                const currentLabel = currentOverrides[acc.index] || acc.label || `账号 ${acc.index + 1}`;
                const input = prompt('为这个账号设置一个名字(留空恢复默认):', currentLabel);

                if (input === null) {
                    // 用户取消
                    return;
                }

                const trimmed = input.trim();
                if (trimmed) {
                    currentOverrides[acc.index] = trimmed;
                    spanLabel.textContent = trimmed;
                } else {
                    // 清除自定义标签,恢复默认
                    delete currentOverrides[acc.index];
                    spanLabel.textContent = acc.label;
                }
                saveLabelOverrides(currentOverrides);
            });

            menu.appendChild(item);
        });

        document.body.appendChild(menu);

        function positionMenu() {
            const rect = anchorButton.getBoundingClientRect();
            menu.style.top = (rect.bottom + 8) + 'px';
            menu.style.left = rect.left + 'px';
        }

        function showMenu() {
            positionMenu();
            menu.classList.add('visible');
        }

        function hideMenu() {
            menu.classList.remove('visible');
        }

        // 点击按钮:切换菜单显示/隐藏
        anchorButton.addEventListener('click', (e) => {
            e.stopPropagation();
            if (menu.classList.contains('visible')) {
                hideMenu();
            } else {
                showMenu();
            }
        });

        // 点击外部关闭菜单
        document.addEventListener('click', (e) => {
            if (!menu.contains(e.target) && e.target !== anchorButton) {
                hideMenu();
            }
        });

        // 窗口缩放时重新定位(如果菜单是打开的)
        window.addEventListener('resize', () => {
            if (menu.classList.contains('visible')) {
                positionMenu();
            }
        });

        return menu;
    }

    function createNewTabButton() {
        const button = document.createElement('button');
        button.className = 'gemini-new-tab-btn';
        button.title = '选择账号打开新的 Gemini 标签页';

        // SVG icon (open in new tab) using DOM APIs
        const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
        svg.setAttribute('viewBox', '0 0 24 24');
        const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
        path.setAttribute('d', 'M19 19H5V5h7V3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z');
        svg.appendChild(path);
        button.appendChild(svg);

        // Position button dynamically next to Gemini text
        function positionButton() {
            const geminiText = document.querySelector('.bard-text');
            if (geminiText) {
                const rect = geminiText.getBoundingClientRect();
                if (rect.width > 0 && rect.left > 0) {
                    button.style.top = (rect.top + (rect.height - 32) / 2) + 'px';
                    button.style.left = (rect.right + 2) + 'px';
                    button.classList.add('visible');
                    return true;
                }
            }
            return false;
        }

        function waitAndPosition() {
            if (!positionButton()) {
                requestAnimationFrame(waitAndPosition);
            }
        }

        document.body.appendChild(button);
        waitAndPosition();

        // 创建账号选择菜单(挂在同一个页面上)
        createAccountMenu(button);

        window.addEventListener('resize', positionButton);
    }

    // ==================== Initialize ====================
    function init() {
        injectStyles();
        createNewTabButton();
    }

    init();
})();

Version 1.2

修复展开侧栏时,按钮不跟随 Gemini 文字的问题

好用,感谢佬友分享