Skip to content

Instantly share code, notes, and snippets.

@nemokaul
Created June 27, 2024 22:16
Show Gist options
  • Save nemokaul/9d4c054d9116895a0fdf5fb7adc7e87f to your computer and use it in GitHub Desktop.
Save nemokaul/9d4c054d9116895a0fdf5fb7adc7e87f to your computer and use it in GitHub Desktop.
Capture video screenshots and save to clipboard or download with timestamp and filename. `Alt+'` - Copy to Clipboard. `Alt + /` - Save as File.
// ==UserScript==
// @name Video Screenshot Tool
// @namespace nemokaul
// @version 1.0
// @description Capture video screenshots and save to clipboard or download with timestamp and filename.
// @license MIT
// @author Nemo Kaul
// @match http://*/*
// @match https://*/*
// @grant none
// @downloadURL https://gist.github.com/nemokaul/9d4c054d9116895a0fdf5fb7adc7e87f/raw/8e64171856da5aaa92eeec6839fbce5925d51c1b/videosnip.user.js
// @updateURL https://gist.github.com/nemokaul/9d4c054d9116895a0fdf5fb7adc7e87f/raw/8e64171856da5aaa92eeec6839fbce5925d51c1b/videosnip.user.js
// ==/UserScript==
(function() {
'use strict';
let disableWebsiteShortcuts = false;
// Block shortcut keys provided by the website
function disableShortcuts(e) {
if (disableWebsiteShortcuts) {
e.stopPropagation();
e.preventDefault();
}
}
// Listen for keyboard key events
document.addEventListener('keydown', function(e) {
// Alt + ' -- Copy to Clipboard
if (e.altKey && e.key === '\'') {
handleScreenshot(e, false);
}
// Alt + / -- Save the Screen
else if (e.altKey && e.key === '/') {
handleScreenshot(e, true);
}
});
function handleScreenshot(e, shouldDownload) {
e.preventDefault();
disableWebsiteShortcuts = true;
var video = document.querySelector('video');
if (video) {
var currentTime = getCurrentTime();
var canvas = document.createElement('canvas');
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
canvas.getContext('2d').drawImage(video, 0, 0, canvas.width, canvas.height);
canvas.toBlob(function(blob) {
if (shouldDownload) {
var url = URL.createObjectURL(blob);
var filename = getFilename(currentTime, video);
download(url, filename);
URL.revokeObjectURL(url);
} else {
setClipboard(blob).then(() => {
showMessage('success-message', 'Copied frame to clipboard!');
}).catch(() => {
showMessage('error-message', 'Failed to copy frame to clipboard!');
});
}
}, 'image/png', 0.99);
}
disableWebsiteShortcuts = false;
}
// Enable or disable the shortcut keys that come with the website
window.addEventListener('keydown', disableShortcuts, false);
// Get the video file name
function getFilename(currentTime, videoElement) {
var videoNameElement = document.querySelector('div.vp-video-page-card span.is-playing.vp-video-page-card__video-name,div.frame-main div.video-title span.video-title-left');
var originalFilename = videoNameElement ? videoNameElement.innerText.trim() : '';
if (!originalFilename) {
var titleElement = document.querySelector('head > title');
originalFilename = titleElement ? titleElement.innerText.trim() : '';
}
if (videoNameElement || titleElement) {
originalFilename = originalFilename.replace(/[\-|\|][^.]+$/, "");
}
const currentTimeStr = `${Math.floor(currentTime / 60)}\:${(currentTime % 60).toFixed(0)}`;
var newFilename = "screenshot_" + getCurrentDate() + "_frame_" + currentTimeStr + "_" + originalFilename + ".png";
return newFilename || 'screenshot';
}
// Get the current full date and time in the format of yyyy-MM-dd_HH-mm-ss
function getCurrentDate() {
var date = new Date();
var year = date.getFullYear();
var month = ('0' + (date.getMonth() + 1)).slice(-2);
var day = ('0' + date.getDate()).slice(-2);
var hours = ('0' + date.getHours()).slice(-2);
var minutes = ('0' + date.getMinutes()).slice(-2);
var seconds = ('0' + date.getSeconds()).slice(-2);
return year + "-" + month + "-" + day + "_" + hours + "-" + minutes + "-" + seconds;
}
function getCurrentTime() {
var timeElements = document.querySelectorAll("[class*='current' i][class*='time' i],[class*='cur' i][class*='time' i],[class*='vjs'][class*='time'], *[class*='display'], *[class*='tooltip'], *[class*='playtime'], .hv_time span:first-child");
var currentTime = null;
for (var i = 0; i < timeElements.length; i++) {
var timeStr = timeElements[i].textContent.trim();
if (/^\d+:\d+$/.test(timeStr)) {
var minutes = parseInt(timeStr.split(":")[0], 10);
var seconds = parseInt(timeStr.split(":")[1], 10);
currentTime = minutes * 60 + seconds;
} else if (/^\d+:\d+:\d+$/.test(timeStr)) {
var hours = parseInt(timeStr.split(":")[0], 10);
minutes = parseInt(timeStr.split(":")[1], 10);
seconds = parseInt(timeStr.split(":")[2], 10);
currentTime = hours * 3600 + minutes * 60 + seconds;
}
if (currentTime !== null) {
break;
}
}
return currentTime;
}
// Function to save the image. It simulates clicking a link and opens a save window
function download(href, name) {
var save_link = document.createElement('a');
save_link.href = href;
save_link.download = name;
var event = document.createEvent('MouseEvents');
event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, 0, null);
save_link.dispatchEvent(event);
}
// Function to copy to clipboard
function setClipboard(blob) {
return navigator.clipboard.write([
new ClipboardItem({
'image/png': blob
})
]);
}
// Function to show messages
function showMessage(id, message) {
var messageElement = document.createElement('div');
messageElement.id = id;
messageElement.className = id;
messageElement.textContent = message;
messageElement.style.position = 'fixed';
messageElement.style.bottom = '10px';
messageElement.style.left = '30px';
messageElement.style.padding = '20px';
messageElement.style.borderRadius = '5px';
messageElement.style.color = 'white';
messageElement.style.fontSize = '16px';
messageElement.style.fontFamily = 'Arial, sans-serif';
messageElement.style.zIndex = '1000';
if (id === 'success-message') {
messageElement.style.backgroundColor = 'green';
} else if (id === 'error-message') {
messageElement.style.backgroundColor = 'red';
}
document.body.appendChild(messageElement);
setTimeout(() => {
document.body.removeChild(messageElement);
}, 3000);
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment