// ==UserScript==
// @name H5视频播放器截图工具
// @version 2025.07.14.6
// @description 适用于所有H5播放器的截图脚本,快捷键Alt+1
// @author 嘉友友
// @match *://www.youtube.com/*
// @match *://www.bilibili.com/*
// @license GPL-3.0
// @namespace https://greasyfork.org/users/1336389
// ==/UserScript==
(function() {
'use strict';
// 创建截图功能
function captureVideoFrame() {
// 查找页面中的视频元素
const videos = document.querySelectorAll('video');
if (videos.length === 0) {
showMessage('未找到视频播放器!', 'error');
return;
}
// 选择第一个可见的视频元素
let targetVideo = null;
for (let video of videos) {
const rect = video.getBoundingClientRect();
if (rect.width > 0 && rect.height > 0 && !video.hidden && video.readyState >= 2) {
targetVideo = video;
break;
}
}
if (!targetVideo) {
showMessage('未找到正在播放的视频!', 'error');
return;
}
try {
// 创建canvas元素
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// 设置canvas尺寸为视频原始尺寸
canvas.width = targetVideo.videoWidth || targetVideo.clientWidth;
canvas.height = targetVideo.videoHeight || targetVideo.clientHeight;
// 检查视频是否已加载
if (targetVideo.readyState < 2) {
showMessage('视频尚未加载完成,请稍后再试!', 'warning');
return;
}
// 将视频当前帧绘制到canvas
ctx.drawImage(targetVideo, 0, 0, canvas.width, canvas.height);
// 转换为PNG格式的blob
canvas.toBlob(function(blob) {
if (!blob) {
showMessage('截图失败,可能是由于CORS限制!', 'error');
return;
}
// 创建下载链接
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);
// 清理URL对象
URL.revokeObjectURL(url);
// 显示成功消息
const resolution = `${canvas.width}x${canvas.height}`;
showMessage(`📸 截图成功!分辨率: ${resolution}`, 'success');
}, 'image/png', 1.0); // 无损PNG格式,质量为1.0
} catch (error) {
console.error('截图错误:', error);
showMessage('截图失败: ' + error.message, 'error');
}
}
// 显示提示消息
function showMessage(text, type = 'info') {
const messageDiv = document.createElement('div');
messageDiv.textContent = text;
let bgColor;
switch(type) {
case 'success':
bgColor = 'rgba(40, 167, 69, 0.9)';
break;
case 'error':
bgColor = 'rgba(220, 53, 69, 0.9)';
break;
case 'warning':
bgColor = 'rgba(255, 193, 7, 0.9)';
break;
default:
bgColor = 'rgba(0, 0, 0, 0.8)';
}
messageDiv.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
background: ${bgColor};
color: white;
padding: 12px 20px;
border-radius: 6px;
font-size: 14px;
font-family: Arial, sans-serif;
z-index: 999999;
box-shadow: 0 4px 12px rgba(0,0,0,0.2);
max-width: 300px;
word-wrap: break-word;
transition: all 0.3s ease;
`;
document.body.appendChild(messageDiv);
// 3秒后自动消失
setTimeout(() => {
messageDiv.style.opacity = '0';
messageDiv.style.transform = 'translateX(20px)';
setTimeout(() => {
if (document.body.contains(messageDiv)) {
document.body.removeChild(messageDiv);
}
}, 300);
}, 3000);
}
// 获取当前页面视频信息
function getVideoInfo() {
const videos = document.querySelectorAll('video');
if (videos.length === 0) {
return '当前页面暂无视频';
}
let info = `发现 ${videos.length} 个视频元素:\n`;
videos.forEach((video, index) => {
const rect = video.getBoundingClientRect();
const isVisible = rect.width > 0 && rect.height > 0 && !video.hidden;
const isReady = video.readyState >= 2;
const resolution = video.videoWidth ? `${video.videoWidth}x${video.videoHeight}` : '未知';
info += `视频${index + 1}: ${resolution}, ${isVisible ? '可见' : '隐藏'}, ${isReady ? '已就绪' : '未就绪'}\n`;
});
return info;
}
// 监听键盘事件
document.addEventListener('keydown', function(event) {
// 检查是否按下Alt+1
if (event.altKey && event.code === 'Digit1') {
event.preventDefault();
captureVideoFrame();
}
});
// 注册Tampermonkey菜单命令
GM_registerMenuCommand('📸 截取视频截图', captureVideoFrame);
GM_registerMenuCommand('📺 查看视频信息', function() {
const info = getVideoInfo();
showMessage(info, 'info');
});
// 页面加载完成后的初始化
function initialize() {
const videos = document.querySelectorAll('video');
if (videos.length > 0) {
showMessage('H5视频截图工具已就绪\n快捷键: Alt+1\n或使用右键菜单', 'success');
}
// 为现有视频添加加载事件监听
videos.forEach(video => {
if (video.readyState < 2) {
video.addEventListener('loadeddata', function() {
showMessage('视频加载完成,可以截图了!', 'info');
}, { once: true });
}
});
}
// 监听动态添加的视频元素
const observer = new MutationObserver(function(mutations) {
let hasNewVideo = false;
mutations.forEach(function(mutation) {
if (mutation.type === 'childList') {
const addedNodes = Array.from(mutation.addedNodes);
const newVideos = addedNodes.filter(node =>
node.tagName === 'VIDEO' ||
(node.querySelectorAll && node.querySelectorAll('video').length > 0)
);
if (newVideos.length > 0) {
hasNewVideo = true;
}
}
});
if (hasNewVideo) {
setTimeout(() => {
showMessage('检测到新视频加载', 'info');
}, 1000);
}
});
// 页面加载状态检查
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', function() {
setTimeout(initialize, 1000);
});
} else {
setTimeout(initialize, 1000);
}
// 开始观察DOM变化
observer.observe(document.body, {
childList: true,
subtree: true
});
console.log('H5视频截图工具已加载');
})();