您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
动画疯截图工具,支援快捷键截图、连拍模式,自定义快捷键、连拍间隔设定、中英菜单切换
- // ==UserScript==
- // @name AniGamer Screenshot Helper
- // @name:zh-TW 動畫瘋截圖助手
- // @name:zh-CN 动画疯截图助手
- // @namespace https://www.tampermonkey.net/
- // @version 2.0
- // @description AniGamer Screenshot Tool – supports hotkey capture, burst mode, customizable hotkeys, burst interval settings, and menu language switch between Chinese and English.
- // @description:zh-TW 動畫瘋截圖工具,支援快捷鍵截圖、連拍模式,自定義快捷鍵、連拍間隔設定、中英菜單切換
- // @description:zh-CN 动画疯截图工具,支援快捷键截图、连拍模式,自定义快捷键、连拍间隔设定、中英菜单切换
- // @author ChatGPT
- // @match https://ani.gamer.com.tw/*
- // @grant GM_registerMenuCommand
- // @grant GM_getValue
- // @grant GM_setValue
- // @license MIT
- // ==/UserScript==
- (function () {
- 'use strict';
- // 預設快捷鍵
- const DEFAULT_SHORTCUT = 'S';
- // 預設連拍間隔(毫秒)
- const DEFAULT_INTERVAL = 1000;
- // 最小連拍間隔(毫秒)
- const MIN_INTERVAL = 100;
- // 多語系字典
- const i18n = {
- EN: {
- langSwitch: 'LANG EN',
- setKey: key => `Set Shortcut Key (Current: ${key})`,
- setInterval: ms => `Set Burst Interval (Current: ${ms}ms)`,
- inputKey: 'Enter a new shortcut key (one character):',
- inputInterval: 'Enter new burst interval in ms (min: 100):',
- invalidInterval: 'Invalid input. Must be ≥ 100.'
- },
- ZH: {
- langSwitch: '語言 中文',
- setKey: key => `設定快捷鍵(目前:${key})`,
- setInterval: ms => `設定連拍間隔(目前:${ms}ms)`,
- inputKey: '請輸入新的截圖快捷鍵(單一字母):',
- inputInterval: '請輸入新的連拍間隔(單位:毫秒,最小值:100):',
- invalidInterval: '請輸入一個不小於 100 的有效數字。'
- }
- };
- // 取得目前設定(語言、快捷鍵、連拍間隔)
- function getSettings() {
- return {
- lang: GM_getValue('lang', 'EN'),
- shortcutKey: GM_getValue('screenshotKey', DEFAULT_SHORTCUT),
- interval: parseInt(GM_getValue('burstInterval', DEFAULT_INTERVAL), 10)
- };
- }
- // 產生檔名:影片標題_小時_分鐘_秒_毫秒_解析度.png
- function generateFilename(video, canvas) {
- // 補零用
- const pad = (n, len = 2) => n.toString().padStart(len, '0');
- const time = video.currentTime;
- const h = pad(Math.floor(time / 3600));
- const m = pad(Math.floor((time % 3600) / 60));
- const s = pad(Math.floor(time % 60));
- const ms = pad(Math.floor((time % 1) * 1000), 3);
- // 取得網頁標題並移除非法字元
- const rawTitle = document.title;
- const cleanedTitle = rawTitle.replace(/[\s\\/:*?"<>|]/g, '_');
- // 解析度
- const resolution = `${canvas.width}x${canvas.height}`;
- // 修改命名規則:影片標題_小時_分鐘_秒_毫秒_解析度
- return `${cleanedTitle}_${h}_${m}_${s}_${ms}_${resolution}.png`;
- }
- // 截圖主程式
- function captureScreenshot() {
- const video = document.querySelector('video');
- // 若找不到影片或影片未載入完成則不執行
- if (!video || video.readyState < 2) return;
- // 建立 canvas 並繪製當前影像
- 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 filename = generateFilename(video, canvas);
- // 轉成 blob 並觸發下載
- canvas.toBlob(blob => {
- const a = document.createElement('a');
- a.href = URL.createObjectURL(blob);
- a.download = filename;
- a.click();
- // 延遲釋放 blob,避免尚未下載即釋放
- setTimeout(() => URL.revokeObjectURL(a.href), 1000);
- }, 'image/png');
- }
- // 綁定快捷鍵與連拍事件
- (function bindHotkeys() {
- let isPressing = false; // 是否正在按壓
- let burstTimer = null; // 連拍計時器
- window.addEventListener('keydown', e => {
- const { shortcutKey, interval } = getSettings();
- // 按下自訂快捷鍵且未重複觸發時
- if (e.key.toUpperCase() === shortcutKey.toUpperCase() && !isPressing) {
- isPressing = true;
- captureScreenshot();
- burstTimer = setInterval(captureScreenshot, interval);
- }
- });
- window.addEventListener('keyup', e => {
- const { shortcutKey } = getSettings();
- // 放開自訂快捷鍵時停止連拍
- if (e.key.toUpperCase() === shortcutKey.toUpperCase()) {
- isPressing = false;
- if (burstTimer) clearInterval(burstTimer);
- }
- });
- })();
- // 註冊油猴右上角選單
- (function registerMenu() {
- // 動態取得目前語系與設定
- function t() {
- const { lang, shortcutKey, interval } = getSettings();
- return { ...i18n[lang], shortcutKey, interval, lang };
- }
- // 設定快捷鍵
- GM_registerMenuCommand(t().setKey(t().shortcutKey), () => {
- const input = prompt(t().inputKey, t().shortcutKey);
- // 僅接受單一字元
- if (input && input.length === 1) {
- GM_setValue('screenshotKey', input.toUpperCase());
- location.reload(); // 直接重新整理,不跳提示
- }
- });
- // 設定連拍間隔
- GM_registerMenuCommand(t().setInterval(t().interval), () => {
- const input = prompt(t().inputInterval, t().interval);
- const newVal = parseInt(input, 10);
- if (!isNaN(newVal) && newVal >= MIN_INTERVAL) {
- GM_setValue('burstInterval', newVal);
- location.reload(); // 直接重新整理,不跳提示
- } else {
- alert(t().invalidInterval); // 僅錯誤時提示
- }
- });
- // 語言切換
- GM_registerMenuCommand(t().langSwitch, () => {
- const newLang = t().lang === 'EN' ? 'ZH' : 'EN';
- GM_setValue('lang', newLang);
- location.reload();
- });
- })();
- })();