您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Takes a screenshot from a YouTube video in current quality, saves to the clipboard (Ctrl+Alt+Shift+Q) or a file (Ctrl+Alt+Shift+W).
// ==UserScript== // @name YouTube Screenshotter // @namespace https://www.youtube.com // @version 2025-09-06 // @description Takes a screenshot from a YouTube video in current quality, saves to the clipboard (Ctrl+Alt+Shift+Q) or a file (Ctrl+Alt+Shift+W). // @author CJMAXiK // @license MIT // @match https://www.youtube.com/watch* // @icon https://icons.duckduckgo.com/ip2/youtube.com.ico // @website https://gist.github.com/cjmaxik/6211f5381c98fbd55267623de4650032 // @grant none // ==/UserScript== // SETTINGS const slugifyTitle = false; const screenshotTitle = "channelName"; // channelName (default), videoTitle, videoId /** * @see https://byby.dev/js-slugify-string * @param {string} str */ function slugify(str) { if (!slugifyTitle) return str; return String(str) .normalize("NFKD") .replace(/[\u0300-\u036f]/g, "") .trim() .toLowerCase() .replace(/[^a-z0-9 -]/g, "") .replace(/\s+/g, "-") .replace(/-+/g, "-"); } /** * @param {Blob} blob */ const saveToClipboard = (blob) => { try { navigator.clipboard.write([ new ClipboardItem({ "image/png": blob, }), ]); console.log("Screenshot copied to the clipboard!"); } catch (err) { console.error("Clipboard is not accessible, saving to file instead", err); saveToFile(blob); } }; /** * @param {Blob} blob */ const saveToFile = (blob) => { try { const data = { videoTitle: document .querySelector("ytd-watch-metadata #title > h1 > yt-formatted-string") .getAttribute("title"), videoId: new URL(window.location.href).searchParams.get("v"), channelName: document.querySelector("ytd-channel-name #text > a") .textContent, }; const now = new Date(); const currentTime = `${now.toDateString()} ${now.toLocaleTimeString()}`; const titlePrefix = data[screenshotTitle] ?? "Screenshot"; const link = document.createElement("a"); link.href = URL.createObjectURL(blob); link.download = slugify(`${titlePrefix} - ${currentTime}`) + ".png"; link.click(); URL.revokeObjectURL(link.href); console.log("Screenshot saved as a file!"); } catch (err) { console.error("Save to file was unsuccessful", err); } }; /** * @param {boolean} shouldDownload */ const screenshot = (shouldDownload) => { const video = document.querySelector("video"); if (!video) throw new Error("Cannot find the video element, aborting..."); const canvas = document.createElement("canvas"); const context = canvas.getContext("2d"); canvas.width = video.videoWidth; canvas.height = video.videoHeight; context.drawImage(video, 0, 0, canvas.width, canvas.height); canvas.toBlob((blob) => { if (!blob) throw new Error("The blob is empty, aborting..."); shouldDownload ? saveToFile(blob) : saveToClipboard(blob); }); canvas.remove(); }; document.addEventListener("keydown", (e) => { // The shortcuts are: // - Ctrl+Alt+Shift+Q for clipboard // - Ctrl+Alt+Shift+W for file if (!e.ctrlKey || !e.altKey || !e.shiftKey) return; if (e.code !== "KeyQ" && e.code !== "KeyW") return; screenshot(e.code === "KeyW"); });