Greasy Fork

Greasy Fork is available in English.

超级助手面板 (链接新标签页+Cookie+AI媒体下载)

功能集成:1. 链接新标签页打开(白名单启用模式)。2. Cookie管理。3. AI媒体内容下载(作者:醉春风)。均通过右下角UI面板操作。

当前为 2025-06-02 提交的版本,查看 最新版本

// ==UserScript==
// @name         超级助手面板 (链接新标签页+Cookie+AI媒体下载)
// @name:en      Super Assistant Panel (New Tab Links, Cookies, AI Media Downloader)
// @namespace    http://greasyfork.icu/users/your-username // 建议替换为你的唯一命名空间
// @version      1.7.1
// @description  功能集成:1. 链接新标签页打开(白名单启用模式)。2. Cookie管理。3. AI媒体内容下载(作者:醉春风)。均通过右下角UI面板操作。
// @description:en Integrated: 1. Force links in new tab (whitelist mode). 2. Cookie management. 3. AI Media Downloader (Author: 醉春风). All via a UI panel.
// @author       AI Assistant (AI Media Downloader features by 醉春风)
// @match        *://*/*
// @grant        GM_openInTab
// @grant        window.open
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_registerMenuCommand
// @grant        GM_addStyle
// @grant        GM_setClipboard
// @grant        GM_download
// @grant        GM_xmlhttpRequest
// @license MIT
// ==/UserScript==

