🎉 欢迎访问GreasyFork.Org 镜像站!本镜像站由公众号【爱吃馍】搭建,用于分享脚本。联系邮箱📮

Greasy fork 爱吃馍镜像

通用视频播放器截图工具(测试)

适用于所有视频播放器的截图脚本(H5、Flash、iframe等)

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

🚀 安装遇到问题?关注公众号获取帮助

公众号二维码

扫码关注【爱吃馍】

回复【脚本】获取最新教程和防失联地址

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

🚀 安装遇到问题?关注公众号获取帮助

公众号二维码

扫码关注【爱吃馍】

回复【脚本】获取最新教程和防失联地址

// ==UserScript==
// @name         通用视频播放器截图工具(测试)
// @icon         data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADwAAAA8CAYAAAA6/NlyAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAB3RJTUUH6AgOExwe5HRyqgAAAAZiS0dEAP8A/wD/oL2nkwAADVVJREFUaN7tmnlQVdcdx1+STmeSmXQy/adtlpnOtE1m0qi8fRdEBUFFCC64oiaSAgZFXBJNouIGxroGcV8IaCKLcTcGXAA1EbDRoJgajE2jWZrEJdGIIN/+fucu777HY42QhPHOfOfed+/ZPvf3O+f8zrlPp2vlgTwDycgKoetk0v18r9MeMixBGlcS6DekcOQadZ0WWgb+C6maBAKtJD0jLJ/byaA17pxIqpeABfRe0h86nZVl2IdJRR5YAcxaQXqwJdCiC+QaH6C0D6FAfx/pFwibq1jX0JPO36uwuQZJecZbdE4i3efPtWXI+0l/IkWSaAww9hX3OxJYttrvSS7S30iPkH6DXL0O+WYfdxYjcoYX7I4eQL5FAf+aFC7K5BfUEDKTdJZUS2lOkx7ntD+HmzJkHulLUhkpl7SANJYURPor6XekJwm4WoXNMwFVG4CjycC2AOUlVJK6EtQfSQM0kDWabsD9f4LiNR3sqkbFenbSJe++KRp2k/Q56QTpOKlOAtMDu0OB658C31ZK13xPPDOeITF4jcbl+b7S309iu+FRFPxMgxwOkfv2cuqoEZOoMbU+0P61rRtZdhJw5zbE8fFmyeIKIFucX8B2h+c+wd4h6HMrTWmP/737E3qr+8/tpCcCrO5HSA+QvGENVruui9mte+xp98MRoc7EE4vN15FvkK0hW5LhGoiAqnOhHjXXgNIk6dk73YFDY4Cza4CKeVSOWQKmcgkWoT2dX3azuC9Sw9pD/yFdINAy0hq9xR2mt7geJEnAAXRBPx7VW11bu5rdt0dGOvDVJpPketzI/VHAiVeAD1gzPKqYC3z/X3gd352lPr0e+N+/gNob5O4XgXcHyq4uWTc93gaqB1Rvu4vAQWw3SOsJ/FESAVvdD5HW0Q9KJGnxeBvqcmXr7gkHLpdIQPX1pDuy6iU1dtTdohf1GpUR4GXd3sEukHWlxrSDupmdQgzc1eTwgFtdOaRHGDiablxXM1Bj3G4XiheaIbl2gAT9RSladVzcBRTYvPqux7pSXVpraBvqZaFWwkbHjMSmrBzkb9+JpEnTYLQHymW5bgVYXfEMXOCbkRvl7dqthGZX3/+slI/HAXpxn6ySrNvVLMHx2+e6rO6e6N4rHMFhA4T4mu+JdlAa5SW0BDa0XxROf1SpNuPqtWsCWqmLvLiU++9l38yqayfaULtNGbxk6MulTbsyHze/BkpelLqEbOFvs4yY+ZwdNncPhEfFIGnKDCzJ3ICcgj3Y+V4x9h95X4iv+R4/S5r6CqUdIqzk7Z4N1cVoR/KUl1FbW+vVlLyCd7Qec5WB6xoW4BJWptFUWEZybZ5qugLvxQA/XGreyjcuN4D+IceAw6tG4GBxMcrOXsDJc58KVVRd8JJyv+zMJyg6VoGMDdkYPvYfMDmCGrU4v5C4xAm4efOmVzM2ZmVr89Tr/FmXYUMI9p2ZFtS8LQ9erKJRZOFiz9zbBuj6AjOuHEjE6Q+PobzqogrMcCwtcPnZavV36ckzWL52s7C4P2j+bQ/sjW352/HjrVuoq6sT7s19mtMr6XT+YIdFOFC+xIx60X/10rx6agm56ldo9eELnSuVeWPPYBx7dxPSlq1CyoxUJCS/JDSZrtOWZpJb78bhE6dUqzM8g+85eBTPJyarkP6g2dLs3iHUp7WwXsDSyOnC5JF2fLZOcWO9NPiwVevr0Objh88pEBmrCT3Z2np8vdmM18baoDc7qA86hFsqAxUPXJGDR2J2+lLRtxVoPheXf4RJL8+CwdbdLzSXwX3aF1YF7kZWtTtdWJ5kw7UcI9RIixu2Jww4uQD4/KA0GPEc3JKD03H6S4ek/Hv6qm6tQlM9N7casXGKFUGBLmmw1ExXiuuGRQ7G0tUbcfzUORX6KLn4hKmvtnoK0yn9dQf119vb1OBe0zA5tMy3UtQULTWeLdbctMTpOD3n4/xkUfEiZXF3uU3jw5U3jTifaULqODtZzKXO0VqLMbjZ2YNcfzaKy06rbn7ogw8x4rl4v5ZsFDg2ygGKn0UD6smq/nRHnA1Sw3f1Aq5VayzJU5TPNPXdGer3bhFvcz4e+L6jaek8jfglFNBsnW4VQciLMXYMDLcjOMgBm9MlA5JVzfIUpLGcYsnxk6ejpKJS7dN5ewoR3CeixdC6uEEOvDLGjumj/eulWDsyJtqE6yFXXiHV1cgD0pfAv3MIsMobuOYqUDhczN3Xso2Y9bwd0eFOAnPBYufQ0oUuJgo+nH2gj4iDeXQqLPFLYSVZxqTCFBkHvbuPBO8DzecZc9JxovK8gC4nS89OX9Ji1xYu3cXUuJ42ujGbGlyvrGmr8ySrfkHxdVGs5PL7BgCf7afpqtZj9fJU8YKu05gwNMKJZ0xS2CoaZQ+CaWASbNO2wjH/MJzppaSjskrFPX7GaTitLzSPxBu25KNCntIOlJwQ/bwlVtY19ZD7k5ksUrTAQv1OLw1gX30AnF5OLhsor3nl0HO7S7p/64oEfaFAvKBacucJw+zoIq+Q9I6esDy3AI55hyTQtBI4FxRLZ+01g1MaTst5tNA8CsfEjhOjtTKIzZizsEVhaJPAbP2oMKccU8vAhcPUudRrQ0DxAJ5zr56Xloq830Vjw7w4G3kLN6Q7LOS+DgVKC+or+Rmn5TycV4HhM0ddq7PeVoOUt3fuhyMo5KcBs1XmUmPrc7U7lHoPnDLqaqcatvq+SOCTbVIYmheAtSlWsooTxv5j4JjzXvOwvtCUh/MGaFyWrRw/cZral3n0jhwyslm31rXMnTXzcp4EyevlqgwTNtAcKuLtPO3elV5ycY7QKO2OWRbobYGwjl8p9dOWwGqhKQ/n5TIUCzJYnwGDUEixthKaJqa87FkZtRbY2529QXkhv5Cmld7BTpFuSD8nPspkOI1rK2Ek5Tn2ugm2kEjYZ+5uOaiPOK8hOFKM3F6x864DqlvzaN1cP9a1yJ0bAVVG3a50fmP567hSlELzuckDLbv9uQwDggePhZ0HqjYC8wBm7D9WzNEKMC8b1+XkqsCLM9c3Oz3pmnLng2kWdWumIaj33LhiXTZOna3C5cNzUVfgkF1city+WK/HgLEJsM8vbjswubYpOtELmGPplRtyVOAV6970u6hoFphj68g+TpRSVPR6gn9Q32Bg2epNVOlFVJw9j1N7F+KbLJM6oH2frUds/DjY5h1pOzDNzabIFxoAr978lgrMbWgTMEMFUjDfK9jVKKhvrDt/cYZacU7BXiSPCkL1agn69lt6JCcMhGXWgbYDp74LQ8gQrz5soRUVLyOVerkNbezDUhDfFKjvbgMH9koQsPfwcQSGRmBQXwfKFkubgfMSg2Ce9KYUbLR6lC6FbTK5q7OX1yjNMTTXpSwduQ1tHqVbI65k2JgXcOzDKlExn3kV8wytcXkltm+OBauTLTAMTqG+eKQN/fcIzENSJOvKwFwn16Gtc+joFzoGmN92UGh/7CoqUbdk0pZlyu7uRvfuLgwf4IDB1Ru2CWs9IWVaU5b2hJjWCWugp7zaSIvFdShbRLsKSxAU0t8rOGk3YKUhizLWqg3Yd+R9hEYMlPuU0j2cMPSMgm1Ktv842k88zWk5j9J31S1ZKlvZCeE6ue7mBqy7Bqy42NDRcSiV16rckPmL3/BYRH05BN0jgpaCy+CYW6iukJxpsuSVk2NuEawJy0RaLawCxGUrfZfrjKG6m3PnuwrMDeFdiVWbtqo7jkcovh01bnyDPWUBQMs+jo8tcYtgm7oF9ld3CPE13+Nn0tLQ2WC/isvkspVNgEyqk+tu0Xr4bn/XiR42GkXHT6rbMDsLizFg0HA/0C5Pf6PR1xDYV4ivxXNzw8U/lxFBZXGZSvlcF9fZ4h2PuwmsDCbTZs5XVzHcqPx9RXg2JrbR/eRGv/z5zPVRMaOQv7dIdWWug+tqzUbeXQVWGsdbrPypRGzByND7aL7k5Ry7XnOfTXytynniJ04VZSiwLK6D62rVrmV7fbJ09QxDxvpsL2ieKzM3bUFMbJxoqHYfWivlPqfhnY3MjVtEXi0sl811tGbHst2AFWhnj1CkL1sl9pO1Xw941zErdyemp6ZT8JCAfs8ORe++UUJ8PeL5BPGM03Ba7WcXLit9+So4g/u0GrZdgRVoE7kjb63uPni0wWcTBYD3lw+UlgnxtfKCtKAs/szCZbGLtwW23YG1A05o/2jMWbRcBCS8O6EASy7q+XJYrvmkonxB5ABj7qIVVMbAFn8vbgr4x46C5nNIv2hMnPaa2IBjq/PO4/unPxYjLouv+R5bcw2lSX5pJkLoZWnLaHM7pO/D7qr2BvYF5wGJdys4/uaphgOJuBdThPg6asgo8Uz5EP5TQVVZ3Ef5Lw+LSPUdBe0L383k+Wqojtp3E9Kzxq+l8lIY+EnSyY4G7vAXbHWXEvRj1IddOroIpHNlpwW2uD+mdbRb/DktgID1ZjcPXk/Rg3/SmzhH8Df4/xB66Qte/a9OVpa7hgx5ia6z6BzQzerWiT+mKQf/J5H/m0gJHiMFUcYY0ohfpayuoQQcRqBPkUF/S2c2aOf6t/69495x77h3dMrj/3/LPCYOCfsBAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDI0LTA4LTE0VDE5OjI4OjI3KzAwOjAw3KhE6wAAACV0RVh0ZGF0ZTptb2RpZnkAMjAyNC0wOC0xNFQxOToyODoyNyswMDowMK31/FcAAAAASUVORK5CYII=
// @version      2025.07.18
// @description  适用于所有视频播放器的截图脚本(H5、Flash、iframe等)
// @author       嘉友友
// @match        *://www.youtube.com/*
// @match        *://www.bilibili.com/*
// @match        *://live.bilibili.com/*
// @match        *://www.twitch.tv/*
// @match        *://live.douyin.com/*
// @match        *://live.kuaishou.com/*
// @license      GPL-3.0
// @namespace https://greasyfork.org/users/1336389
// ==/UserScript==

