您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
B站视频截图工具,支持截图按钮、快捷键截图、连拍功能,支持自定义快捷键与连拍间隔,中英菜单切换
当前为
// ==UserScript== // @name Bilibili Video Screenshot Helper // @name:zh-TW Bilibili 影片截圖助手 // @name:zh-CN Bilibili 视频截图助手 // @namespace https://www.tampermonkey.net/ // @version 1.5 // @description Bilibili Video Screenshot Tool – supports screenshot button, hotkey capture, burst mode, customizable hotkeys and burst intervals, with menu language switch between Chinese and English. // @description:zh-TW B站影片截圖工具,支持截圖按鈕、快捷鍵截圖、連拍功能,支持自定義快捷鍵與連拍間隔,中英菜單切換 // @description:zh-CN B站视频截图工具,支持截图按钮、快捷键截图、连拍功能,支持自定义快捷键与连拍间隔,中英菜单切换 // @author ChatGPT // @match https://www.bilibili.com/* // @grant GM_registerMenuCommand // @grant GM_setValue // @grant GM_getValue // @run-at document- // @license MIT // ==/UserScript== (function () { 'use strict'; // ====== 預設設定 ====== const DEFAULT_KEY = 'S'; const DEFAULT_INTERVAL = 1000; const MIN_INTERVAL = 100; const SETTINGS_LOCK_KEY = 'screenshotHelperSettingsLock'; // ====== 語言包 ====== const LANGS = { EN: { screenshot: 'Screenshot', keySetting: key => `Set Screenshot Key (Current: ${key})`, intervalSetting: val => `Set Burst Interval (Current: ${val}ms)`, langToggle: 'Language: EN', keyPrompt: 'Enter new key (A-Z)', intervalPrompt: 'Enter new interval in ms (>= 100)', }, ZH: { screenshot: '截圖', keySetting: key => `設定截圖快捷鍵(目前:${key})`, intervalSetting: val => `設定連拍間隔(目前:${val} 毫秒)`, langToggle: '語言:ZH', keyPrompt: '輸入新快捷鍵(A-Z)', intervalPrompt: '輸入新的連拍間隔(最小 100ms)', } }; // ====== 目前狀態 ====== let lang = GM_getValue('lang', 'EN'); let currentKey = GM_getValue('hotkey', DEFAULT_KEY); let interval = GM_getValue('interval', DEFAULT_INTERVAL); const t = () => LANGS[lang]; // ====== 提示鎖定機制(防止彈出兩次) ====== async function promptWithLock(action) { if (localStorage.getItem(SETTINGS_LOCK_KEY) === '1') return; localStorage.setItem(SETTINGS_LOCK_KEY, '1'); // 使用 requestAnimationFrame 等待畫面穩定再解除鎖 await new Promise(resolve => requestAnimationFrame(resolve)); localStorage.removeItem(SETTINGS_LOCK_KEY); action(); } // ====== 功能設定選單 ====== GM_registerMenuCommand(t().keySetting(currentKey), () => { promptWithLock(() => { const input = prompt(t().keyPrompt); if (input && /^[a-zA-Z]$/.test(input)) { const newKey = input.toUpperCase(); if (newKey !== currentKey) { GM_setValue('hotkey', newKey); location.reload(); } } }); }); GM_registerMenuCommand(t().intervalSetting(interval), () => { promptWithLock(() => { const input = prompt(t().intervalPrompt); const val = parseInt(input); if (!isNaN(val) && val >= MIN_INTERVAL && val !== interval) { GM_setValue('interval', val); location.reload(); } }); }); GM_registerMenuCommand(lang === 'EN' ? 'Language: EN' : '語言:ZH', () => { promptWithLock(() => { GM_setValue('lang', lang === 'EN' ? 'ZH' : 'EN'); location.reload(); }); }); // ====== 截圖邏輯 ====== function takeScreenshot() { // 只在播放頁面且影片正在播放時截圖 const video = document.querySelector('video'); const isVideoPage = /\/video\/(BV\w+)/.test(location.pathname); if (!isVideoPage || !video || video.paused) return; // 只有在影片頁且影片播放中才能截圖 const canvas = document.createElement('canvas'); canvas.width = video.videoWidth; canvas.height = video.videoHeight; const ctx = canvas.getContext('2d'); ctx.drawImage(video, 0, 0, canvas.width, canvas.height); const pad = n => n.toString().padStart(2, '0'); const padMs = n => n.toString().padStart(3, '0'); const bvIdMatch = location.href.match(/\/video\/(BV\w+)/); const bvId = bvIdMatch ? bvIdMatch[1] : 'UnknownBV'; const videoTime = video.currentTime; const h = pad(Math.floor(videoTime / 3600)); const m = pad(Math.floor((videoTime % 3600) / 60)); const s = pad(Math.floor(videoTime % 60)); const ms = padMs(Math.floor((videoTime * 1000) % 1000)); const res = `${canvas.width}x${canvas.height}`; const filename = `${h}_${m}_${s}_${ms}_${bvId}_${res}.png`; canvas.toBlob(blob => { const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = filename; a.click(); URL.revokeObjectURL(url); }, 'image/png'); } // ====== 插入按鈕 ====== function insertScreenshotButton() { const qualityBtn = document.querySelector('.bpx-player-ctrl-quality'); if (!qualityBtn || document.querySelector('.bili-screenshot-btn')) return; const btn = document.createElement('div'); btn.className = 'bpx-player-ctrl-btn bili-screenshot-btn'; btn.style.display = 'flex'; btn.style.alignItems = 'center'; btn.style.justifyContent = 'center'; btn.style.cursor = 'pointer'; btn.style.fontSize = '18px'; btn.style.marginRight = '6px'; btn.title = t().screenshot; btn.innerHTML = '📸'; btn.addEventListener('click', takeScreenshot); qualityBtn.parentNode.insertBefore(btn, qualityBtn); } // ====== 快捷鍵與連拍 ====== let holdTimer = null; document.addEventListener('keydown', e => { if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA' || e.target.isContentEditable) return; if (e.key.toUpperCase() === currentKey && !holdTimer) { takeScreenshot(); holdTimer = setInterval(takeScreenshot, interval); } }); document.addEventListener('keyup', e => { if (e.key.toUpperCase() === currentKey && holdTimer) { clearInterval(holdTimer); holdTimer = null; } }); // ====== 監聽 DOM 插入按鈕 ====== const observer = new MutationObserver(() => { insertScreenshotButton(); }); observer.observe(document.body, { childList: true, subtree: true }); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址