您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
适用于所有视频播放器的截图脚本(H5、Flash、iframe等)
// ==UserScript== // @name 通用视频播放器截图工具(测试) // @icon data:image/png;base64,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 // @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); } })();