(function() {
    'use strict';

    // 缓存优化
    const cache = {
        videoElements: null,
        lastCacheTime: 0,
        cacheValidityTime: 2000, // 缓存2秒有效
        queryResults: new Map()
    };

    // 防抖函数
    function debounce(func, wait) {
        let timeout;
        return function executedFunction(...args) {
            const later = () => {
                clearTimeout(timeout);
                func(...args);
            };
            clearTimeout(timeout);
            timeout = setTimeout(later, wait);
        };
    }

    // 节流函数
    function throttle(func, limit) {
        let inThrottle;
        return function(...args) {
            if (!inThrottle) {
                func.apply(this, args);
                inThrottle = true;
                setTimeout(() => inThrottle = false, limit);
            }
        };
    }

    // 优化的页面检查(使用缓存)
    function isVideoPage() {
        const cacheKey = 'isVideoPage';
        if (cache.queryResults.has(cacheKey)) {
            return cache.queryResults.get(cacheKey);
        }

        const url = window.location.href.toLowerCase();
        const videoKeywords = [
            'youtube', 'bilibili', 'iqiyi', 'youku', 'douyin', 'tiktok',
            'twitch', 'kuaishou', 'huya', 'douyu', 'acfun', 'vimeo',
            'video', 'movie', 'play', 'watch', 'live', 'stream'
        ];

        const result = videoKeywords.some(keyword => url.includes(keyword)) ||
                      document.querySelector('video, embed, object, iframe[src*="video"], iframe[src*="player"]');

        cache.queryResults.set(cacheKey, result);
        // 清理缓存,避免内存泄漏
        setTimeout(() => cache.queryResults.delete(cacheKey), 5000);

        return result;
    }

    // 优化的视频元素查找(使用缓存和优化查询)
    function findVideoElements() {
        const now = Date.now();

        // 使用缓存
        if (cache.videoElements && now - cache.lastCacheTime < cache.cacheValidityTime) {
            return cache.videoElements;
        }

        // 优化选择器,按常用程度排序
        const selectors = [
            'video', // 最常用的放前面
            '.html5-main-video',
            '.video-stream',
            '.bilibili-live-player video',
            '.bpx-player-video-wrap video',
            '#movie_player video',
            '.player-area video',
            '.xgplayer video'
        ];

        const videos = [];
        const processedElements = new Set(); // 避免重复处理

        for (const selector of selectors) {
            try {
                const elements = document.querySelectorAll(selector);
                for (const element of elements) {
                    if (element.tagName === 'VIDEO' && !processedElements.has(element)) {
                        processedElements.add(element);
                        // 使用更高效的尺寸检查
                        if (element.offsetWidth > 0 && element.offsetHeight > 0) {
                            videos.push(element);
                        }
                    }
                }
                // 如果已经找到视频,优先使用第一个匹配的选择器结果
                if (videos.length > 0 && selector === 'video') break;
            } catch (e) {
                // 忽略选择器错误,继续下一个
                continue;
            }
        }

        // 缓存结果
        cache.videoElements = videos;
        cache.lastCacheTime = now;

        return videos;
    }

    // 优化的视频有效性检查(减少DOM查询)
    function isValidVideo(video) {
        // 先检查最简单的属性
        if (video.hidden) return false;

        // 使用 offsetWidth/offsetHeight 替代 getBoundingClientRect(性能更好)
        if (video.offsetWidth <= 0 || video.offsetHeight <= 0) return false;

        // 最后检查 computed style(最耗性能的)
        const style = video.currentStyle || window.getComputedStyle(video);
        return style.display !== 'none';
    }

    // 优化的视频元素截图(保持源质量)
    async function captureVideoElement(video) {
        try {
            // 提前检查,避免无用计算
            if (video.readyState < 1) {
                return { success: false, message: '视频尚未加载,请稍后再试' };
            }

            const canvas = document.createElement('canvas');
            const ctx = canvas.getContext('2d', { alpha: false }); // 禁用alpha通道提升性能

            canvas.width = video.videoWidth || video.clientWidth;
            canvas.height = video.videoHeight || video.clientHeight;

            try {
                ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
            } catch (e) {
                if (e.name === 'SecurityError') {
                    return { success: false, message: 'CORS安全限制,无法截取此视频' };
                }
                throw e;
            }

            return new Promise((resolve) => {
                canvas.toBlob(function(blob) {
                    if (!blob) {
                        resolve({ success: false, message: '生成图片失败' });
                        return;
                    }

                    downloadImage(blob, canvas.width, canvas.height);
                    resolve({
                        success: true,
                        width: canvas.width,
                        height: canvas.height
                    });
                }, 'image/png', 1.0); // 保持源质量 1.0
            });

        } catch (error) {
            return { success: false, message: '截图失败: ' + error.message };
        }
    }

    // 优化的H5视频截图
    function captureH5Video() {
        const videos = findVideoElements();

        // 优先级排序:可见 > 已加载 > 大尺寸
        const sortedVideos = videos
            .filter(video => isValidVideo(video) && video.readyState >= 1)
            .sort((a, b) => {
                const aRect = { width: a.offsetWidth, height: a.offsetHeight };
                const bRect = { width: b.offsetWidth, height: b.offsetHeight };
                return (bRect.width * bRect.height) - (aRect.width * aRect.height);
            });

        for (let video of sortedVideos) {
            // 优先选择较大尺寸的视频
            if (video.offsetWidth >= 200 && video.offsetHeight >= 150) {
                return captureVideoElement(video);
            }
        }

        // 如果没有大尺寸的,选择第一个可用的
        if (sortedVideos.length > 0) {
            return captureVideoElement(sortedVideos[0]);
        }

        return null;
    }

    // 优化的iframe查找(减少DOM查询)
    function captureIframeVideo() {
        const iframes = document.querySelectorAll('iframe[src*="video"], iframe[src*="player"], iframe[src*="youtube"], iframe[src*="bilibili"], iframe[src*="vimeo"], iframe[src*="live"]');

        const validIframes = [];
        for (const iframe of iframes) {
            if (iframe.offsetWidth > 0 && iframe.offsetHeight > 0) {
                validIframes.push({
                    element: iframe,
                    area: iframe.offsetWidth * iframe.offsetHeight
                });
            }
        }

        if (validIframes.length > 0) {
            // 选择面积最大的iframe
            validIframes.sort((a, b) => b.area - a.area);
            return captureElementArea(validIframes[0].element);
        }
        return null;
    }

    // 优化的Flash/Object查找
    function captureFlashVideo() {
        const objects = document.querySelectorAll('object[type*="flash"], object[data*="video"], embed[type*="flash"], embed[src*="video"]');

        const validObjects = [];
        for (const obj of objects) {
            if (obj.offsetWidth > 0 && obj.offsetHeight > 0) {
                validObjects.push(obj);
                break; // 找到第一个就够了
            }
        }

        if (validObjects.length > 0) {
            return captureElementArea(validObjects[0]);
        }
        return null;
    }

    // 优化的元素区域截图(保持源质量)
    function captureElementArea(element) {
        try {
            const width = Math.min(element.offsetWidth, 1920);
            const height = Math.min(element.offsetHeight, 1080);

            if (width === 0 || height === 0) {
                return { success: false, message: '播放器区域无效' };
            }

            const canvas = document.createElement('canvas');
            const ctx = canvas.getContext('2d', { alpha: false });

            canvas.width = width;
            canvas.height = height;

            // 优化绘制过程,减少绘制调用
            ctx.fillStyle = '#1a1a1a';
            ctx.fillRect(0, 0, width, height);

            ctx.strokeStyle = '#333333';
            ctx.lineWidth = 2;
            ctx.strokeRect(1, 1, width - 2, height - 2);

            // 合并文字绘制
            ctx.textAlign = 'center';
            ctx.fillStyle = '#ffffff';
            ctx.font = 'bold 28px Arial';
            ctx.fillText('🎬 视频播放器区域', width / 2, height / 2 - 40);

            ctx.font = '18px Arial';
            ctx.fillStyle = '#ffcc00';
            ctx.fillText('无法直接截取视频内容', width / 2, height / 2);

            ctx.fillStyle = '#888888';
            ctx.font = '16px Arial';
            ctx.fillText(`尺寸: ${Math.round(element.offsetWidth)} × ${Math.round(element.offsetHeight)}`, width / 2, height / 2 + 40);

            return new Promise((resolve) => {
                canvas.toBlob(function(blob) {
                    downloadImage(blob, width, height);
                    resolve({ success: true, isPlaceholder: true });
                }, 'image/png', 1.0); // 保持源质量 1.0
            });

        } catch (error) {
            return { success: false, message: '截图失败: ' + error.message };
        }
    }

    // 优化的主截图函数
    async function captureVideoFrame() {
        try {
            // 清除缓存,强制重新查找
            cache.videoElements = null;

            const h5Result = captureH5Video();
            if (h5Result) {
                const result = await h5Result;
                if (result.success) {
                    showMessage(`📸 截图成功!分辨率: ${result.width}×${result.height}`, 'success');
                    return;
                } else {
                    showMessage(result.message, 'warning');
                }
            }

            // 使用 requestAnimationFrame 优化后续操作
            await new Promise(resolve => requestAnimationFrame(resolve));

            const iframeResult = captureIframeVideo();
            if (iframeResult) {
                const result = await iframeResult;
                if (result.success) {
                    const type = result.isPlaceholder ? '播放器区域截图' : '截图';
                    showMessage(`📸 ${type}成功!`, 'success');
                    return;
                }
            }

            const flashResult = captureFlashVideo();
            if (flashResult) {
                const result = await flashResult;
                if (result.success) {
                    showMessage('📸 播放器区域截图成功!', 'success');
                    return;
                }
            }

            showMessage('未找到可截图的视频播放器!\n请等待视频加载完成后再试', 'error');
        } catch (error) {
            showMessage('截图过程出错:' + error.message, 'error');
        }
    }

    // 优化的视频信息获取
    function getVideoInfo() {
        const videos = findVideoElements();

        if (videos.length === 0) {
            return '📺 未检测到有效的视频播放器';
        }

        const infoParts = [`📺 检测到 ${videos.length} 个有效视频播放器:\n`];
        let validCount = 0;

        videos.forEach((video) => {
            const isVisible = isValidVideo(video);
            const videoWidth = video.videoWidth || 0;
            const videoHeight = video.videoHeight || 0;
            const displayWidth = video.offsetWidth;
            const displayHeight = video.offsetHeight;

            if (displayWidth > 0 && displayHeight > 0) {
                validCount++;
                const status = video.readyState >= 1 ? '✅' : '⏳';
                const visibility = isVisible ? '👁️' : '🚫';

                let info = `${validCount}. ${status}${visibility} `;

                if (videoWidth && videoHeight) {
                    info += `视频分辨率: ${videoWidth}×${videoHeight}\n`;
                    if (displayWidth !== videoWidth || displayHeight !== videoHeight) {
                        info += `   显示尺寸: ${displayWidth}×${displayHeight}\n`;
                    }
                } else {
                    info += `显示尺寸: ${displayWidth}×${displayHeight}\n`;
                }

                if (video.duration && !isNaN(video.duration) && video.duration !== Infinity) {
                    const duration = Math.round(video.duration);
                    const minutes = Math.floor(duration / 60);
                    const seconds = duration % 60;
                    info += `   时长: ${minutes}:${seconds.toString().padStart(2, '0')}\n`;
                }

                infoParts.push(info + '\n');
            }
        });

        // 优化iframe检查
        const validIframes = document.querySelectorAll('iframe[src*="video"], iframe[src*="player"], iframe[src*="youtube"], iframe[src*="bilibili"]');
        const visibleIframes = Array.from(validIframes).filter(iframe =>
            iframe.offsetWidth > 0 && iframe.offsetHeight > 0
        );

        if (visibleIframes.length > 0) {
            infoParts.push(`📱 iframe播放器: ${visibleIframes.length} 个\n`);
            visibleIframes.forEach((iframe, index) => {
                infoParts.push(`${index + 1}. 尺寸: ${iframe.offsetWidth}×${iframe.offsetHeight}\n`);
            });
        }

        if (validCount === 0 && visibleIframes.length === 0) {
            return '📺 未检测到有尺寸信息的播放器';
        }

        return infoParts.join('').trim();
    }

    // 优化的下载函数(使用 revokeObjectURL 的延迟清理)
    function downloadImage(blob, width, height) {
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;

        const now = new Date();
        const timestamp = now.getFullYear() +
            String(now.getMonth() + 1).padStart(2, '0') +
            String(now.getDate()).padStart(2, '0') + '_' +
            String(now.getHours()).padStart(2, '0') +
            String(now.getMinutes()).padStart(2, '0') +
            String(now.getSeconds()).padStart(2, '0');

        const domain = window.location.hostname.replace(/\./g, '_');
        a.download = `${domain}_video_${timestamp}.png`;

        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);

        // 延迟清理,确保下载完成
        setTimeout(() => URL.revokeObjectURL(url), 1000);
    }

    // 优化的消息显示(缓存样式)
    const messageStyles = {
        success: { bg: 'rgba(40, 167, 69, 0.95)', icon: '✅' },
        error: { bg: 'rgba(220, 53, 69, 0.95)', icon: '❌' },
        warning: { bg: 'rgba(255, 193, 7, 0.95)', icon: '⚠️' },
        info: { bg: 'rgba(52, 58, 64, 0.95)', icon: 'ℹ️' }
    };

    function showMessage(text, type = 'info') {
        const messageDiv = document.createElement('div');
        const style = messageStyles[type];

        messageDiv.textContent = `${style.icon} ${text}`;
        messageDiv.style.cssText = `
            position: fixed;
            top: 20px;
            right: 20px;
            background: ${style.bg};
            color: white;
            padding: 12px 20px;
            border-radius: 8px;
            font-size: 14px;
            font-family: -apple-system, BlinkMacSystemFont, sans-serif;
            z-index: 999999;
            box-shadow: 0 4px 20px rgba(0,0,0,0.3);
            max-width: 350px;
            word-wrap: break-word;
            white-space: pre-line;
            opacity: 0;
            transform: translateX(20px);
            transition: all 0.3s ease;
            will-change: transform, opacity;
        `;

        document.body.appendChild(messageDiv);

        // 使用 requestAnimationFrame 优化动画
        requestAnimationFrame(() => {
            messageDiv.style.opacity = '1';
            messageDiv.style.transform = 'translateX(0)';
        });

        const hideDelay = type === 'error' ? 5000 : 3500;
        setTimeout(() => {
            messageDiv.style.opacity = '0';
            messageDiv.style.transform = 'translateX(20px)';
            setTimeout(() => {
                if (document.body.contains(messageDiv)) {
                    document.body.removeChild(messageDiv);
                }
            }, 300);
        }, hideDelay);
    }

    // 优化的键盘事件监听(防抖处理)
    const debouncedCapture = debounce(captureVideoFrame, 300);
    const debouncedInfo = debounce(() => {
        const info = getVideoInfo();
        showMessage(info, 'info');
    }, 300);

    document.addEventListener('keydown', function(event) {
        // 避免在输入框中触发
        if (event.target.tagName === 'INPUT' || event.target.tagName === 'TEXTAREA') {
            return;
        }

        if (event.altKey && event.code === 'Digit1') {
            event.preventDefault();
            debouncedCapture();
        }

        if (event.altKey && event.code === 'Digit2') {
            event.preventDefault();
            debouncedInfo();
        }
    }, { passive: false });

    // 优化的初始化
    function initialize() {
        if (!isVideoPage()) return;

        const videos = findVideoElements();
        if (videos.length > 0) {
            showMessage(`🎬 截图工具已就绪\nAlt+1: 截图  Alt+2: 查看信息\n检测到 ${videos.length} 个有效播放器`, 'success');
        } else {
            showMessage('🎬 截图工具已就绪\nAlt+1: 截图  Alt+2: 查看信息', 'info');
        }
    }

    // 优化的页面变化监听(节流 + 防抖)
    let lastUrl = location.href;
    const throttledObserver = throttle(() => {
        const currentUrl = location.href;
        if (currentUrl !== lastUrl) {
            lastUrl = currentUrl;
            // 清除缓存
            cache.videoElements = null;
            cache.queryResults.clear();

            setTimeout(() => {
                if (isVideoPage()) initialize();
            }, 1500);
        }
    }, 1000);

    // 使用更精确的观察配置
    const observer = new MutationObserver(throttledObserver);
    observer.observe(document, {
        subtree: true,
        childList: true,
        attributes: false, // 不观察属性变化
        characterData: false // 不观察文本变化
    });

    // 页面卸载时清理资源
    window.addEventListener('beforeunload', () => {
        observer.disconnect();
        cache.queryResults.clear();
        cache.videoElements = null;
    });

    // 优化的页面加载检查
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', () =>
            setTimeout(initialize, 1000), { once: true });
    } else {
        setTimeout(initialize, 1000);
    }

})();