Greasy Fork

Greasy Fork is available in English.

YouTube to Gemini 自动总结与字幕

YouTube 首页/搜索分段缩略图网格100%修复,Gemini一键总结/字幕

当前为 2025-05-22 提交的版本,查看 最新版本

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         YouTube to Gemini 自动总结与字幕
// @namespace    http://tampermonkey.net/
// @version      2.0
// @description  YouTube 首页/搜索分段缩略图网格100%修复,Gemini一键总结/字幕
// @author       hengyu (优化 by Assistant)
// @match        *://www.youtube.com/*
// @match        *://gemini.google.com/*
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_deleteValue
// @grant        GM_addStyle
// @run-at       document-start
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    // --- 终极分段网格修复 CSS ---
    // 只对首页和搜索结果页面应用网格布局修复
    GM_addStyle(`
    /* 首页和搜索页面网格布局 */
    body[data-is-home-page="true"] ytd-rich-grid-renderer > #contents,
    body[data-page-subtype="home"] ytd-rich-grid-renderer > #contents,
    body[data-page-type="search"] ytd-rich-grid-renderer > #contents {
        display: grid !important;
        grid-template-columns: repeat(2, 1fr) !important;
        gap: 24px 16px !important;
        width: 100% !important;
        margin: 0 auto !important;
        --ytd-rich-grid-items-per-row: 2 !important;
        --ytd-rich-grid-max-width: none !important;
    }
    @media (min-width: 1000px) {
        body[data-is-home-page="true"] ytd-rich-grid-renderer > #contents,
        body[data-page-subtype="home"] ytd-rich-grid-renderer > #contents,
        body[data-page-type="search"] ytd-rich-grid-renderer > #contents {
            grid-template-columns: repeat(3, 1fr) !important;
            --ytd-rich-grid-items-per-row: 3 !important;
        }
    }
    @media (min-width: 1400px) {
        body[data-is-home-page="true"] ytd-rich-grid-renderer > #contents,
        body[data-page-subtype="home"] ytd-rich-grid-renderer > #contents,
        body[data-page-type="search"] ytd-rich-grid-renderer > #contents {
            grid-template-columns: repeat(4, 1fr) !important;
            --ytd-rich-grid-items-per-row: 4 !important;
        }
    }
    @media (min-width: 1700px) {
        body[data-is-home-page="true"] ytd-rich-grid-renderer > #contents,
        body[data-page-subtype="home"] ytd-rich-grid-renderer > #contents,
        body[data-page-type="search"] ytd-rich-grid-renderer > #contents {
            grid-template-columns: repeat(5, 1fr) !important;
            --ytd-rich-grid-items-per-row: 5 !important;
        }
    }

    /* 确保只在首页和搜索页面修改布局结构 */
    body[data-is-home-page="true"] ytd-rich-grid-row,
    body[data-is-home-page="true"] ytd-rich-grid-row > #contents,
    body[data-is-home-page="true"] ytd-rich-grid-row > #dismissible,
    body[data-is-home-page="true"] ytd-rich-grid-row > div,
    body[data-is-home-page="true"] ytd-rich-grid-row > #dismissible > #contents,
    body[data-is-home-page="true"] ytd-rich-grid-row > div > #contents,
    body[data-is-home-page="true"] ytd-rich-grid-row > div > #dismissible,
    body[data-is-home-page="true"] ytd-rich-grid-row > div > #dismissible > #contents,
    body[data-is-home-page="true"] ytd-rich-grid-row > .ytd-rich-grid-row,
    body[data-is-home-page="true"] ytd-rich-grid-row > div > .ytd-rich-grid-row,
    body[data-is-home-page="true"] ytd-rich-grid-row > div > div,
    body[data-is-home-page="true"] ytd-rich-grid-row > div > div > #contents,
    body[data-page-subtype="home"] ytd-rich-grid-row,
    body[data-page-subtype="home"] ytd-rich-grid-row > #contents,
    body[data-page-subtype="home"] ytd-rich-grid-row > #dismissible,
    body[data-page-subtype="home"] ytd-rich-grid-row > div,
    body[data-page-subtype="home"] ytd-rich-grid-row > #dismissible > #contents,
    body[data-page-subtype="home"] ytd-rich-grid-row > div > #contents,
    body[data-page-subtype="home"] ytd-rich-grid-row > div > #dismissible,
    body[data-page-subtype="home"] ytd-rich-grid-row > div > #dismissible > #contents,
    body[data-page-subtype="home"] ytd-rich-grid-row > .ytd-rich-grid-row,
    body[data-page-subtype="home"] ytd-rich-grid-row > div > .ytd-rich-grid-row,
    body[data-page-subtype="home"] ytd-rich-grid-row > div > div,
    body[data-page-subtype="home"] ytd-rich-grid-row > div > div > #contents,
    body[data-page-type="search"] ytd-rich-grid-row,
    body[data-page-type="search"] ytd-rich-grid-row > #contents,
    body[data-page-type="search"] ytd-rich-grid-row > #dismissible,
    body[data-page-type="search"] ytd-rich-grid-row > div,
    body[data-page-type="search"] ytd-rich-grid-row > #dismissible > #contents,
    body[data-page-type="search"] ytd-rich-grid-row > div > #contents,
    body[data-page-type="search"] ytd-rich-grid-row > div > #dismissible,
    body[data-page-type="search"] ytd-rich-grid-row > div > #dismissible > #contents,
    body[data-page-type="search"] ytd-rich-grid-row > .ytd-rich-grid-row,
    body[data-page-type="search"] ytd-rich-grid-row > div > .ytd-rich-grid-row,
    body[data-page-type="search"] ytd-rich-grid-row > div > div,
    body[data-page-type="search"] ytd-rich-grid-row > div > div > #contents {
        display: contents !important;
    }

    /* 视频项修复 - 仅限首页和搜索页面 */
    body[data-is-home-page="true"] ytd-rich-item-renderer,
    body[data-is-home-page="true"] ytd-grid-video-renderer,
    body[data-is-home-page="true"] ytd-rich-grid-media,
    body[data-page-subtype="home"] ytd-rich-item-renderer,
    body[data-page-subtype="home"] ytd-grid-video-renderer,
    body[data-page-subtype="home"] ytd-rich-grid-media,
    body[data-page-type="search"] ytd-rich-item-renderer,
    body[data-page-type="search"] ytd-grid-video-renderer,
    body[data-page-type="search"] ytd-rich-grid-media {
        width: 100% !important;
        max-width: none !important;
        min-width: 0 !important;
        margin: 0 !important;
        box-sizing: border-box !important;
    }

    /* 弹性项 - 仅首页和搜索页面 */
    body[data-is-home-page="true"] ytd-rich-grid-renderer > #contents > ytd-rich-section-renderer,
    body[data-is-home-page="true"] ytd-rich-grid-renderer > #contents > ytd-reel-shelf-renderer,
    body[data-page-subtype="home"] ytd-rich-grid-renderer > #contents > ytd-rich-section-renderer,
    body[data-page-subtype="home"] ytd-rich-grid-renderer > #contents > ytd-reel-shelf-renderer,
    body[data-page-type="search"] ytd-rich-grid-renderer > #contents > ytd-rich-section-renderer,
    body[data-page-type="search"] ytd-rich-grid-renderer > #contents > ytd-reel-shelf-renderer {
        grid-column: 1 / -1 !important;
        width: 100% !important;
        margin: 16px 0 !important;
    }

    /* 搜索页面修复 */
    ytd-search ytd-video-renderer {
        display: block !important;
        position: relative !important;
        z-index: 1 !important;
    }

    ytd-search ytd-thumbnail {
        position: relative !important;
        z-index: 5 !important;
    }
    `);

    // --- Gemini 按钮与交互 ---
    const PROMPT_KEY = 'geminiPrompt';
    const TITLE_KEY = 'videoTitle';
    const ORIGINAL_TITLE_KEY = 'geminiOriginalVideoTitle';
    const TIMESTAMP_KEY = 'timestamp';
    const ACTION_TYPE_KEY = 'geminiActionType';
    const VIDEO_TOTAL_DURATION_KEY = 'geminiVideoTotalDuration';
    const FIRST_SEGMENT_END_TIME_KEY = 'geminiFirstSegmentEndTime';
    const SUMMARY_BUTTON_ID = 'gemini-summarize-btn';
    const SUBTITLE_BUTTON_ID = 'gemini-subtitle-btn';
    const THUMBNAIL_BUTTON_CLASS = 'gemini-thumbnail-btn';
    const THUMBNAIL_PROCESSED_FLAG = 'data-gemini-processed';
    const YOUTUBE_NOTIFICATION_ID = 'gemini-yt-notification';
    const YOUTUBE_CONFIRMATION_ID = 'gemini-yt-confirmation';
    // 恢复原始通知样式
    const YOUTUBE_NOTIFICATION_STYLE = {
        position: 'fixed', bottom: '20px', left: '50%', transform: 'translateX(-50%)',
        backgroundColor: 'rgba(0,0,0,0.85)', color: 'white', padding: '15px 35px 15px 20px',
        borderRadius: '8px', zIndex: '99999', maxWidth: 'calc(100% - 40px)', textAlign: 'left',
        boxSizing: 'border-box', whiteSpace: 'pre-wrap',
        boxShadow: '0 4px 12px rgba(0,0,0,0.3)'
    };
    const YOUTUBE_CONFIRMATION_STYLE = {
        position: 'fixed', top: '50%', left: '50%', transform: 'translate(-50%, -50%)',
        backgroundColor: 'rgba(33, 33, 33, 0.95)', color: 'white', padding: '20px 25px',
        borderRadius: '12px', zIndex: '999999', maxWidth: 'calc(100% - 60px)', minWidth: '300px',
        boxSizing: 'border-box', boxShadow: '0 8px 24px rgba(0,0,0,0.5)',
        display: 'flex', flexDirection: 'column', gap: '15px'
    };

    // 缩略图按钮样式
    GM_addStyle(`
    .${THUMBNAIL_BUTTON_CLASS} {
        position: absolute;
        top: 5px;
        right: 5px;
        background-color: rgba(0, 0, 0, 0.7);
        color: white;
        border: none;
        border-radius: 4px;
        padding: 4px 8px;
        font-size: 12px;
        cursor: pointer;
        z-index: 120;
        display: flex;
        align-items: center;
        opacity: 0;
        transition: opacity 0.2s ease;
        pointer-events: auto !important;
    }
    #dismissible:hover .${THUMBNAIL_BUTTON_CLASS},
    ytd-grid-video-renderer:hover .${THUMBNAIL_BUTTON_CLASS},
    ytd-video-renderer:hover .${THUMBNAIL_BUTTON_CLASS},
    ytd-rich-item-renderer:hover .${THUMBNAIL_BUTTON_CLASS},
    ytd-compact-video-renderer:hover .${THUMBNAIL_BUTTON_CLASS},
    ytd-playlist-video-renderer:hover .${THUMBNAIL_BUTTON_CLASS},
    ytd-reel-item-renderer:hover .${THUMBNAIL_BUTTON_CLASS},
    ytd-search ytd-video-renderer:hover .${THUMBNAIL_BUTTON_CLASS} {
        opacity: 1 !important;
        visibility: visible !important;
        pointer-events: auto !important;
    }
    .${THUMBNAIL_BUTTON_CLASS}:hover {
        background-color: rgba(0, 0, 0, 0.9);
        opacity: 1 !important;
        visibility: visible !important;
    }

    .gemini-confirmation-btn {
        padding: 8px 20px;
        border-radius: 4px;
        border: none;
        cursor: pointer;
        font-weight: 500;
        font-size: 14px;
        transition: background-color 0.2s ease;
    }
    .gemini-confirmation-confirm {
        background-color: #1a73e8;
        color: white;
    }
    .gemini-confirmation-confirm:hover {
        background-color: #0d65d9;
    }
    .gemini-confirmation-cancel {
        background-color: #5f6368;
        color: white;
        margin-right: 10px;
    }
    .gemini-confirmation-cancel:hover {
        background-color: #494c50;
    }
    `);

    // 辅助函数
    function showNotification(elementId, message, styles, duration = 15000) {
        let existing = document.getElementById(elementId);
        if (existing) {
            clearTimeout(parseInt(existing.dataset.timeoutId));
            existing.remove();
        }
        const notif = document.createElement('div');
        notif.id = elementId;
        notif.textContent = message;
        Object.assign(notif.style, styles);
        document.body.appendChild(notif);
        const btn = document.createElement('button');
        btn.textContent = '✕';
        Object.assign(btn.style, { position: 'absolute', top: '5px', right: '10px', background: 'transparent', border: 'none', color: 'inherit', fontSize: '16px', cursor: 'pointer', padding: '0', lineHeight: '1' });
        btn.onclick = () => notif.remove();
        notif.appendChild(btn);
        notif.dataset.timeoutId = setTimeout(() => notif.remove(), duration).toString();
        return notif;
    }

    function showConfirmation(elementId, title, message, videoInfo, onConfirm, onCancel, styles) {
        let existing = document.getElementById(elementId);
        if (existing) existing.remove();

        const dialog = document.createElement('div');
        dialog.id = elementId;
        Object.assign(dialog.style, styles);
        document.body.appendChild(dialog);

        const titleElem = document.createElement('h3');
        titleElem.textContent = title;
        titleElem.style.margin = '0 0 10px 0';
        titleElem.style.fontSize = '18px';

        const messageElem = document.createElement('div');
        messageElem.textContent = message;
        messageElem.style.marginBottom = '15px';
        messageElem.style.fontSize = '14px';

        const videoTitleElem = document.createElement('div');
        videoTitleElem.textContent = `视频标题: ${videoInfo.title}`;
        videoTitleElem.style.marginBottom = '5px';
        videoTitleElem.style.fontWeight = 'bold';

        const videoIdElem = document.createElement('div');
        videoIdElem.textContent = `视频ID: ${videoInfo.id}`;
        videoIdElem.style.fontSize = '12px';
        videoIdElem.style.color = '#aaa';
        videoIdElem.style.marginBottom = '15px';

        const buttonsContainer = document.createElement('div');
        buttonsContainer.style.display = 'flex';
        buttonsContainer.style.justifyContent = 'flex-end';
        buttonsContainer.style.gap = '10px';

        const cancelBtn = document.createElement('button');
        cancelBtn.textContent = '取消';
        cancelBtn.className = 'gemini-confirmation-btn gemini-confirmation-cancel';
        cancelBtn.onclick = () => {
            dialog.remove();
            if (onCancel) onCancel();
        };

        const confirmBtn = document.createElement('button');
        confirmBtn.textContent = '确认';
        confirmBtn.className = 'gemini-confirmation-btn gemini-confirmation-confirm';
        confirmBtn.onclick = () => {
            dialog.remove();
            if (onConfirm) onConfirm(videoInfo);
        };

        buttonsContainer.appendChild(cancelBtn);
        buttonsContainer.appendChild(confirmBtn);

        dialog.appendChild(titleElem);
        dialog.appendChild(messageElem);
        dialog.appendChild(videoTitleElem);
        dialog.appendChild(videoIdElem);
        dialog.appendChild(buttonsContainer);

        return dialog;
    }

    function copyToClipboard(text) {
        navigator.clipboard.writeText(text).catch(() => {
            const ta = document.createElement('textarea');
            ta.value = text;
            ta.style.position = 'fixed'; ta.style.opacity = '0';
            document.body.appendChild(ta);
            ta.select();
            try { document.execCommand('copy'); } catch {}
            document.body.removeChild(ta);
        });
    }

    function isVideoPage() {
        return window.location.pathname === '/watch' && new URLSearchParams(window.location.search).has('v');
    }

    // 验证YouTube视频ID格式
    function isValidYouTubeVideoId(id) {
        // YouTube视频ID通常是11位字符,由字母、数字、下划线和连字符组成
        return id && typeof id === 'string' && /^[A-Za-z0-9_-]{11}$/.test(id);
    }    function getVideoInfoFromElement(element) {
        if (element.hasAttribute(THUMBNAIL_PROCESSED_FLAG)) return null;

        let videoId = '';
        let videoTitle = '';

        // 优先从数据属性中提取视频ID
        if (element.dataset && element.dataset.videoId) {
            videoId = element.dataset.videoId;
        } else if (element.getAttribute('video-id')) {
            videoId = element.getAttribute('video-id');
        }

        // 尝试从各种可能的属性和元素中提取视频ID
        if (!isValidYouTubeVideoId(videoId)) {
            // 1. 首先从链接中查找
            const linkElements = Array.from(element.querySelectorAll('a[href*="/watch?v="]'));
            for (const link of linkElements) {
                const match = link.href.match(/\/watch\?v=([^&]+)/);
                if (match && match[1] && isValidYouTubeVideoId(match[1])) {
                    videoId = match[1];
                    break;
                }
            }

            // 2. 从缩略图元素寻找
            if (!isValidYouTubeVideoId(videoId)) {
                const thumbnailElements = element.querySelectorAll('img[src*="/vi/"], img[src*="i.ytimg.com"]');
                for (const img of thumbnailElements) {
                    const match = img.src.match(/\/vi\/([^\/]+)\//) || img.src.match(/\/([A-Za-z0-9_-]{11})\/[\w]+\.jpg/);
                    if (match && match[1] && isValidYouTubeVideoId(match[1])) {
                        videoId = match[1];
                        break;
                    }
                }
            }

            // 3. 从缩略图容器data属性获取
            if (!isValidYouTubeVideoId(videoId)) {
                const thumbnails = element.querySelectorAll('#thumbnail, .thumbnail, ytd-thumbnail');
                for (const thumb of thumbnails) {
                    if (thumb.dataset && thumb.dataset.videoId && isValidYouTubeVideoId(thumb.dataset.videoId)) {
                        videoId = thumb.dataset.videoId;
                        break;
                    }

                    // 来自href属性
                    if (thumb.tagName === 'A' && thumb.href) {
                        const match = thumb.href.match(/\/watch\?v=([^&]+)/);
                        if (match && match[1] && isValidYouTubeVideoId(match[1])) {
                            videoId = match[1];
                            break;
                        }
                    }
                }
            }

            // 4. 从视频渲染器元素获取
            if (!isValidYouTubeVideoId(videoId)) {
                const renderers = element.closest('ytd-rich-item-renderer, ytd-grid-video-renderer, ytd-video-renderer, ytd-compact-video-renderer');
                if (renderers && renderers.dataset && renderers.dataset.videoId && isValidYouTubeVideoId(renderers.dataset.videoId)) {
                    videoId = renderers.dataset.videoId;
                }
            }
        }

        // 增强标题提取方法
        const titleSelectors = [
            '#video-title',
            '.title',
            '[title]',
            'h3 a',
            'h3',
            'a[title]',
            'span[title]',
            'yt-formatted-string',
            '[aria-label]'
        ];

        for (const selector of titleSelectors) {
            const titleElements = element.querySelectorAll(selector);
            for (const titleElement of titleElements) {
                const possibleTitle = titleElement.textContent?.trim() ||
                                     titleElement.getAttribute('title')?.trim() ||
                                     titleElement.getAttribute('aria-label')?.trim();
                if (possibleTitle && possibleTitle.length > 5) {
                    videoTitle = possibleTitle;
                    break;
                }
            }
            if (videoTitle) break;
        }

        // 最后验证结果
        if (!isValidYouTubeVideoId(videoId) || !videoTitle) {
            return null;
        }

        return {
            id: videoId,
            title: videoTitle,
            url: `https://www.youtube.com/watch?v=${videoId}`
        };
    }

    function processVideoSummary(videoInfo) {
        const prompt = `请分析这个YouTube视频: ${videoInfo.url}\n\n提供一个全面的摘要,包括主要观点、关键见解和视频中讨论的重要细节,以结构化的方式分解内容,并包括任何重要的结论或要点。`;

        GM_setValue(PROMPT_KEY, prompt);
        GM_setValue(TITLE_KEY, videoInfo.title);
        GM_setValue(ORIGINAL_TITLE_KEY, videoInfo.title);
        GM_setValue(TIMESTAMP_KEY, Date.now());
        GM_setValue(ACTION_TYPE_KEY, 'summary');

        window.open('https://gemini.google.com/', '_blank');

        showNotification(
            YOUTUBE_NOTIFICATION_ID,
            `已跳转到 Gemini!\n系统将尝试自动输入提示词并发送请求。\n\n视频: "${videoInfo.title}"\n\n(如果自动操作失败,提示词已复制到剪贴板,请手动粘贴)`,
            YOUTUBE_NOTIFICATION_STYLE,
            10000
        );

        copyToClipboard(prompt);
    }

    function handleThumbnailButtonClick(event, videoInfo) {
        if (event) {
            event.preventDefault();
            event.stopPropagation();
            event.stopImmediatePropagation();

            // 确保不会触发原始点击事件
            if (event.cancelable) event.returnValue = false;
        }

        if (!videoInfo || !videoInfo.url || !videoInfo.title) {
            showNotification(
                YOUTUBE_NOTIFICATION_ID,
                "无法获取视频信息,请尝试直接在视频页面使用总结功能。",
                { ...YOUTUBE_NOTIFICATION_STYLE, backgroundColor: '#d93025' },
                5000
            );
            return false;
        }

        // 验证视频ID
        if (!isValidYouTubeVideoId(videoInfo.id)) {
            showNotification(
                YOUTUBE_NOTIFICATION_ID,
                `获取到的视频ID格式无效: ${videoInfo.id}\n请尝试直接在视频页面使用总结功能。`,
                { ...YOUTUBE_NOTIFICATION_STYLE, backgroundColor: '#d93025' },
                5000
            );
            return false;
        }

        // 显示确认对话框 - 保留缩略图总结的二次确认
        showConfirmation(
            YOUTUBE_CONFIRMATION_ID,
            "确认视频信息",
            "请确认以下视频信息是否正确:",
            videoInfo,
            processVideoSummary,
            null,
            YOUTUBE_CONFIRMATION_STYLE
        );

        return false;
    }

    function addThumbnailButtons() {
        if (isVideoPage()) return;

        const isSearchPage = window.location.pathname === '/results';
        const videoElementSelectors = [
            'ytd-rich-item-renderer',
            'ytd-grid-video-renderer',
            'ytd-video-renderer',
            'ytd-compact-video-renderer',
            'ytd-playlist-video-renderer',
            'ytd-reel-item-renderer',
            '.ytd-video-preview',
            '.video-card',
            '.ytd-compact-playlist-renderer',
            'ytd-grid-playlist-renderer'
        ];

        if (isSearchPage) videoElementSelectors.push('ytd-search ytd-video-renderer');

        document.querySelectorAll(videoElementSelectors.join(',')).forEach(element => {
            if (element.hasAttribute(THUMBNAIL_PROCESSED_FLAG) || element.querySelector(`.${THUMBNAIL_BUTTON_CLASS}`)) {
                element.setAttribute(THUMBNAIL_PROCESSED_FLAG, 'true');
                return;
            }

            // 增强缩略图容器选择
            let thumbnailContainer = isSearchPage ?
                (element.querySelector('ytd-thumbnail') || element.querySelector('a#thumbnail') || element.querySelector('[id="thumbnail"]')) :
                element.querySelector('#thumbnail, .thumbnail, a[href*="/watch"], ytd-thumbnail');

            if (!thumbnailContainer) return;

            const videoInfo = getVideoInfoFromElement(element);
            if (!videoInfo) return;

            const button = document.createElement('button');
            button.className = THUMBNAIL_BUTTON_CLASS;
            button.textContent = '📝 总结';
            button.title = '使用Gemini总结此视频';

            // 增强事件处理
            const eventHandler = (e) => {
                if (e.type === 'click') {
                    return handleThumbnailButtonClick(e, videoInfo);
                } else {
                    e.stopPropagation();
                    e.preventDefault();
                    if (e.cancelable) e.returnValue = false;
                    return false;
                }
            };

            ['click', 'mousedown', 'mouseup', 'touchstart', 'touchend'].forEach(type => {
                button.addEventListener(type, eventHandler, { capture: true, passive: false });
            });

            if (getComputedStyle(thumbnailContainer).position === 'static') {
                thumbnailContainer.style.position = 'relative';
            }

            if (isSearchPage) {
                Object.assign(button.style, {
                    zIndex: '999',
                    pointerEvents: 'auto',
                    position: 'absolute',
                    top: '5px',
                    right: '5px'
                });
            }

            thumbnailContainer.appendChild(button);
            element.setAttribute(THUMBNAIL_PROCESSED_FLAG, 'true');
        });
    }

    function setupThumbnailButtonSystem() {
        addThumbnailButtons();

        const obs = new MutationObserver(() => setTimeout(addThumbnailButtons, 300));
        obs.observe(document.body, { childList: true, subtree: true });

        setInterval(() => {
            if (!isVideoPage()) addThumbnailButtons();
        }, 1500);

        window.addEventListener('load', () => setTimeout(addThumbnailButtons, 1000));
    }

   function addYouTubeActionButtons() {
    if (!isVideoPage()) {
        removeYouTubeActionButtonsIfExists();
        return;
    }

    if (document.getElementById(SUMMARY_BUTTON_ID) || document.getElementById(SUBTITLE_BUTTON_ID)) return;

    // 寻找顶部导航区域 - 搜索框右侧的区域
    const container = document.querySelector('#end') ||
                      document.querySelector('ytd-masthead #container') ||
                      document.querySelector('ytd-masthead');

    if (!container) return;

    // 创建一个容器包装我们的按钮
    const buttonsWrapper = document.createElement('div');
    buttonsWrapper.style.display = 'inline-flex';
    buttonsWrapper.style.alignItems = 'center';
    buttonsWrapper.style.marginRight = '16px';

    const subtitleButton = document.createElement('button');
    subtitleButton.id = SUBTITLE_BUTTON_ID;
    subtitleButton.textContent = '🎯 生成字幕';
    Object.assign(subtitleButton.style, {
        backgroundColor: '#28a745',
        color: 'white',
        border: 'none',
        borderRadius: '18px',
        padding: '0 16px',
        margin: '0 8px 0 0',
        cursor: 'pointer',
        fontWeight: '500',
        height: '36px',
        display: 'inline-flex',
        alignItems: 'center',
        justifyContent: 'center',
        fontSize: '14px',
        zIndex: '100',
        whiteSpace: 'nowrap',
        transition: 'all 0.2s ease'
    });

    const summaryButton = document.createElement('button');
    summaryButton.id = SUMMARY_BUTTON_ID;
    summaryButton.textContent = '📝 Gemini摘要';
    Object.assign(summaryButton.style, {
        backgroundColor: '#1a73e8',
        color: 'white',
        border: 'none',
        borderRadius: '18px',
        padding: '0 16px',
        margin: '0',
        cursor: 'pointer',
        fontWeight: '500',
        height: '36px',
        display: 'inline-flex',
        alignItems: 'center',
        justifyContent: 'center',
        fontSize: '14px',
        zIndex: '100',
        whiteSpace: 'nowrap',
        transition: 'all 0.2s ease'
    });

    // 为移动设备添加响应式适应
    const mediaQuery = window.matchMedia('(max-width: 768px)');
    const adjustForMobile = () => {
        if (mediaQuery.matches) {
            subtitleButton.style.fontSize = '12px';
            subtitleButton.style.padding = '0 10px';
            subtitleButton.style.height = '32px';
            summaryButton.style.fontSize = '12px';
            summaryButton.style.padding = '0 10px';
            summaryButton.style.height = '32px';
        } else {
            subtitleButton.style.fontSize = '14px';
            subtitleButton.style.padding = '0 16px';
            subtitleButton.style.height = '36px';
            summaryButton.style.fontSize = '14px';
            summaryButton.style.padding = '0 16px';
            summaryButton.style.height = '36px';
        }
    };

    mediaQuery.addEventListener('change', adjustForMobile);
    adjustForMobile();

    subtitleButton.addEventListener('click', handleGenerateSubtitlesClick);
    summaryButton.addEventListener('click', handleSummarizeClick);

    buttonsWrapper.appendChild(subtitleButton);
    buttonsWrapper.appendChild(summaryButton);

    // 将按钮添加到顶部导航区域
    // 在创建按钮之前插入
    const createButton = container.querySelector('#create-icon') || container.querySelector('button[aria-label*="创建"]');
    if (createButton) {
        container.insertBefore(buttonsWrapper, createButton);
    } else {
        // 如果找不到创建按钮,就插入到容器前面
        container.insertBefore(buttonsWrapper, container.firstChild);
    }
}
    // 视频页面摘要函数 - 移除确认步骤,直接处理
    function handleSummarizeClick() {
        const youtubeUrl = window.location.href;

        // 从URL获取视频ID并验证
        const urlParams = new URLSearchParams(window.location.search);
        const videoId = urlParams.get('v');

        if (!isValidYouTubeVideoId(videoId)) {
            showNotification(
                YOUTUBE_NOTIFICATION_ID,
                "无法获取有效的视频ID,请确认当前是否在YouTube视频页面。",
                { ...YOUTUBE_NOTIFICATION_STYLE, backgroundColor: '#d93025' },
                5000
            );
            return;
        }

        // 增强标题选择
        const titleSelectors = [
            'h1.ytd-watch-metadata',
            '#video-title',
            '#title h1',
            '.title',
            'yt-formatted-string.ytd-watch-metadata'
        ];

        let videoTitle = '';
        for (const selector of titleSelectors) {
            const titleElement = document.querySelector(selector);
            if (titleElement) {
                videoTitle = titleElement.textContent?.trim();
                if (videoTitle) break;
            }
        }

        if (!videoTitle) {
            videoTitle = document.title.replace(/ - YouTube$/, '').trim() || 'Unknown Video';
        }

        const videoInfo = {
            id: videoId,
            title: videoTitle,
            url: youtubeUrl
        };

        // 直接处理,不显示确认对话框
        processVideoSummary(videoInfo);
    }

    // 完全保留原始字幕生成函数
    function handleGenerateSubtitlesClick() {
        const youtubeUrl = window.location.href;
        const titleElement = document.querySelector('h1.ytd-watch-metadata, #video-title, #title h1, .title');
        const videoTitle = titleElement?.textContent?.trim() || document.title.replace(/ - YouTube$/, '').trim() || 'Unknown Video';
        let videoDurationInSeconds = 0;
        const durationMeta = document.querySelector('meta[itemprop="duration"]');
        if (durationMeta?.content) {
            const match = durationMeta.content.match(/PT(\d+H)?(\d+M)?(\d+S)?/);
            if (match) {
                videoDurationInSeconds = 0;
                if (match[1]) videoDurationInSeconds += parseInt(match[1].replace('H', '')) * 3600;
                if (match[2]) videoDurationInSeconds += parseInt(match[2].replace('M', '')) * 60;
                if (match[3]) videoDurationInSeconds += parseInt(match[3].replace('S', ''));
            }
        }

        if (videoDurationInSeconds <= 0) {
            showNotification(YOUTUBE_NOTIFICATION_ID, "无法获取视频时长,无法启动字幕任务。", { ...YOUTUBE_NOTIFICATION_STYLE, backgroundColor: '#d93025' }, 15000); return;
        }

        const firstSegmentEnd = Math.min(videoDurationInSeconds, 1200);
        const prompt = `${youtubeUrl}\n1.不要添加自己的语言\n2.变成简体中文,流畅版本。\n\nYouTube\n请提取此视频从00:00:00到${new Date(firstSegmentEnd * 1000).toISOString().substr(11, 8)}的完整字幕文本。`;

        GM_setValue(PROMPT_KEY, prompt);
        GM_setValue(TITLE_KEY, `${videoTitle} (字幕 00:00:00-${new Date(firstSegmentEnd * 1000).toISOString().substr(11, 8)})`);
        GM_setValue(ORIGINAL_TITLE_KEY, videoTitle);
        GM_setValue(TIMESTAMP_KEY, Date.now());
        GM_setValue(ACTION_TYPE_KEY, 'subtitle');
        GM_setValue(VIDEO_TOTAL_DURATION_KEY, videoDurationInSeconds);
        GM_setValue(FIRST_SEGMENT_END_TIME_KEY, firstSegmentEnd);

        showNotification(YOUTUBE_NOTIFICATION_ID, `已跳转到 Gemini 生成字幕: 00:00:00 - ${new Date(firstSegmentEnd * 1000).toISOString().substr(11, 8)}...\n"${videoTitle}"`, YOUTUBE_NOTIFICATION_STYLE, 15000);
        window.open('https://gemini.google.com/', '_blank');
        copyToClipboard(prompt);
    }

    function removeYouTubeActionButtonsIfExists() {
        [SUMMARY_BUTTON_ID, SUBTITLE_BUTTON_ID].forEach(id => {
            const button = document.getElementById(id);
            if (button) button.remove();
        });
    }

    // --- 页面类型检测函数 ---
    function detectYouTubePageType() {
        // 确保body元素存在
        if (!document.body) return;

        // 确定页面类型
        let isHomePage = window.location.pathname === '/' || window.location.pathname === '/feed/subscriptions';
        let isChannelPage = window.location.pathname.includes('/channel/') ||
                          window.location.pathname.includes('/c/') ||
                          window.location.pathname.includes('/user/') ||
                          window.location.pathname.includes('/@');
        let isSearchPage = window.location.pathname === '/results';

        // 添加页面类型属性
        if (isHomePage) {
            document.body.setAttribute('data-is-home-page', 'true');
            document.body.setAttribute('data-page-subtype', 'home');
        } else {
            document.body.removeAttribute('data-is-home-page');
        }

        if (isChannelPage) {
            document.body.setAttribute('data-page-subtype', 'channels');
        } else if (isSearchPage) {
            document.body.setAttribute('data-page-type', 'search');
        }
    }

// --- 页面初始化 ---
if (window.location.hostname.includes('www.youtube.com')) {
    // 检测页面类型并设置相应的属性
    detectYouTubePageType();

    // 当URL变化时重新检测页面类型
    let lastUrl = location.href;
    const urlObserver = new MutationObserver(() => {
        if (location.href !== lastUrl) {
            lastUrl = location.href;
            setTimeout(() => {
                detectYouTubePageType();
                if (isVideoPage()) {
                    addYouTubeActionButtons();
                } else {
                    removeYouTubeActionButtonsIfExists();
                }
            }, 1000);
        }
    });

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

    if (document.readyState === 'complete' || document.readyState === 'interactive') {
        setupThumbnailButtonSystem();
        setTimeout(addYouTubeActionButtons, 1000);

        // 每隔一段时间检查视频页面按钮
        setInterval(() => {
            if (isVideoPage()) {
                if (!document.getElementById(SUMMARY_BUTTON_ID) || !document.getElementById(SUBTITLE_BUTTON_ID)) {
                    addYouTubeActionButtons();
                }
            }
            // 重新检测页面类型
            detectYouTubePageType();
        }, 5000);
    } else {
        document.addEventListener('DOMContentLoaded', () => {
            detectYouTubePageType();
            setupThumbnailButtonSystem();
            setTimeout(addYouTubeActionButtons, 1000);
        }, { once: true });
    }
} else if (window.location.hostname.includes('gemini.google.com')) {
    // Gemini自动填充 - 简化版,删除了所有自动分段处理
    const prompt = GM_getValue(PROMPT_KEY);
    const timestamp = GM_getValue(TIMESTAMP_KEY, 0);
    const actionType = GM_getValue(ACTION_TYPE_KEY);

    // 检查是否有有效的待处理请求且来源是YouTube
    const referrerIsYouTube = document.referrer.includes('youtube.com');
    if (prompt && actionType && Date.now() - timestamp <= 300000 && referrerIsYouTube) {
        setTimeout(() => {
            const textarea = document.querySelector('textarea, div[contenteditable="true"]');
            if (textarea) {
                if (textarea.isContentEditable) textarea.textContent = prompt;
                else textarea.value = prompt;

                textarea.dispatchEvent(new Event('input', { bubbles: true, cancelable: true }));
                textarea.dispatchEvent(new Event('change', { bubbles: true, cancelable: true }));

                setTimeout(() => {
                    const sendBtn = document.querySelector('button[aria-label*="Send"],button[aria-label*="发送"],button[aria-label*="提交"],button[aria-label*="Run"],button[aria-label*="Submit"]');
                    if (sendBtn && !sendBtn.disabled) {
                        sendBtn.click();

                        // 单次操作完成后清理数据
                        setTimeout(() => {
                            GM_deleteValue(PROMPT_KEY);
                            GM_deleteValue(TITLE_KEY);
                            GM_deleteValue(ORIGINAL_TITLE_KEY);
                            GM_deleteValue(TIMESTAMP_KEY);
                            GM_deleteValue(ACTION_TYPE_KEY);
                            GM_deleteValue(VIDEO_TOTAL_DURATION_KEY);
                            GM_deleteValue(FIRST_SEGMENT_END_TIME_KEY);
                        }, 5000); // 延迟清理以确保提交后处理完成
                    }
                }, 500);
            }
        }, 1200);
    }
}
})();