Greasy Fork

来自缓存

即梦AI全能助手

支持图片/视频下载的即梦AI增强工具

// ==UserScript==
// @name         即梦AI全能助手
// @namespace    http://tampermonkey.net/
// @version      3.3
// @description  支持图片/视频下载的即梦AI增强工具
// @author       Jackey
// @license      GPL-3.0
// @match        https://jimeng.jianying.com/*
// @icon         https://lf3-lv-buz.vlabstatic.com/obj/image-lvweb-buz/common/images/dreamina-v5.ico
// @grant        GM.xmlHttpRequest
// @grant        GM_download
// @grant        GM_addStyle
// @grant        window.open
// @connect      byteimg.com
// @connect      *.byteimg.com
// @require      https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js
// ==/UserScript==

(function() {
    'use strict';

    const CONFIG = {
        ACTION_BAR_SELECTOR: '.topActionBar-b6PHoX',
        BUTTON_STYLE: `
            margin-left: 12px;
            cursor: pointer;
            border-radius: 8px;
            padding: 8px 16px;
            transition: all 0.2s;
            background: #f0f2f5;
            border: 1px solid #d9d9d9;
            position: relative !important;
        `,
        HOVER_STYLE: `
            background: #e6f7ff;
            border-color: #91d5ff;
        `,
        VIDEO_SCAN_INTERVAL: 3000,
        VIDEO_PANEL_STYLE: `
            position: fixed;
            right: 20px;
            top: 100px;
            background: rgba(255,255,255,0.95);
            border: 1px solid #ddd;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
            width: 320px;
            z-index: 9999;
            max-height: 70vh;
            overflow: hidden;
        `,
        ASSET_PAGE_BUTTON_CONTAINER_STYLE: `
            display: flex;
            position: fixed;
            top: 10px;
            right: 20px;
            z-index: 9999;
            background: rgba(255,255,255,0.9);
            padding: 8px;
            border-radius: 8px;
            box-shadow: 0 2px 8px rgba(0,0,0,0.1);
        `
    };

    class JimengEnhancer {
        constructor() {
            this.observer = null;
            this.actionBar = null;
            this.buttonsAdded = false;
            this.videoList = new Map();
            this.videoPanel = null;
            this.assetButtonContainer = null;
            this.init();
        }

        init() {
            this.setupDOMObserver();
            this.setupGlobalListener();
            this.initVideoMonitor();
            this.createVideoPanel();

            // 立即尝试几次查找按钮容器并添加按钮
            setTimeout(() => this.safeUpdateButtons(), 1000);
            setTimeout(() => this.safeUpdateButtons(), 3000);
            setTimeout(() => this.safeUpdateButtons(), 5000);

            // 特别处理asset页面
            this.handleAssetPage();

            // 监听URL变化,以处理SPA导航
            this.setupUrlChangeListener();
        }

        setupDOMObserver() {
            const Observer = window.MutationObserver || window.WebKitMutationObserver;
            this.observer = new Observer(mutations => {
                mutations.forEach(mutation => {
                    if (mutation.type === 'childList') {
                        this.handleDOMChange(mutation);
                    }
                });
            });

            this.observer.observe(document, {
                childList: true,
                subtree: true,
                attributes: false,
                characterData: false
            });
        }

        setupGlobalListener() {
            document.addEventListener('click', this.handleGlobalClick.bind(this));
        }

        handleDOMChange(mutation) {
            const shouldUpdate = Array.from(mutation.addedNodes).some(node =>
                node.nodeType === 1 &&
                (node.matches(CONFIG.ACTION_BAR_SELECTOR) || node.querySelector(CONFIG.ACTION_BAR_SELECTOR))
            ) || !document.contains(this.actionBar);

            if (shouldUpdate) {
                this.safeUpdateButtons();
            }

            // 在AI-tool/asset页面监测按钮容器
            if (this.isAssetPage()) {
                if (!this.buttonsAdded) {
                    this.safeUpdateButtons();
                }
            }
        }

        safeUpdateButtons() {
            // 在asset页面,也尝试使用更广泛的选择器查找操作栏
            if (this.isAssetPage()) {
                this.actionBar = document.querySelector(CONFIG.ACTION_BAR_SELECTOR) ||
                                 document.querySelector('.topActionBar') ||
                                 document.querySelector('.actionBar') ||
                                 document.querySelector('.header-actions');

                // 如果在asset页面仍找不到操作栏,尝试创建一个
                if (!this.actionBar) {
                    const potentialParent = document.querySelector('.layout-header') ||
                                        document.querySelector('.header') ||
                                        document.querySelector('header');

                    if (potentialParent && !document.querySelector('.jimeng-custom-action-bar')) {
                        const customBar = document.createElement('div');
                        customBar.className = 'topActionBar-b6PHoX jimeng-custom-action-bar';
                        customBar.style = 'display: flex; align-items: center; justify-content: flex-end; padding: 8px 16px;';
                        potentialParent.appendChild(customBar);
                        this.actionBar = customBar;
                    }
                }
            } else {
                this.actionBar = document.querySelector(CONFIG.ACTION_BAR_SELECTOR);
            }

            if (this.actionBar && !this.buttonsAdded) {
                this.injectButtons();
                this.buttonsAdded = true;
            } else if (!this.actionBar) {
                this.buttonsAdded = false;
            }
        }

        injectButtons() {
            if (!this.actionBar.querySelector('.jimeng-download-btn')) {
                ['download', 'video', 'open'].forEach(type => {
                    this.actionBar.insertAdjacentHTML('beforeend', this.generateButton(type));
                });

                this.actionBar.querySelector('.jimeng-download-btn').onclick = () => this.handleDownload();
                this.actionBar.querySelector('.jimeng-video-btn').onclick = () => this.toggleVideoPanel();
                this.actionBar.querySelector('.jimeng-open-btn').onclick = () => this.handleOpen();
            }
        }

        generateButton(type) {
            const templates = {
                download: () => `
                    <div class="jimeng-download-btn custom-btn"
                         style="${CONFIG.BUTTON_STYLE}"
                         onmouseover="this.style='${CONFIG.BUTTON_STYLE}${CONFIG.HOVER_STYLE}'"
                         onmouseout="this.style='${CONFIG.BUTTON_STYLE}'">
                        <svg width="16" height="16" viewBox="0 0 24 24" fill="#1890ff">
                            <path d="M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z"/>
                        </svg>
                        <span style="margin-left:8px;color:#1890ff">下载PNG</span>
                    </div>
                `,
                video: () => `
                    <div class="jimeng-video-btn custom-btn"
                         style="${CONFIG.BUTTON_STYLE}"
                         onmouseover="this.style='${CONFIG.BUTTON_STYLE}${CONFIG.HOVER_STYLE}'"
                         onmouseout="this.style='${CONFIG.BUTTON_STYLE}'">
                        <svg width="16" height="16" viewBox="0 0 24 24" fill="#eb2f96">
                            <path d="M18 3v2h-2V3H8v2H6V3H4v18h2v-2h2v2h8v-2h2v2h2V3h-2zM8 17H6v-2h2v2zm0-4H6v-2h2v2zm0-4H6V7h2v2zm10 8h-2v-2h2v2zm0-4h-2v-2h2v2zm0-4h-2V7h2v2z"/>
                        </svg>
                        <span style="margin-left:8px;color:#eb2f96">
                            视频下载
                            <span class="video-count" style="margin-left:4px;background:#ff4d4f;color:white;border-radius:10px;padding:0 6px;">
                                ${this.videoList.size}
                            </span>
                        </span>
                    </div>
                `,
                open: () => `
                    <div class="jimeng-open-btn custom-btn"
                         style="${CONFIG.BUTTON_STYLE}"
                         onmouseover="this.style='${CONFIG.BUTTON_STYLE}${CONFIG.HOVER_STYLE}'"
                         onmouseout="this.style='${CONFIG.BUTTON_STYLE}'">
                        <svg width="16" height="16" viewBox="0 0 24 24" fill="#52c41a">
                            <path d="M19 19H5V5h7V3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14c1.1 0 2-.9 2-2v-7h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z"/>
                        </svg>
                        <span style="margin-left:8px;color:#52c41a">打开图片</span>
                    </div>
                `
            };
            return templates[type]();
        }

        getCurrentImage() {
            try {
                // 获取当前活跃或选中的图片
                const getActiveImage = () => {
                    // 查找带有selected、active等类的容器内的图片
                    const activeContainers = Array.from(document.querySelectorAll('.selected, .active, .current, .focused, [data-active="true"], [aria-selected="true"]'));
                    for (const container of activeContainers) {
                        const img = container.querySelector('img');
                        if (img && img.src && img.width > 100) return img;
                    }
                    return null;
                };

                // 首先尝试获取活跃的图片
                const activeImage = getActiveImage();
                if (activeImage) {
                    console.log('[即梦助手] 找到活跃图片:', activeImage.src);
                    return activeImage;
                }

                // 支持AI-tool/image/generate页面的图片获取
                if (this.isImageGeneratePage()) {
                    const generateImage = document.querySelector('.imageResult img') ||
                                         document.querySelector('.generatedImage img') ||
                                         document.querySelector('.previewResult img') ||
                                         document.querySelector('.result-container img');

                    if (generateImage) {
                        console.log('[即梦助手] 找到生成图片:', generateImage.src);
                        return generateImage;
                    }
                }

                // 支持AI-tool/asset页面的图片获取
                if (this.isAssetPage()) {
                    const assetImage = document.querySelector('.viewerImage img') ||
                                      document.querySelector('.media-container img') ||
                                      document.querySelector('.assetPreview img') ||
                                      document.querySelector('.mediaViewer img') ||
                                      document.querySelector('.asset-preview img') ||
                                      document.querySelector('.content-view img');

                    if (assetImage) {
                        console.log('[即梦助手] 找到资源图片:', assetImage.src);
                        return assetImage;
                    }
                }

                // 一般页面的图片查找
                const mainImage = document.querySelector('.imageContainer-Ey3Aqm img') ||
                                document.querySelector('.generatedImage-Ey3Aqm img') ||
                                document.querySelector('.previewArea-Ey3Aqm img');

                if (mainImage) {
                    console.log('[即梦助手] 找到主要图片:', mainImage.src);
                    return mainImage;
                }

                // 回退策略:查找所有较大的图片
                const allPossible = Array.from(document.querySelectorAll('img'))
                    .filter(img => img.src?.includes('byteimg.com') && img.width > 200 && img.height > 200 && img.complete);

                if (allPossible.length > 0) {
                    // 根据图片尺寸和可见性排序
                    allPossible.sort((a, b) => {
                        // 可见性评分
                        const visibilityA = this.getElementVisibility(a);
                        const visibilityB = this.getElementVisibility(b);

                        if (visibilityA !== visibilityB) {
                            return visibilityB - visibilityA; // 可见性优先
                        }

                        // 尺寸评分
                        return (b.width * b.height) - (a.width * a.height); // 大尺寸优先
                    });

                    console.log('[即梦助手] 回退策略找到图片:', allPossible[0].src);
                    return allPossible[0];
                }

                return null;
            } catch (error) {
                console.error('图片查找失败:', error);
                return null;
            }
        }

        // 获取元素的可见性评分(0-10)
        getElementVisibility(element) {
            if (!element) return 0;

            try {
                const rect = element.getBoundingClientRect();

                // 检查元素是否在视口内
                if (rect.right < 0 || rect.bottom < 0 ||
                    rect.left > window.innerWidth || rect.top > window.innerHeight) {
                    return 0; // 不在视口内
                }

                // 检查元素是否被隐藏
                const style = window.getComputedStyle(element);
                if (style.display === 'none' || style.visibility === 'hidden' || style.opacity === '0') {
                    return 0;
                }

                // 检查元素尺寸
                if (rect.width < 50 || rect.height < 50) {
                    return 2; // 元素太小
                }

                // 计算元素在视口中的面积比例
                const visibleWidth = Math.min(rect.right, window.innerWidth) - Math.max(rect.left, 0);
                const visibleHeight = Math.min(rect.bottom, window.innerHeight) - Math.max(rect.top, 0);
                const visibleArea = visibleWidth * visibleHeight;
                const elementArea = rect.width * rect.height;
                const visibilityRatio = visibleArea / elementArea;

                // 基于可见比例返回评分(0-10)
                return Math.round(visibilityRatio * 10);
            } catch (e) {
                console.error('计算元素可见性失败:', e);
                return 0;
            }
        }

        async handleDownload() {
            const img = this.getCurrentImage();
            if (!img?.src) {
                console.error('[即梦助手] 未找到有效图片');
                alert('未找到有效图片,请确保当前页面有图片显示');
                return;
            }

            try {
                const { blob, fileName } = await this.convertWebpToPng(img.src);
                const url = URL.createObjectURL(blob);

                const link = document.createElement('a');
                link.href = url;
                link.download = fileName;
                link.click();

                setTimeout(() => URL.revokeObjectURL(url), 1000);
            } catch (error) {
                alert(`下载失败: ${error.message}`);
            }
        }

        handleOpen() {
            const img = this.getCurrentImage();
            if (img?.src) window.open(img.src, '_blank');
        }

        async convertWebpToPng(src) {
            const blob = await this.fetchImageBlob(src);
            return new Promise((resolve, reject) => {
                const img = new Image();
                img.onload = () => {
                    const canvas = document.createElement('canvas');
                    canvas.width = img.width;
                    canvas.height = img.height;
                    canvas.getContext('2d').drawImage(img, 0, 0);
                    canvas.toBlob(pngBlob => resolve({
                        blob: pngBlob,
                        fileName: `jimeng-ai-${Date.now()}.png`
                    }), 'image/png');
                };
                img.onerror = reject;
                img.src = URL.createObjectURL(blob);
            });
        }

        fetchImageBlob(url) {
            return new Promise((resolve, reject) => {
                GM.xmlHttpRequest({
                    method: 'GET',
                    url: url,
                    responseType: 'blob',
                    onload: res => resolve(res.response),
                    onerror: reject
                });
            });
        }

        /* 视频下载相关功能 */
        initVideoMonitor() {
            setInterval(() => this.scanVideos(), CONFIG.VIDEO_SCAN_INTERVAL);
        }

        scanVideos() {
            console.log('[即梦助手] 正在扫描视频元素...');

            // 找出所有视频元素
            const videos = document.querySelectorAll('video');
            console.log(`[即梦助手] 找到 ${videos.length} 个视频元素`);

            // 在asset页面特别处理
            if (this.isAssetPage()) {
                const assetVideoPlayer = document.querySelector('.video-react-video') ||
                                        document.querySelector('.asset-video video') ||
                                        document.querySelector('.media-player video');

                if (assetVideoPlayer && assetVideoPlayer.src) {
                    const src = this.cleanVideoUrl(assetVideoPlayer.src);

                    if (src && !this.videoList.has(src)) {
                        console.log(`[即梦助手] 在asset页面发现新视频: ${src}`);

                        this.videoList.set(src, {
                            element: assetVideoPlayer,
                            timestamp: Date.now()
                        });

                        // 更新UI
                        this.updateVideoUI();
                    }
                }
            }

            videos.forEach(video => {
                // 处理视频源
                let src = '';

                // 尝试从视频元素直接获取src
                if (video.src) {
                    src = this.cleanVideoUrl(video.src);
                }

                // 如果直接src为空,检查source子元素
                if (!src) {
                    const sources = video.querySelectorAll('source');
                    for (const source of sources) {
                        if (source.src) {
                            src = this.cleanVideoUrl(source.src);
                            if (src) break;
                        }
                    }
                }

                // 检查视频是否已经在列表中或src是否为空
                if (!src) {
                    console.log('[即梦助手] 跳过没有src的视频元素');
                    return;
                }

                if (this.videoList.has(src)) {
                    return;
                }

                console.log(`[即梦助手] 发现新视频: ${src}`);

                // 添加到视频列表
                this.videoList.set(src, {
                    element: video,
                    timestamp: Date.now()
                });

                // 更新UI
                this.updateVideoUI();
            });

            // 在每次扫描后显示已找到的视频总数
            console.log(`[即梦助手] 当前视频列表中共有 ${this.videoList.size} 个视频`);
        }

        cleanVideoUrl(url) {
            if (!url || url === '' || url === 'about:blank') {
                return '';
            }

            try {
                // 对于相对路径,转换为绝对路径
                if (url.startsWith('/')) {
                    url = window.location.origin + url;
                }

                const u = new URL(url);

                // 移除可能导致水印的参数
                u.searchParams.delete('watermark');
                u.searchParams.delete('logo');
                u.searchParams.delete('w');
                u.searchParams.delete('h');
                u.searchParams.delete('quality');

                return u.toString();
            } catch(e) {
                console.error(`[即梦助手] 清理视频URL失败: ${e.message}`, url);
                // 如果URL解析失败但非空,仍返回原始URL
                return url && url !== 'about:blank' ? url : '';
            }
        }

        createVideoPanel() {
            this.videoPanel = document.createElement('div');
            this.videoPanel.style = CONFIG.VIDEO_PANEL_STYLE;
            this.videoPanel.innerHTML = `
                <div style="padding:12px;border-bottom:1px solid #eee;background:#f8f9fa;">
                    检测到 ${this.videoList.size} 个视频
                </div>
                <div style="max-height:calc(70vh - 50px);overflow-y:auto;"></div>
            `;
            document.body.appendChild(this.videoPanel);
            this.setupDrag(this.videoPanel);
        }

        updateVideoUI() {
            // 更新操作栏按钮
            const countBadge = this.actionBar?.querySelector('.video-count');
            if (countBadge) countBadge.textContent = this.videoList.size;

            // 更新asset页面的按钮
            this.updateAssetButtonsVideoCount();

            // 视频面板可能尚未创建
            if (!this.videoPanel) {
                this.createVideoPanel();
            }

            // 更新视频面板标题
            const panelTitle = this.videoPanel.querySelector('div:first-child');
            if (panelTitle) {
                panelTitle.textContent = `检测到 ${this.videoList.size} 个视频`;
            }

            // 更新视频面板
            const content = this.videoPanel.querySelector('div:last-child');
            content.innerHTML = '';  // 清空内容

            Array.from(this.videoList.entries()).forEach(([url, info], index) => {
                const videoContainer = document.createElement('div');
                videoContainer.style = 'padding:12px;border-bottom:1px solid #eee;';

                // 创建视频信息标题
                const titleDiv = document.createElement('div');
                titleDiv.style = 'font-size:12px;color:#666;word-break:break-all;';
                titleDiv.textContent = `视频 ${index + 1} - ${new Date(info.timestamp).toLocaleTimeString()}`;
                videoContainer.appendChild(titleDiv);

                // 创建视频预览区域
                const previewDiv = document.createElement('div');
                previewDiv.style = 'margin:8px 0;background:#f0f0f0;border-radius:4px;text-align:center;position:relative;height:120px;display:flex;justify-content:center;align-items:center;';

                // 默认占位符
                previewDiv.innerHTML = `
                    <div style="position:absolute;top:0;left:0;right:0;bottom:0;display:flex;flex-direction:column;justify-content:center;align-items:center;">
                        <svg width="42" height="42" viewBox="0 0 24 24" fill="#999999">
                            <path d="M12 2C6.48 2 2 6.48 2 12C2 17.52 6.48 22 12 22C17.52 22 22 17.52 22 12C22 6.48 17.52 2 12 2ZM10 16.5V7.5L16 12L10 16.5Z" fill="#999999"/>
                        </svg>
                        <div style="margin-top:8px;font-size:12px;color:#888;">视频预览</div>
                    </div>
                `;
                videoContainer.appendChild(previewDiv);

                // 创建下载按钮
                const downloadBtn = document.createElement('button');
                downloadBtn.textContent = '下载无水印版';
                downloadBtn.dataset.url = url;
                downloadBtn.style = 'margin-top:8px;padding:4px 8px;background:#007bff;color:white;border:none;border-radius:4px;';
                downloadBtn.addEventListener('click', () => this.downloadVideo(url));
                videoContainer.appendChild(downloadBtn);

                // 创建预览按钮
                const previewBtn = document.createElement('button');
                previewBtn.textContent = '预览视频';
                previewBtn.style = 'margin-top:8px;margin-left:8px;padding:4px 8px;background:#28a745;color:white;border:none;border-radius:4px;';
                previewBtn.addEventListener('click', () => {
                    // 检查是否已经有预览视频
                    if (previewDiv.querySelector('video')) {
                        previewDiv.innerHTML = `
                            <div style="position:absolute;top:0;left:0;right:0;bottom:0;display:flex;flex-direction:column;justify-content:center;align-items:center;">
                                <svg width="42" height="42" viewBox="0 0 24 24" fill="#999999">
                                    <path d="M12 2C6.48 2 2 6.48 2 12C2 17.52 6.48 22 12 22C17.52 22 22 17.52 22 12C22 6.48 17.52 2 12 2ZM10 16.5V7.5L16 12L10 16.5Z" fill="#999999"/>
                                </svg>
                                <div style="margin-top:8px;font-size:12px;color:#888;">视频预览</div>
                            </div>
                        `;
                        previewBtn.textContent = '预览视频';
                    } else {
                        // 创建一个新的视频元素用于预览
                        const videoPreview = document.createElement('video');
                        videoPreview.src = url;
                        videoPreview.controls = true;
                        videoPreview.style = 'max-width:100%;max-height:120px;border-radius:4px;';
                        videoPreview.volume = 0.5;
                        previewDiv.innerHTML = '';
                        previewDiv.appendChild(videoPreview);
                        previewBtn.textContent = '关闭预览';
                    }
                });
                videoContainer.appendChild(previewBtn);

                content.appendChild(videoContainer);
            });
        }

        downloadVideo(url) {
            if (!this.videoList.has(url)) return;

            GM_download({
                url: url,
                name: `即梦视频_${Date.now()}.mp4`,
                onload: () => {
                    this.videoList.delete(url);
                    this.updateVideoUI();
                },
                onerror: (e) => console.error('视频下载失败:', e)
            });
        }

        toggleVideoPanel() {
            this.videoPanel.style.display = this.videoPanel.style.display === 'none' ? 'block' : 'none';
        }

        setupDrag(element) {
            let isDragging = false;
            let startX = 0, startY = 0, initialX = 0, initialY = 0;

            element.querySelector('div:first-child').addEventListener('mousedown', e => {
                isDragging = true;
                startX = e.clientX;
                startY = e.clientY;
                initialX = element.offsetLeft;
                initialY = element.offsetTop;
                document.addEventListener('mousemove', onMouseMove);
                document.addEventListener('mouseup', onMouseUp);
            });

            const onMouseMove = e => {
                if (!isDragging) return;
                const dx = e.clientX - startX;
                const dy = e.clientY - startY;
                element.style.left = `${initialX + dx}px`;
                element.style.top = `${initialY + dy}px`;
            };

            const onMouseUp = () => {
                isDragging = false;
                document.removeEventListener('mousemove', onMouseMove);
                document.removeEventListener('mouseup', onMouseUp);
            };
        }

        handleGlobalClick(event) {
            if (event.target.closest('.jimeng-download-btn, .jimeng-video-btn, .jimeng-open-btn')) {
                event.stopImmediatePropagation();
            }
        }

        // 监听URL变化
        setupUrlChangeListener() {
            let lastUrl = window.location.href;

            // 通过定期检查URL是否变化来模拟监听
            setInterval(() => {
                const currentUrl = window.location.href;
                if (currentUrl !== lastUrl) {
                    lastUrl = currentUrl;
                    console.log('[即梦助手] 检测到URL变化:', currentUrl);

                    // 根据URL做相应处理
                    this.handleUrlChange();
                }
            }, 1000);
        }

        // 处理URL变化
        handleUrlChange() {
            // 处理悬浮按钮
            if (this.isImageGeneratePage()) {
                this.hideAssetPageButtons();
            } else if (this.isAssetPage()) {
                this.injectAssetPageButtons();
            } else {
                this.hideAssetPageButtons();
            }

            // 重置按钮状态
            this.buttonsAdded = false;
            setTimeout(() => this.safeUpdateButtons(), 1000);
        }

        // 隐藏悬浮按钮
        hideAssetPageButtons() {
            const buttonContainer = document.querySelector('.jimeng-asset-buttons');
            if (buttonContainer) {
                buttonContainer.style.display = 'none';
            }
        }

        // 判断当前是否为asset页面
        isAssetPage() {
            const url = window.location.href;
            return url.includes('/ai-tool/asset');
        }

        // 判断当前是否为图片生成页面
        isImageGeneratePage() {
            const url = window.location.href;
            return url.includes('/ai-tool/image/generate');
        }

        // 针对asset页面的特殊处理
        handleAssetPage() {
            if (!this.isAssetPage() || this.isImageGeneratePage()) return;

            // 设置定期检查,因为asset页面可能是动态加载的
            const checkInterval = setInterval(() => {
                if (document.readyState === 'complete') {
                    // 再次检查URL,因为在等待期间可能已经发生变化
                    if (this.isAssetPage() && !this.isImageGeneratePage()) {
                        this.injectAssetPageButtons();
                        if (document.querySelector('.jimeng-asset-buttons')) {
                            clearInterval(checkInterval);
                        }
                    } else {
                        this.hideAssetPageButtons();
                        clearInterval(checkInterval);
                    }
                }
            }, 1000);
        }

        // 在asset页面直接添加按钮
        injectAssetPageButtons() {
            if (!this.isAssetPage() || this.isImageGeneratePage()) return;

            // 如果已经添加过按钮,则不再添加,但确保它是可见的
            const existingButtons = document.querySelector('.jimeng-asset-buttons');
            if (existingButtons) {
                existingButtons.style.display = 'flex';
                return;
            }

            // 创建按钮容器
            const buttonContainer = document.createElement('div');
            buttonContainer.className = 'jimeng-asset-buttons';
            buttonContainer.style = CONFIG.ASSET_PAGE_BUTTON_CONTAINER_STYLE;

            // 添加按钮
            ['download', 'video', 'open'].forEach(type => {
                const buttonDiv = document.createElement('div');
                buttonDiv.className = `jimeng-${type}-btn custom-btn`;
                buttonDiv.style = CONFIG.BUTTON_STYLE;
                buttonDiv.onmouseover = () => buttonDiv.style = `${CONFIG.BUTTON_STYLE}${CONFIG.HOVER_STYLE}`;
                buttonDiv.onmouseout = () => buttonDiv.style = CONFIG.BUTTON_STYLE;

                const templates = {
                    download: () => `
                        <svg width="16" height="16" viewBox="0 0 24 24" fill="#1890ff">
                            <path d="M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z"/>
                        </svg>
                        <span style="margin-left:8px;color:#1890ff">下载PNG</span>
                    `,
                    video: () => `
                        <svg width="16" height="16" viewBox="0 0 24 24" fill="#eb2f96">
                            <path d="M18 3v2h-2V3H8v2H6V3H4v18h2v-2h2v2h8v-2h2v2h2V3h-2zM8 17H6v-2h2v2zm0-4H6v-2h2v2zm0-4H6V7h2v2zm10 8h-2v-2h2v2zm0-4h-2v-2h2v2zm0-4h-2V7h2v2z"/>
                        </svg>
                        <span style="margin-left:8px;color:#eb2f96">
                            视频下载
                            <span class="video-count" style="margin-left:4px;background:#ff4d4f;color:white;border-radius:10px;padding:0 6px;">
                                ${this.videoList.size}
                            </span>
                        </span>
                    `,
                    open: () => `
                        <svg width="16" height="16" viewBox="0 0 24 24" fill="#52c41a">
                            <path d="M19 19H5V5h7V3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14c1.1 0 2-.9 2-2v-7h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z"/>
                        </svg>
                        <span style="margin-left:8px;color:#52c41a">打开图片</span>
                    `
                };

                buttonDiv.innerHTML = templates[type]();
                buttonContainer.appendChild(buttonDiv);

                // 添加点击事件
                if (type === 'download') {
                    buttonDiv.onclick = () => this.handleDownload();
                } else if (type === 'video') {
                    buttonDiv.onclick = () => this.toggleVideoPanel();
                } else if (type === 'open') {
                    buttonDiv.onclick = () => this.handleOpen();
                }
            });

            // 将按钮容器添加到页面
            document.body.appendChild(buttonContainer);
            console.log('[即梦助手] 在asset页面添加按钮成功');

            // 添加拖动功能
            this.setupDrag(buttonContainer);

            // 保留一个引用以便后续操作
            this.assetButtonContainer = buttonContainer;
        }

        // 更新asset页面按钮中视频计数
        updateAssetButtonsVideoCount() {
            if (this.isAssetPage() && this.assetButtonContainer) {
                const countBadge = this.assetButtonContainer.querySelector('.video-count');
                if (countBadge) countBadge.textContent = this.videoList.size;
            }
        }
    }

    new JimengEnhancer();
})();