YouTube to Gemini 自动总结与字幕

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

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

// ==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);
    }
}
})();