(function() {
    'use strict';

    // *************************************************************************************
    // * 主脚本部分 (链接新标签页打开 + Cookie管理 + 主UI面板框架)                           *
    // *************************************************************************************
    const MAIN_DEBUG = true; // 设置为 true 来查看主面板的调试日志
    const main_log = (...args) => { if (MAIN_DEBUG) console.log('[主助手面板]', ...args); };

    const MAIN_SCRIPT_CONFIG = {
        whitelistKey: 'openInNewTab_custom_whitelist_v1',
        blacklistKey: 'openInNewTab_custom_blacklist_v1',
        panelVisibleKey: 'openInNewTab_panelVisibleState_v1',
        defaultWhitelist: [],
        defaultBlacklist: []
    };

    let main_userWhitelist = [];
    let main_userBlacklist = [];
    let main_panelVisible = GM_getValue(MAIN_SCRIPT_CONFIG.panelVisibleKey, false);
    main_log("脚本加载,初始面板可见状态 (从存储读取):", main_panelVisible);
    let main_uiPanel = null;

    GM_addStyle(`
        #superAssistantPanel {
            position: fixed !important;
            right: 15px !important; /* 定位到右侧 */
            bottom: 15px !important; /* 定位到下方 */
            left: auto !important;
            top: auto !important;
            width: 320px;
            max-height: calc(90vh - 30px); background-color: #f0f2f5;
            border: 1px solid #d9d9d9; border-radius: 8px; padding: 10px;
            z-index: 2147483640 !important; /* 主面板的 z-index */
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";
            font-size: 13px; color: #333; box-shadow: 0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 9px 28px 8px rgba(0, 0, 0, 0.05);
            display: none !important; /* 默认隐藏 */
            flex-direction: column;
            line-height: 1.5;
        }
        #superAssistantPanel.panel-visible { /* 当此类存在时显示 */
            display: flex !important;
        }
        #superAssistantPanel .panel-header { text-align: center; font-size: 16px; font-weight: 600; color: #2c3e50; padding-bottom: 8px; margin-bottom: 8px; border-bottom: 1px solid #e8e8e8;}
        #superAssistantPanel .panel-content-scrollable { overflow-y: auto; flex-grow: 1; margin-bottom: 8px; padding-right: 5px; }
        #superAssistantPanel .section-title { margin-top: 8px; margin-bottom: 6px; font-size: 14px; font-weight: 500; color: #34495e; padding-bottom: 4px; border-bottom: 1px dashed #bdc3c7; }
        #superAssistantPanel .add-form { display: flex; margin-bottom: 8px; }
        #superAssistantPanel .add-form input[type="text"] { flex-grow: 1; margin-right: 6px; padding: 5px 8px; border: 1px solid #ccc; border-radius: 4px; font-size: 12px; }
        #superAssistantPanel .add-form button { padding: 5px 10px; font-size: 12px; color: white; background-color: #3498db; border: none; border-radius: 4px; cursor: pointer; white-space: nowrap; }
        #superAssistantPanel .add-form button:hover { background-color: #2980b9; }
        #superAssistantPanel ul { list-style-type: none; padding-left: 0; margin: 0 0 8px 0; border: 1px solid #ecf0f1; border-radius: 4px; background-color: #fff; }
        #superAssistantPanel li { padding: 6px 8px; border-bottom: 1px solid #f5f7fa; display: flex; align-items: center; justify-content: space-between; font-size: 12px; }
        #superAssistantPanel li:last-child { border-bottom: none; }
        #superAssistantPanel li .pattern-text { word-break: break-all; margin-right: 6px; flex-grow: 1; line-height: 1.4; }
        #superAssistantPanel .delete-btn { color: #e74c3c; background-color: transparent; border: none; cursor: pointer; font-weight: bold; font-size: 18px; padding: 0 4px; line-height: 1; opacity: 0.7; }
        #superAssistantPanel .delete-btn:hover { opacity: 1; }
        #superAssistantPanel .panel-empty-msg { font-size: 12px; color: #7f8c8d; padding: 8px; text-align: center; background-color: #fff; border-radius: 4px; }
        #superAssistantPanel .cookie-section { margin-top: 10px; }
        #superAssistantPanel .cookie-display { width: calc(100% - 12px); min-height: 60px; max-height:100px; margin-top: 4px; margin-bottom: 6px; padding: 5px; border: 1px solid #ccc; border-radius: 4px; font-size: 11px; word-break: break-all; overflow-y: auto; line-height: 1.4; background:#fff; }
        #superAssistantPanel .actions-group { display: flex; justify-content: space-between; gap: 8px; margin-top: 6px; }
        #superAssistantPanel .actions-group button { padding: 6px 0; font-size: 12px; color: white; border-radius: 4px; cursor: pointer; flex-grow: 1; border:none; }
        #superAssistantPanel .actions-group .btn-primary { background-color: #3498db; } #superAssistantPanel .actions-group .btn-primary:hover { background-color: #2980b9; }
        #superAssistantPanel .actions-group .btn-secondary { background-color: #2ecc71; } #superAssistantPanel .actions-group .btn-secondary:hover { background-color: #27ae60; }
        #superAssistantPanel .actions-group .btn-info { background-color: #1abc9c; } #superAssistantPanel .actions-group .btn-info:hover { background-color: #16a085; }
        #superAssistantPanel .close-panel-btn { display: block; width: 100%; padding: 7px 10px; font-size: 13px; color: #fff; background-color: #95a5a6; border: none; border-radius: 4px; cursor: pointer; margin-top:10px; }
        #superAssistantPanel .close-panel-btn:hover { background-color: #7f8c8d; }
        #superAssistantPanel .ai-downloader-author { font-size: 10px; color: #7f8c8d; text-align: right; margin-top: 4px; }

        /* AI Downloader Panel Styles (manus-ai-*) - 这些是AI下载模块自己的UI,层级更高 */
        .manus-ai-preview-panel { /* AI下载模块的媒体选择面板,从右侧滑出 */
            position: fixed !important; top: 0 !important; right: 0 !important; width: 320px !important;
            height: 100% !important; background: rgba(26, 26, 26, 0.98) !important;
            border-radius: 0 !important; box-shadow: -5px 0 15px rgba(0, 0, 0, 0.2) !important;
            z-index: 2147483646 !important; /* 比主面板高 */ display: flex !important; flex-direction: column !important;
            transform: translateX(100%) !important; transition: transform 0.35s ease-out !important;
            color: white !important; font-family: sans-serif !important; border-left: 1px solid #3a8ffe !important;
        }
        .manus-ai-preview-panel.show { transform: translateX(0) !important; }
        /* ... (AI下载模块的其他CSS,与之前版本类似,确保z-index高于主面板) ... */
        .manus-ai-preview-header { display: flex !important; justify-content: space-between !important; align-items: center !important; padding: 10px 12px !important; border-bottom: 1px solid rgba(255, 255, 255, 0.1) !important; flex-shrink: 0 !important; background-color: rgba(0,0,0,0.2); }
        .manus-ai-preview-title { color: white !important; font-size: 15px !important; font-weight: bold !important; }
        .manus-ai-author-credit { color: #ffcc00 !important; font-size: 11px !important; font-style: italic !important; margin-left: 8px !important; font-weight: normal !important; }
        .manus-ai-preview-close { color: white !important; background: none !important; border: none !important; cursor: pointer !important; font-size: 20px !important; padding: 5px !important; line-height:1; opacity: 0.7; }
        .manus-ai-preview-close:hover { opacity: 1; background: rgba(255,255,255,0.1) !important; border-radius: 50%;}
        .manus-ai-preview-toolbar { display: flex !important; padding: 8px 12px !important; border-bottom: 1px solid rgba(255, 255, 255, 0.1) !important; gap: 6px !important; flex-wrap: wrap !important; flex-shrink: 0 !important; background-color: rgba(0,0,0,0.1); }
        .manus-ai-preview-toolbar button { background: rgba(255, 255, 255, 0.1) !important; color: white !important; border: none !important; border-radius: 3px !important; padding: 5px 8px !important; font-size: 12px !important; cursor: pointer !important; transition: background 0.2s !important; }
        .manus-ai-preview-toolbar button:hover { background: rgba(255, 255, 255, 0.2) !important; }
        .manus-ai-preview-counter { margin-left: auto !important; color: rgba(255, 255, 255, 0.8) !important; font-size: 12px !important; display: flex !important; align-items: center !important; }
        .manus-ai-preview-content { flex: 1 !important; overflow-y: auto !important; padding: 10px !important; display: grid !important; grid-template-columns: repeat(auto-fill, minmax(75px, 1fr)) !important; gap: 8px !important; }
        .manus-ai-preview-content::-webkit-scrollbar { width: 5px !important; }
        .manus-ai-preview-content::-webkit-scrollbar-track { background: rgba(0, 0, 0, 0.1) !important; }
        .manus-ai-preview-content::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.25) !important; border-radius: 3px !important; }
        .manus-ai-media-item { position: relative !important; width: 100% !important; padding-bottom: 100% !important; border-radius: 3px !important; overflow: hidden !important; cursor: pointer !important; transition: transform 0.15s, box-shadow 0.15s !important; background-color: #222 !important; }
        .manus-ai-media-item:hover { transform: scale(1.03) !important; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.4) !important; z-index: 1 !important; }
        .manus-ai-media-item.selected { border: 2px solid #007bff !important; box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.25) !important; }
        .manus-ai-media-thumbnail-container { position: absolute !important; top: 0 !important; left: 0 !important; width: 100% !important; height: 100% !important; display: flex !important; align-items: center !important; justify-content: center !important; background-color: #282c34 !important; }
        .manus-ai-media-thumbnail-container svg { width: 28px !important; height: 28px !important; opacity: 0.7 !important; fill: none !important; stroke: #ccc !important; stroke-width: 1.5 !important; stroke-linecap: round !important; stroke-linejoin: round !important; }
        .manus-ai-media-checkbox { position: absolute !important; top: 4px !important; right: 4px !important; width: 16px !important; height: 16px !important; border: 1.5px solid white !important; border-radius: 2px !important; background: rgba(0, 0, 0, 0.6) !important; display: flex !important; align-items: center !important; justify-content: center !important; transition: background 0.2s !important; z-index: 3 !important; }
        .manus-ai-media-checkbox.checked { background: #007bff !important; border-color: #007bff !important; }
        .manus-ai-media-checkbox.checked::after { content: "" !important; width: 8px !important; height: 4px !important; border-left: 2px solid white !important; border-bottom: 2px solid white !important; transform: rotate(-45deg) translate(0px, -1px) !important; }
        .manus-ai-media-item.video .manus-ai-media-thumbnail-container::before { content: "▶"; position: absolute; font-size: 20px; color: rgba(255,255,255,0.7); z-index: 1; opacity: 0.8; text-shadow: 0 0 3px black;}
        .manus-ai-media-duration { position: absolute !important; bottom: 4px !important; right: 4px !important; background: rgba(0, 0, 0, 0.75) !important; color: white !important; font-size: 9px !important; padding: 1px 3px !important; border-radius: 2px !important; z-index: 3 !important; }
        .manus-ai-preview-footer { padding: 8px 12px !important; border-top: 1px solid rgba(255, 255, 255, 0.1) !important; display: flex !important; justify-content: space-between !important; flex-shrink: 0 !important; background-color: rgba(0,0,0,0.2); }
        .manus-ai-download-btn { background: linear-gradient(135deg, #007bff 0%, #0056b3 100%) !important; color: white !important; border: none !important; border-radius: 3px !important; padding: 6px 12px !important; font-size: 13px !important; font-weight: bold !important; cursor: pointer !important; transition: all 0.2s !important; display: flex !important; align-items: center !important; }
        .manus-ai-download-btn svg { margin-right: 5px !important; fill: none !important; stroke: white !important; stroke-width: 2 !important; stroke-linecap: round !important; stroke-linejoin: round !important; width: 14px; height: 14px; }
        .manus-ai-download-btn:hover { transform: translateY(-1px) !important; box-shadow: 0 2px 5px rgba(0, 0, 0, 0.25) !important; }
        .manus-ai-download-btn:disabled { background: #555 !important; cursor: not-allowed !important; transform: none !important; box-shadow: none !important; opacity:0.7; }
        .manus-ai-cancel-btn { background: rgba(255, 255, 255, 0.15) !important; color: white !important; border: none !important; border-radius: 3px !important; padding: 6px 12px !important; font-size: 13px !important; cursor: pointer !important; transition: background 0.2s !important; }
        .manus-ai-cancel-btn:hover { background: rgba(255, 255, 255, 0.25) !important; }
        .manus-ai-downloader-notification, .manus-ai-downloader-error {
            position: fixed !important; top: 20px !important; right: 20px !important;
            background: rgba(0, 0, 0, 0.85) !important; color: white !important;
            padding: 10px 15px !important; border-radius: 4px !important;
            z-index: 2147483647 !important; font-size: 14px !important;
            max-width: 300px !important; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2) !important;
            opacity: 0; animation: manusAiFadeInAndOut 3s ease-in-out forwards !important;
        }
        .manus-ai-downloader-error { background: rgba(220, 53, 69, 0.9) !important; animation-duration: 3.5s !important; }
        .manus-ai-downloader-error svg { margin-right: 8px; vertical-align: middle; }
        @keyframes manusAiFadeInAndOut {
            0%, 100% { opacity: 0; transform: translateY(-10px); }
            10%, 90% { opacity: 1; transform: translateY(0); }
        }
    `);

    function main_getPageCookies() { return document.cookie; }
    function main_copyToClipboard(text) {
        if (typeof GM_setClipboard === 'function') {
            GM_setClipboard(text, 'text'); alert('内容已复制到剪贴板! (GM)');
        } else {
            const textarea = document.createElement('textarea');
            textarea.value = text; textarea.style.position = 'fixed'; textarea.style.top = '-9999px'; textarea.style.left = '-9999px';
            document.body.appendChild(textarea); textarea.focus(); textarea.select();
            try { if (document.execCommand('copy')) alert('内容已复制到剪贴板!'); else prompt('复制失败,请手动复制:', text);
            } catch (err) { prompt('复制操作异常,请手动复制:', text); }
            document.body.removeChild(textarea);
        }
    }

    function main_createAddForm(listType, listArray, configKey, parentElement) {
        const form = document.createElement('div'); form.className = 'add-form';
        const input = document.createElement('input'); input.type = 'text';
        input.placeholder = `添加${listType === 'whitelist' ? '白' : '黑'}名单模式...`;
        input.addEventListener('keypress', (e) => { if (e.key === 'Enter') addButton.click(); });
        const addButton = document.createElement('button'); addButton.textContent = '添加';
        addButton.onclick = () => {
            const pattern = input.value.trim();
            if (pattern) {
                if (listArray.includes(pattern)) { alert(`模式 "${pattern}" 已存在!`); return; }
                listArray.push(pattern); GM_setValue(configKey, listArray.join(','));
                input.value = ''; main_renderListsUI();
            } else { alert('请输入有效的URL模式!'); }
        };
        form.appendChild(input); form.appendChild(addButton); parentElement.appendChild(form);
    }

    function main_createUIPanel() {
        main_log("main_createUIPanel 调用");
        if (!document.body) { main_log("document.body 未准备好,延迟创建"); setTimeout(main_createUIPanel, 100); return; }
        if (document.getElementById('superAssistantPanel')) {
            main_log("面板已存在,仅更新状态和内容");
            main_uiPanel = document.getElementById('superAssistantPanel');
            main_renderListsUI();
            main_uiPanel.classList.toggle('panel-visible', main_panelVisible);
            main_log("面板已存在,切换后 classList:", main_uiPanel.classList);
            return;
        }
        main_log("创建新的UI面板DOM");
        main_uiPanel = document.createElement('div'); main_uiPanel.id = 'superAssistantPanel';
        const header = document.createElement('div'); header.className = 'panel-header'; header.textContent = '超级助手面板'; main_uiPanel.appendChild(header);
        const scrollableContent = document.createElement('div'); scrollableContent.className = 'panel-content-scrollable';

        const linkRulesSection = document.createElement('div');
        const linkRulesTitle = document.createElement('h4'); linkRulesTitle.className = 'section-title'; linkRulesTitle.textContent = '链接新标签页规则:'; linkRulesSection.appendChild(linkRulesTitle);
        ['whitelist', 'blacklist'].forEach(type => {
            const subSection = document.createElement('div');
            const subTitle = document.createElement('h5'); subTitle.style.cssText = 'font-size: 13px; font-weight: normal; margin-bottom: 4px;';
            subTitle.textContent = type === 'whitelist' ? '白名单 (在这些站点启用):' : '黑名单 (在这些站点禁用):';
            subSection.appendChild(subTitle);
            main_createAddForm(type, type === 'whitelist' ? main_userWhitelist : main_userBlacklist, type === 'whitelist' ? MAIN_SCRIPT_CONFIG.whitelistKey : MAIN_SCRIPT_CONFIG.blacklistKey, subSection);
            const ul = document.createElement('ul'); ul.id = `main-${type}-ul`; subSection.appendChild(ul);
            linkRulesSection.appendChild(subSection);
        });
        scrollableContent.appendChild(linkRulesSection);

        const cookieSection = document.createElement('div'); cookieSection.className = 'cookie-section';
        const cookieTitle = document.createElement('h4'); cookieTitle.className = 'section-title'; cookieTitle.textContent = 'Cookie 管理:'; cookieSection.appendChild(cookieTitle);
        const cookieDisplayArea = document.createElement('textarea'); cookieDisplayArea.id = 'main-cookie-display';
        cookieDisplayArea.readOnly = true; cookieDisplayArea.className = 'cookie-display';
        cookieDisplayArea.placeholder = '点击“获取Cookies”按钮显示...\n(注意: HttpOnly Cookies 无法获取)'; cookieSection.appendChild(cookieDisplayArea);
        const cookieActionsDiv = document.createElement('div'); cookieActionsDiv.className = 'actions-group';
        const getCookieButton = document.createElement('button'); getCookieButton.textContent = '获取Cookies'; getCookieButton.className = 'btn-info';
        getCookieButton.onclick = () => {
            const cookies = main_getPageCookies(); cookieDisplayArea.value = cookies || '';
            cookieDisplayArea.placeholder = cookies ? 'Cookies 已获取 (不含 HttpOnly)' : '当前页面没有可访问的 Cookies。';
        };
        const copyCookieButton = document.createElement('button'); copyCookieButton.textContent = '复制Cookies'; copyCookieButton.className = 'btn-secondary';
        copyCookieButton.onclick = () => { if (cookieDisplayArea.value) main_copyToClipboard(cookieDisplayArea.value); else alert('文本框中没有 Cookies 内容可复制。'); };
        cookieActionsDiv.appendChild(getCookieButton); cookieActionsDiv.appendChild(copyCookieButton);
        cookieSection.appendChild(cookieActionsDiv); scrollableContent.appendChild(cookieSection);

        const aiDownloaderSection = document.createElement('div');
        aiDownloaderSection.style.cssText = 'margin-top: 10px; padding-top: 8px; border-top: 1px solid #e8e8e8;';
        const aiDownloaderTitle = document.createElement('h4'); aiDownloaderTitle.className = 'section-title'; aiDownloaderTitle.textContent = 'AI 媒体下载';
        aiDownloaderSection.appendChild(aiDownloaderTitle);
        const aiAuthorCredit = document.createElement('div'); aiAuthorCredit.className = 'ai-downloader-author';
        aiAuthorCredit.textContent = `功能模块作者: 醉春风 (v${AIContentDownloader && AIContentDownloader.CONFIG ? AIContentDownloader.CONFIG.VERSION : 'N/A'})`;
        aiDownloaderSection.appendChild(aiAuthorCredit);
        const aiActionsDiv = document.createElement('div'); aiActionsDiv.className = 'actions-group';
        const toggleMediaPanelButton = document.createElement('button');
        toggleMediaPanelButton.textContent = '显示/隐藏媒体列表'; toggleMediaPanelButton.className = 'btn-primary';
        toggleMediaPanelButton.onclick = () => AIContentDownloader.toggleMediaPanel();
        const manualScanButton = document.createElement('button'); manualScanButton.textContent = '手动扫描媒体'; manualScanButton.className = 'btn-info';
        manualScanButton.onclick = () => AIContentDownloader.scanForMedia();
        aiActionsDiv.appendChild(toggleMediaPanelButton); aiActionsDiv.appendChild(manualScanButton);
        aiDownloaderSection.appendChild(aiActionsDiv); scrollableContent.appendChild(aiDownloaderSection);

        main_uiPanel.appendChild(scrollableContent);
        const closeButton = document.createElement('button'); closeButton.textContent = '关闭面板';
        closeButton.className = 'close-panel-btn'; closeButton.onclick = main_togglePanelVisibility; main_uiPanel.appendChild(closeButton);
        document.body.appendChild(main_uiPanel);
        main_log("UI面板已附加到body");
        main_renderListsUI();
        main_uiPanel.classList.toggle('panel-visible', main_panelVisible);
        main_log(`UI面板创建后,显示状态 (基于main_panelVisible=${main_panelVisible}):`, main_uiPanel.classList.contains('panel-visible') ? '可见' : '隐藏');
    }

    function main_renderListsUI() {
        if (!main_uiPanel || !document.body.contains(main_uiPanel)) return;
        main_log("main_renderListsUI 调用");
        const renderUlContent = (listArray, ulElementId, listType, configKey) => {
            const ul = main_uiPanel.querySelector('#' + ulElementId); if (!ul) return; ul.innerHTML = '';
            if (listArray.length === 0) {
                const emptyMsgLi = document.createElement('li'); emptyMsgLi.textContent = '(列表为空)';
                emptyMsgLi.className = 'panel-empty-msg'; emptyMsgLi.style.justifyContent = 'center'; emptyMsgLi.style.padding = '8px';
                ul.appendChild(emptyMsgLi); return;
            }
            listArray.forEach((pattern, index) => {
                const li = document.createElement('li'); const patternText = document.createElement('span');
                patternText.className = 'pattern-text'; patternText.textContent = pattern;
                const deleteBtn = document.createElement('button'); deleteBtn.innerHTML = '×';
                deleteBtn.className = 'delete-btn'; deleteBtn.title = '删除此条规则';
                deleteBtn.onclick = function() {
                    if (confirm(`确定要从${listType === 'whitelist' ? '白' : '黑'}名单中删除 "${pattern}" 吗?`)) {
                        listArray.splice(index, 1); GM_setValue(configKey, listArray.join(',')); main_renderListsUI();
                    }
                };
                li.appendChild(patternText); li.appendChild(deleteBtn); ul.appendChild(li);
            });
        };
        renderUlContent(main_userWhitelist, 'main-whitelist-ul', 'whitelist', MAIN_SCRIPT_CONFIG.whitelistKey);
        renderUlContent(main_userBlacklist, 'main-blacklist-ul', 'black', MAIN_SCRIPT_CONFIG.blacklistKey);
    }

    function main_togglePanelVisibility() {
        main_log(`切换面板可见性前,当前状态 main_panelVisible: ${main_panelVisible}`);
        main_panelVisible = !main_panelVisible;
        GM_setValue(MAIN_SCRIPT_CONFIG.panelVisibleKey, main_panelVisible);
        main_log(`切换后,目标状态 main_panelVisible: ${main_panelVisible}, 已保存`);

        if (main_panelVisible) {
            if (!main_uiPanel || !document.body.contains(main_uiPanel)) {
                main_log("面板DOM不存在或未附加,调用 main_createUIPanel()");
                main_createUIPanel();
            } else {
                main_log("面板DOM已存在,设置为可见并刷新列表");
                main_renderListsUI();
                main_uiPanel.classList.add('panel-visible');
            }
        } else {
            if (main_uiPanel) {
                main_log("设置为隐藏面板");
                main_uiPanel.classList.remove('panel-visible');
            } else {
                main_log("面板DOM不存在,无需隐藏操作");
            }
        }
        if (main_uiPanel) main_log("面板最终classList:", main_uiPanel.classList.toString());
        else main_log("面板DOM (main_uiPanel) 仍然为 null");
    }

    function main_loadConfig() {
        main_log("main_loadConfig 调用");
        const storedWhitelistStr = GM_getValue(MAIN_SCRIPT_CONFIG.whitelistKey);
        const storedBlacklistStr = GM_getValue(MAIN_SCRIPT_CONFIG.blacklistKey);
        main_userWhitelist = (typeof storedWhitelistStr === 'string' && storedWhitelistStr.trim() !== '') ? storedWhitelistStr.split(',').map(s => s.trim()).filter(s => s) : (typeof storedWhitelistStr === 'undefined' ? (GM_setValue(MAIN_SCRIPT_CONFIG.whitelistKey, MAIN_SCRIPT_CONFIG.defaultWhitelist.join(',')), [...MAIN_SCRIPT_CONFIG.defaultWhitelist]) : []);
        main_userBlacklist = (typeof storedBlacklistStr === 'string' && storedBlacklistStr.trim() !== '') ? storedBlacklistStr.split(',').map(s => s.trim()).filter(s => s) : (typeof storedBlacklistStr === 'undefined' ? (GM_setValue(MAIN_SCRIPT_CONFIG.blacklistKey, MAIN_SCRIPT_CONFIG.defaultBlacklist.join(',')), [...MAIN_SCRIPT_CONFIG.defaultBlacklist]) : []);

        if (main_uiPanel && main_panelVisible && document.body.contains(main_uiPanel)) {
            main_log("配置已加载,面板可见,刷新UI列表");
            main_renderListsUI();
        }
    }

    function main_urlMatchesPattern(url, pattern) { /* ... (与之前版本相同) ... */
        if (!pattern || !url) return false; let currentUrl = url; let p = pattern.trim();
        if (!p.includes("://")) { currentUrl = currentUrl.replace(/^https?:\/\//, ""); }
        if (!p.startsWith("www.") && !p.includes("://") && currentUrl.startsWith("www.")) { currentUrl = currentUrl.replace(/^www\./, "");}
        const escapedPattern = p.replace(/[.+?^${}()|[\]\\]/g, '\\$&');
        const regexString = '^' + escapedPattern.replace(/\\\*/g, '.*') + '$';
        try { return new RegExp(regexString, 'i').test(currentUrl); } catch (e) { return false; }
    }

    if (typeof GM_registerMenuCommand === 'function') { /* ... (与之前版本相同) ... */
        GM_registerMenuCommand('配置 "链接新标签页" 白名单 (Prompt)', () => {
            const c = GM_getValue(MAIN_SCRIPT_CONFIG.whitelistKey,main_userWhitelist.join(',')); const n=prompt('白名单(启用链接新标签页功能),逗号分隔:',c);
            if(n!==null){GM_setValue(MAIN_SCRIPT_CONFIG.whitelistKey,n);main_loadConfig();alert('链接白名单已更新!');}
        }, 'L');
        GM_registerMenuCommand('配置 "链接新标签页" 黑名单 (Prompt)', () => {
            const c = GM_getValue(MAIN_SCRIPT_CONFIG.blacklistKey,main_userBlacklist.join(',')); const n=prompt('黑名单(禁用链接新标签页功能),逗号分隔:',c);
            if(n!==null){GM_setValue(MAIN_SCRIPT_CONFIG.blacklistKey,n);main_loadConfig();alert('链接黑名单已更新!');}
        }, 'K');
        GM_registerMenuCommand('显示/隐藏 超级助手面板', main_togglePanelVisibility, 'P');
    }

    // *************************************************************************************
    // * AIContentDownloader 模块 (基于 "醉春风" 的脚本,并根据新需求调整)                  *
    // *************************************************************************************
    const AIContentDownloader = (function() {
        const CONFIG = { /* ... (AI下载模块的配置,与之前版本一致) ... */
            DEBUG: false, INIT_DELAY: 2500, RETRY_DELAY: 3000, MAX_RETRIES: 2,
            AUTHOR: "醉春风", VERSION: "3.4" // 保留原作者信息
        };
        const state = { /* ... (AI下载模块的状态,与之前版本一致) ... */
            platform: null, mediaItems: [], selectedItems: [], isProcessing: false, isPanelOpen: false,
            mediaMap: new Map(), mediaUrls: new Set(), windowLock: false,
            instanceId: 'manus_ai_dl_' + Math.random().toString(36).substr(2, 9),
            initRetries: 0, observer: null, observerScanTimeout: null
        };
        const log = (...args) => { if (CONFIG.DEBUG) console.log(`[AI下载模块 v${CONFIG.VERSION}]`, ...args); };
        const error = (...args) => { console.error(`[AI下载模块 v${CONFIG.VERSION}]`, ...args); };
        const ICONS = { /* ... (与之前版本一致) ... */
            image: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect><circle cx="8.5" cy="8.5" r="1.5"></circle><polyline points="21 15 16 10 5 21"></polyline></svg>`,
            video: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><rect x="2" y="2" width="20" height="20" rx="2.18" ry="2.18"></rect><line x1="7" y1="2" x2="7" y2="22"></line><line x1="17" y1="2" x2="17" y2="22"></line><line x1="2" y1="12" x2="22" y2="12"></line><line x1="2" y1="7" x2="7" y2="7"></line><line x1="2" y1="17" x2="7" y2="17"></line><line x1="17" y1="17" x2="22" y2="17"></line><line x1="17" y1="7" x2="22" y2="7"></line></svg>`,
            download: `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline points="7 10 12 15 17 10"></polyline><line x1="12" y1="15" x2="12" y2="3"></line></svg>`,
            error: `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"></circle><line x1="15" y1="9" x2="9" y2="15"></line><line x1="9" y1="9" x2="15" y2="15"></line></svg>`,
        };

        class MediaItem { /* ... (与之前版本一致,特别是 createThumbnailElement 中的点击行为已修改为新标签打开) ... */
            constructor(element, type, url = null) { /* ... */
                this.id = 'media_' + Math.random().toString(36).substr(2, 9);
                this.element = element; this.type = type;
                this.url = url || (element ? (element.src || element.currentSrc) : null);
                this.highestQualityUrl = this.url;
                this.width = element ? (element.naturalWidth || element.videoWidth || 0) : 0;
                this.height = element ? (element.naturalHeight || element.videoHeight || 0) : 0;
                this.duration = type === 'video' && element ? element.duration : 0;
                this.selected = false; this.timestamp = Date.now();
                this.videoLoaded = false; this.thumbnailLoaded = false;
            }
            createThumbnailElement() { /* ... (已修改为点击非checkbox区域时新标签打开 this.url) ... */
                const itemDiv = document.createElement('div'); itemDiv.className = `manus-ai-media-item ${this.type}`; itemDiv.dataset.id = this.id;
                const thumbnailContainer = document.createElement('div'); thumbnailContainer.className = 'manus-ai-media-thumbnail-container';
                if (this.url) {
                    try {
                        const placeholder = document.createElement('div'); placeholder.innerHTML = this.type === 'image' ? ICONS.image : ICONS.video;
                        placeholder.style.cssText = 'position:absolute;top:0;left:0;width:100%;height:100%;display:flex;align-items:center;justify-content:center;background-color:#2a2a2a;';
                        thumbnailContainer.appendChild(placeholder);
                        if (this.type === 'image') {
                            const img = document.createElement('img'); img.src = this.url;
                            img.style.cssText = 'width:100%;height:100%;object-fit:cover;position:absolute;top:0;left:0;';
                            img.crossOrigin = 'anonymous'; img.loading = 'lazy'; img.decoding = 'async';
                            img.onload = () => { this.thumbnailLoaded = true; if(placeholder.parentNode) placeholder.remove(); };
                            img.onerror = () => { /* 保留占位符 */ };
                            thumbnailContainer.appendChild(img);
                        } else { /* video */
                            const video = document.createElement('video'); video.src = this.url; video.crossOrigin = 'anonymous'; video.muted = true; video.preload = 'metadata';
                            video.style.cssText = 'width:100%;height:100%;object-fit:cover;position:absolute;top:0;left:0;';
                            video.addEventListener('loadeddata', () => {
                                this.videoLoaded = true; this.thumbnailLoaded = true; this.duration = video.duration || 0;
                                const durationEl = itemDiv.querySelector('.manus-ai-media-duration');
                                if (durationEl) durationEl.textContent = this.formatDuration(this.duration);
                                if(placeholder.parentNode) placeholder.remove();
                            });
                            video.addEventListener('error', () => { /* 保留占位符 */});
                            thumbnailContainer.appendChild(video);
                        }
                    } catch (e) { error('创建缩略图DOM出错:', e); thumbnailContainer.innerHTML = this.type === 'image' ? ICONS.image : ICONS.video; }
                } else { thumbnailContainer.innerHTML = this.type === 'image' ? ICONS.image : ICONS.video; }
                itemDiv.appendChild(thumbnailContainer);
                if (this.type === 'video') {
                    const durationSpan = document.createElement('span'); durationSpan.className = 'manus-ai-media-duration';
                    durationSpan.textContent = this.formatDuration(this.duration); itemDiv.appendChild(durationSpan);
                }
                const checkbox = document.createElement('div'); checkbox.className = 'manus-ai-media-checkbox';
                if (this.selected) checkbox.classList.add('checked'); itemDiv.appendChild(checkbox);
                itemDiv.addEventListener('click', (e) => {
                    if (state.windowLock) return;
                    const rect = checkbox.getBoundingClientRect();
                    const isCheckboxClick = (e.clientX >= rect.left && e.clientX <= rect.right && e.clientY >= rect.top && e.clientY <= rect.bottom);
                    if (isCheckboxClick) { this.toggleSelect(); UI.updateSelectedCounter(); UI.updateDownloadButton(); }
                    else {
                        if (this.url) {
                            if (typeof GM_openInTab === 'function') { GM_openInTab(this.url, { active: true, insert: true }); }
                            else { window.open(this.url, '_blank'); }
                        } else { UI.showError("此媒体项没有有效的URL可打开。"); }
                    }
                });
                return itemDiv;
            }
            toggleSelect() { /* ... (与原AI脚本一致) ... */
                this.selected = !this.selected;
                const itemElement = document.querySelector(`.manus-ai-media-item[data-id="${this.id}"]`);
                if (itemElement) { itemElement.classList.toggle('selected', this.selected); itemElement.querySelector('.manus-ai-media-checkbox').classList.toggle('checked', this.selected); }
                if (this.selected) { if (!state.selectedItems.includes(this.id)) state.selectedItems.push(this.id); }
                else { const index = state.selectedItems.indexOf(this.id); if (index !== -1) state.selectedItems.splice(index, 1); }
            }
            setSelected(selected) { if (this.selected !== selected) this.toggleSelect(); }
            formatDuration(seconds) { /* ... (与原AI脚本一致) ... */
                if (!seconds || isNaN(seconds)) return '0:00'; seconds = Math.round(seconds);
                const m = Math.floor(seconds / 60); const s = seconds % 60;
                return `${m}:${s.toString().padStart(2, '0')}`;
            }
        }
        const UI = { /* ... (与之前版本类似,但移除了LargePreview相关方法) ... */
            createPreviewPanel: () => { /* ... (与之前版本类似) ... */
                let panel = document.querySelector('.manus-ai-preview-panel'); if (panel) return panel;
                panel = document.createElement('div'); panel.className = 'manus-ai-preview-panel'; panel.dataset.instanceId = state.instanceId;
                panel.innerHTML = `
                    <div class="manus-ai-preview-header">
                        <div class="manus-ai-preview-title">媒体内容 <span class="manus-ai-author-credit">by ${CONFIG.AUTHOR}</span> v${CONFIG.VERSION}</div>
                        <button class="manus-ai-preview-close" title="关闭媒体列表">×</button>
                    </div>
                    <div class="manus-ai-preview-toolbar">
                        <button class="manus-ai-select-all" title="全选所有媒体">全选</button> <button class="manus-ai-select-none" title="取消所有选择">无</button>
                        <button class="manus-ai-select-images" title="仅选择图片">图片</button> <button class="manus-ai-select-videos" title="仅选择视频">视频</button>
                        <div class="manus-ai-preview-counter">已选: 0</div>
                    </div>
                    <div class="manus-ai-preview-content"></div>
                    <div class="manus-ai-preview-footer">
                        <button class="manus-ai-download-btn" disabled> ${ICONS.download} 下载选中(0) </button>
                        <button class="manus-ai-cancel-btn">关闭</button>
                    </div>`;
                document.body.appendChild(panel);
                panel.querySelector('.manus-ai-preview-close').addEventListener('click', () => UI.togglePreviewPanel(false));
                panel.querySelector('.manus-ai-cancel-btn').addEventListener('click', () => UI.togglePreviewPanel(false));
                panel.querySelector('.manus-ai-select-all').addEventListener('click', UI.selectAll);
                panel.querySelector('.manus-ai-select-none').addEventListener('click', UI.selectNone);
                panel.querySelector('.manus-ai-select-images').addEventListener('click', () => UI.selectByType('image'));
                panel.querySelector('.manus-ai-select-videos').addEventListener('click', () => UI.selectByType('video'));
                panel.querySelector('.manus-ai-download-btn').addEventListener('click', UI.startDownload);
                return panel;
            },
            showNotification: (message, duration = 2500) => { /* ... (与之前版本一致) ... */
                const n = document.createElement('div'); n.className = 'manus-ai-downloader-notification'; n.textContent = message;
                document.body.appendChild(n); setTimeout(() => n.remove(), duration);
            },
            showError: (message, duration = 3500) => { /* ... (与之前版本一致) ... */
                const e = document.createElement('div'); e.className = 'manus-ai-downloader-error'; e.innerHTML = `${ICONS.error} ${message}`;
                document.body.appendChild(e); setTimeout(() => e.remove(), duration);
            },
            togglePreviewPanel: (show = null) => { /* ... (与之前版本一致) ... */
                const panel = UI.createPreviewPanel(); const isCurrentlyShown = panel.classList.contains('show');
                const shouldShow = show !== null ? show : !isCurrentlyShown;
                if (shouldShow) { panel.classList.add('show'); state.isPanelOpen = true; UI.refreshPreviewContent(); }
                else { panel.classList.remove('show'); state.isPanelOpen = false; }
            },
            refreshPreviewContent: () => { /* ... (与之前版本一致) ... */
                const cc = document.querySelector('.manus-ai-preview-panel .manus-ai-preview-content'); if (!cc) return; cc.innerHTML = '';
                if (state.mediaItems.length === 0) { cc.innerHTML = '<div style="grid-column: 1 / -1; color: #aaa; text-align: center; padding: 20px;">暂无媒体或尝试手动扫描</div>'; }
                else { [...state.mediaItems].sort((a, b) => b.timestamp - a.timestamp).forEach(item => cc.appendChild(item.createThumbnailElement())); }
                UI.updateSelectedCounter(); UI.updateDownloadButton();
            },
            updateSelectedCounter: () => { /* ... (与之前版本一致) ... */
                const c = document.querySelector('.manus-ai-preview-counter'); if (c) c.textContent = `已选: ${state.selectedItems.length}`;
            },
            updateDownloadButton: () => { /* ... (与之前版本一致) ... */
                const b = document.querySelector('.manus-ai-download-btn'); if(!b)return; const cnt = state.selectedItems.length; b.disabled = cnt === 0; b.innerHTML = `${ICONS.download} 下载选中(${cnt})`;
            },
            selectAll: () => { state.mediaItems.forEach(i => i.setSelected(true)); UI.updateSelectedCounter(); UI.updateDownloadButton(); },
            selectNone: () => { state.mediaItems.forEach(i => i.setSelected(false)); UI.updateSelectedCounter(); UI.updateDownloadButton(); },
            selectByType: (t) => { state.mediaItems.forEach(i => i.setSelected(i.type === t)); UI.updateSelectedCounter(); UI.updateDownloadButton(); },
            startDownload: () => { /* ... (与之前版本一致) ... */
                const itemsToDownload = state.mediaItems.filter(item => state.selectedItems.includes(item.id));
                if (itemsToDownload.length === 0) { UI.showError('没有选中任何项'); return; }
                UI.showNotification(`开始下载 ${itemsToDownload.length} 个媒体项...`);
                itemsToDownload.forEach((item, index) => {
                    setTimeout(() => {
                        if (!item.url) { UI.showError(`媒体项 #${index+1} URL无效`); return; }
                        const ext = item.type === 'video' ? (item.url.match(/\.(mp4|webm|mov|mkv|avi)/i)?.[1] || 'mp4') : (item.url.match(/\.(jpg|jpeg|png|gif|webp|bmp|svg)/i)?.[1] || 'jpg');
                        const ts = new Date().toISOString().replace(/[-:.]/g, '').replace('T','_');
                        const fileName = `${item.type}_${CONFIG.AUTHOR}_${ts}_${index + 1}.${ext}`;
                        log(`准备下载: ${fileName} from ${item.url}`);
                        if (typeof GM_download === 'function') {
                            GM_download({ url: item.url, name: fileName, saveAs: false,
                                onload: () => log(`${fileName} 下载完成。`),
                                onerror: (err) => { error(`下载 ${fileName} 失败:`, err.error || err); UI.showError(`${fileName.substring(0,20)}... 下载失败`); }
                            });
                        } else { const a = document.createElement('a'); a.href = item.url; a.download = fileName; document.body.appendChild(a); a.click(); document.body.removeChild(a); }
                    }, index * 700);
                });
            }
        };
        const utils = { /* ... (与之前版本一致) ... */
            detectPlatform: () => {
                const url = window.location.href.toLowerCase(); const host = window.location.hostname.toLowerCase();
                if (host.includes('klingai.com') || host.includes('kuaishou.com') || host.includes('kuaishou.cn') || host.includes('app.klingai.com')) return 'keling';
                if (host.includes('mjianying.com') || host.includes('dreamina.capcut.com') || host.includes('capcut.com')) return 'jimeng';
                if (host.includes('googleusercontent.com')) { if (url.includes('/youtube.com/')) return 'generic_video'; return 'generic_image';} // 注意这里的 /0 变 /2,或更通用
                if (document.querySelector('[class*="kl-"], [data-kl]')) return 'keling';
                if (document.querySelector('[class*="jm-"], [data-jm], [class*="capcut"], [class*="jianying"]')) return 'jimeng';
                const title = document.title.toLowerCase();
                if (title.includes('可灵') || title.includes('kling')) return 'keling';
                if (title.includes('即梦') || title.includes('jimeng') || title.includes('capcut') || title.includes('剪映')) return 'jimeng';
                return null;
            },
            isUrlProcessed: (url) => { if (!url) return true; return state.mediaUrls.has(url); },
            markUrlAsProcessed: (url) => { if (url) state.mediaUrls.add(url); },
            cleanupDuplicateMedia: () => { /* ... (与之前版本一致) ... */
                const uniqueUrls = new Set(); const uniqueItems = [];
                for (let i = state.mediaItems.length - 1; i >= 0; i--) { const item = state.mediaItems[i]; if (item.url && !uniqueUrls.has(item.url)) { uniqueUrls.add(item.url); uniqueItems.push(item); }}
                uniqueItems.reverse(); if (state.mediaItems.length !== uniqueItems.length) { state.mediaItems = uniqueItems; log(`清理后媒体项: ${uniqueItems.length}`);}
            }
        };
        const platforms = { /* ... (与之前版本一致) ... */
            keling: { selectors: ['video[src]', 'img[src]', 'div[style*="background-image"]', '[class*="video"] video', '[class*="image"] img', '[class*="gallery"] img', '[class*="player"] video'] },
            jimeng: { selectors: ['video[src]', 'img[src]', 'div[style*="background-image"]', '[class*="player"] video', '[class*="preview"] img', '[class*="image-render"] img', '[class*="canvas"] canvas'] },
            generic_video: { selectors: ['video[src]'] },
            generic_image: { selectors: ['img[src]', 'div[style*="background-image"]'] }
        };
        function findAndProcessMedia() { /* ... (与之前版本一致) ... */
            if (!state.platform && state.platform !== null) { state.platform = utils.detectPlatform() || 'generic_image'; } else if (state.platform === null) { state.platform = utils.detectPlatform() || 'generic_image';}
            log(`扫描媒体 (平台: ${state.platform})...`); let newMediaFound = false;
            const platformConfig = platforms[state.platform] || { selectors: ['video[src]','img[src]', 'div[style*="background-image"]'] };
            platformConfig.selectors.forEach(selector => {
                try {
                    document.querySelectorAll(selector).forEach(element => {
                        let url = null; let type = 'image';
                        if (element.tagName === 'IMG') { url = element.src; type = 'image'; }
                        else if (element.tagName === 'VIDEO') { url = element.src || element.currentSrc; type = 'video'; }
                        else if (element.tagName === 'DIV' && selector.includes('background-image')) { const bgStyle = window.getComputedStyle(element).backgroundImage; if (bgStyle && bgStyle.startsWith('url("') && bgStyle.endsWith('")')) { url = bgStyle.slice(5, -2); type = 'image';} }
                        else if (element.tagName === 'CANVAS' && state.platform === 'jimeng') { try { url = element.toDataURL('image/png'); type = 'image'; } catch (e) { return; } }
                        if (!url || utils.isUrlProcessed(url)) return; if (type === 'image' && (element.naturalWidth < 50 || element.naturalHeight < 50) && !url.startsWith('data:')) return;
                        utils.markUrlAsProcessed(url); const mediaItem = new MediaItem(null, type, url);
                        mediaItem.width = element.naturalWidth || element.videoWidth || element.width || 0; mediaItem.height = element.naturalHeight || element.videoHeight || element.height || 0;
                        if (type === 'video') mediaItem.duration = element.duration || 0; state.mediaItems.push(mediaItem); newMediaFound = true;
                    });
                } catch (e) { error(`选择器 ${selector} 出错:`, e); }
            });
            if (newMediaFound) { utils.cleanupDuplicateMedia(); if (state.isPanelOpen) UI.refreshPreviewContent(); } else { /* log('本次扫描未发现新媒体。'); */ }
            return newMediaFound;
        }
        function setupNetworkListener() { /* ... (与之前版本一致) ... */
            const processPotentialMediaUrl = (url) => {
                if (url && (url.match(/\.(jpe?g|png|gif|webp|mp4|webm|mov|mkv|avi|bmp|svg)/i) || url.includes('/image/') || url.includes('/video/') || url.startsWith('blob:') || url.startsWith('data:image') || url.startsWith('data:video'))) {
                    if (utils.isUrlProcessed(url)) return;
                    const type = (url.match(/\.(mp4|webm|mov|mkv|avi)/i) || url.includes('/video/') || url.startsWith('data:video')) ? 'video' : 'image';
                    utils.markUrlAsProcessed(url); const mediaItem = new MediaItem(null, type, url); state.mediaItems.push(mediaItem);
                    utils.cleanupDuplicateMedia(); if (state.isPanelOpen) UI.refreshPreviewContent();
                }
            };
            if(window.XMLHttpRequest_ManusAiHooked) return;
            const origXHR = window.XMLHttpRequest; window.XMLHttpRequest = function() { const xhr = new origXHR(); xhr.addEventListener('load', function() { if(this.responseURL) processPotentialMediaUrl(this.responseURL); }); return xhr; }; window.XMLHttpRequest_ManusAiHooked = true;
            if(window.fetch_ManusAiHooked) return;
            const origFetch = window.fetch; window.fetch = function(...args) { return origFetch.apply(this, args).then(response => { if (response && response.url) processPotentialMediaUrl(response.url); return response.clone(); }).catch(err => { error("Fetch hook error:", err); throw err;}); }; window.fetch_ManusAiHooked = true;
        }
        function startObserver() { /* ... (与之前版本一致) ... */
            if (state.observer) state.observer.disconnect();
            state.observer = new MutationObserver((mutations) => {
                let p = mutations.some(m => (m.type==='childList'&&m.addedNodes.length>0) || (m.type==='attributes'&&(m.attributeName==='src'||m.attributeName==='currentSrc'||m.attributeName==='style'||m.attributeName==='href')));
                if(p){clearTimeout(state.observerScanTimeout); state.observerScanTimeout = setTimeout(findAndProcessMedia,700);}
            });
            if(document.body) state.observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['src', 'currentSrc', 'style', 'href'] }); else setTimeout(startObserver, 500);
        }
        function initializeScript() { /* ... (与之前版本一致,不再创建独立按钮) ... */
            log(`尝试初始化AI下载模块 (第 ${state.initRetries + 1} 次)`); state.platform = utils.detectPlatform(); log(`AI下载平台: ${state.platform || '通用 (未特定识别)'}`);
            UI.createPreviewPanel(); setupNetworkListener(); const foundInitially = findAndProcessMedia(); startObserver();
            if (!foundInitially && state.initRetries < CONFIG.MAX_RETRIES) { state.initRetries++; setTimeout(initializeScript, CONFIG.RETRY_DELAY); return; }
            log(`AI下载模块 (v${CONFIG.VERSION} by ${CONFIG.AUTHOR}) 初始化完成。`);
        }
        return { CONFIG: CONFIG, initialize: initializeScript, toggleMediaPanel: UI.togglePreviewPanel, scanForMedia: () => { log("用户手动扫描"); findAndProcessMedia(); UI.showNotification('手动扫描完成'); } };
    })();

    // --- 主脚本初始化和事件监听 ---
    main_loadConfig();
    const main_ensureInitialPanelState = () => { /* ... (与之前版本相同) ... */
        if (main_panelVisible) {
            if (!main_uiPanel || !document.body.contains(main_uiPanel)) { main_createUIPanel(); }
            else { main_uiPanel.classList.add('panel-visible'); main_renderListsUI(); }
        }
    };
    const startAllFeatures = () => { main_ensureInitialPanelState(); AIContentDownloader.initialize(); };
    if (document.readyState !== "loading") { startAllFeatures(); } else { document.addEventListener("DOMContentLoaded", startAllFeatures); }

    document.addEventListener('click', function(event) { /* ... (与之前版本相同,包含对面板内部点击的忽略逻辑和链接处理逻辑) ... */
        if ((main_uiPanel && main_uiPanel.contains(event.target)) || (document.querySelector('.manus-ai-preview-panel') && document.querySelector('.manus-ai-preview-panel').contains(event.target))) return;
        const currentPageUrl = window.location.href; let scriptShouldRunLinkLogic = false;
        const isWhitelisted = main_userWhitelist.some(pattern => main_urlMatchesPattern(currentPageUrl, pattern));
        if (isWhitelisted) { scriptShouldRunLinkLogic = true; } else { const isBlacklisted = main_userBlacklist.some(pattern => main_urlMatchesPattern(currentPageUrl, pattern)); if (isBlacklisted) { scriptShouldRunLinkLogic = false; } else { scriptShouldRunLinkLogic = false; }}
        if(isWhitelisted) scriptShouldRunLinkLogic = true; // 确保白名单优先
        if (!scriptShouldRunLinkLogic) return;
        if (event.button !== 0 || event.ctrlKey || event.metaKey || event.shiftKey || event.altKey) return;
        let targetElement = event.target; let anchorElement = null;
        for (let i = 0; i < 5 && targetElement && targetElement !== document.body; i++) { if (targetElement.tagName === 'A') { anchorElement = targetElement; break; } targetElement = targetElement.parentElement; }
        if (anchorElement) {
            const href = anchorElement.href; const rawHref = anchorElement.getAttribute('href');
            if (!href || (rawHref && rawHref.startsWith('#')) || href.startsWith('javascript:')) return;
            if (anchorElement.hasAttribute('download')) return;
            if (event.altKey && event.shiftKey) { return; }
            event.preventDefault(); event.stopPropagation();
            if (typeof GM_openInTab === 'function') { GM_openInTab(href, { active: true, insert: true }); }
            else if (typeof window.open === 'function') { window.open(href, '_blank'); }
        }
    }, true);
})();