您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
B站直播截图工具,支援快捷键截图、连拍模式、支援自定义快捷键、连拍间隔设定、中英菜单切换
当前为
// ==UserScript== // @name Bilibili Live Screenshot Helper // @name:zh-TW Bilibili 直播截圖助手 // @name:zh-CN Bilibili 直播截图助手 // @namespace https://www.tampermonkey.net/ // @version 1.14 // @description Bilibili Live Screenshot Tool – supports hotkey capture, burst mode, customizable hotkeys, burst interval settings, and menu language switch between Chinese and English. // @description:zh-TW B站直播截圖工具,支援快捷鍵截圖、連拍模式、支援自定義快捷鍵、連拍間隔設定、中英菜單切換 // @description:zh-CN B站直播截图工具,支援快捷键截图、连拍模式、支援自定义快捷键、连拍间隔设定、中英菜单切换 // @match https://live.bilibili.com/* // @grant GM_registerMenuCommand // @grant GM_setValue // @grant GM_getValue // @run-at document-end // @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'); 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(t().langToggle, () => { promptWithLock(() => { GM_setValue('lang', lang === 'EN' ? 'ZH' : 'EN'); location.reload(); }); }); function takeScreenshot() { const video = document.querySelector('video'); if (!video || video.readyState < 2 || video.videoWidth === 0) 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 now = new Date(); const pad = n => n.toString().padStart(2, '0'); const padMs = n => n.toString().padStart(3, '0'); 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 roomIdMatch = location.pathname.match(/^\/(\d+)/); const roomId = roomIdMatch ? roomIdMatch[1] : 'UnknownRoom'; // 使用當前瀏覽器的日期時間 const dateStr = `${now.getFullYear()}${pad(now.getMonth() + 1)}${pad(now.getDate())}`; const filename = `${dateStr}_${pad(now.getHours())}_${pad(now.getMinutes())}_${pad(now.getSeconds())}_${padMs(now.getMilliseconds())}_${roomId}_${canvas.width}x${canvas.height}.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'); } 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; } }); })();