Created
June 27, 2024 22:16
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==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