"S"キーを押すだけでYouTubeのスクリーンショットを保存
当前为
// ==UserScript==
// @name CapTube
// @namespace https://github.com/segabito/
// @description "S"キーを押すだけでYouTubeのスクリーンショットを保存
// @include https://www.youtube.com/*
// @include https://youtube.com/*
// @version 0.0.1
// @grant none
// @license public domain
// @noframes
// ==/UserScript==
(function() {
let previewContainer = null;
const addStyle = function(styles, id) {
var elm = document.createElement('style');
elm.type = 'text/css';
if (id) { elm.id = id; }
var text = styles.toString();
text = document.createTextNode(text);
elm.appendChild(text);
var head = document.getElementsByTagName('head');
head = head[0];
head.appendChild(elm);
return elm;
};
const __css__ = (`
#CapTubePreviewContainer {
position: fixed;
padding: 8px;
width: 90%;
bottom: 100px;
left: 5%;
z-index: 10000;
pointer-events: none;
transform: translateZ(0);
background: rgba(192, 192, 192, 0.4);
/*border: 2px solid #ccc;*/
-webkit-user-select: none;
user-select: none;
}
#CapTubePreviewContainer:empty {
display: none;
}
#CapTubePreviewContainer canvas {
display: inline-block;
width: 128px;
margin-right: 16px;
margin-bottom: 16px;
box-shadow: 4px 4px 4px #000;
transition:
0.4s opacity ease,
0.4s width ease 0.5s,
0.4s margin-right ease 0.5s;
}
#CapTubePreviewContainer canvas.is-removing {
opacity: 0;
margin-right: 0;
width: 0;
}
`).trim();
addStyle(__css__);
const getVideoId = function() {
var id = '';
location.search.substring(1).split('&').forEach(function(item){
if (item.split('=')[0] === 'v') { id = item.split('=')[1]; }
});
return id;
};
const toSafeName = function(text) {
text = text.trim()
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/\?/g, '?')
.replace(/:/g, ':')
.replace(/\|/g, '|')
.replace(/\//g, '/')
.replace(/\\/g, '¥')
.replace(/"/g, '”')
.replace(/\./g, '.')
;
return text;
};
const getVideoTitle = function() {
var videoId = getVideoId();
var title = document.querySelector('.watch-title');
var authorName = toSafeName(document.querySelector('.yt-user-info a').text);
var titleText = toSafeName(title.textContent);
titleText = titleText + ' - by ' + authorName + ' (v=' + videoId + ')';
return titleText;
};
const createCanvasFromVideo = function(video) {
const width = video.videoWidth;
const height = video.videoHeight;
const canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
const context = canvas.getContext('2d');
context.drawImage(video, 0, 0);
return canvas;
};
const getFileName = function(video) {
const title = getVideoTitle();
const currentTime = video.currentTime;
const min = Math.floor(currentTime / 60);
const sec = (currentTime % 60 + 100).toString().substr(1, 6);
const time = `${min}_${sec}`;
return `${title}@${time}.png`;
};
const createBlobLinkElement = function(canvas, fileName) {
const dataUrl = canvas.toDataURL('image/png');
const bin = atob(dataUrl.split(',')[1]);
const buf = new Uint8Array(bin.length);
for (let i = 0, len = buf.length; i < len; i++) { buf[i] = bin.charCodeAt(i); }
const blob = new Blob([buf.buffer], {type: 'image/png'});
const url = window.URL.createObjectURL(blob);
const link = document.createElement('a');
link.setAttribute('download', fileName);
link.setAttribute('target', '_blank');
link.setAttribute('href', url);
return link;
};
const saveScreenShot = function() {
const video = document.querySelector('.html5-main-video');
if (!video) { return; }
const canvas = createCanvasFromVideo(video);
const fileName = getFileName(video);
const link = createBlobLinkElement(canvas, fileName);
if (previewContainer) {
previewContainer.appendChild(canvas);
setTimeout(function() {
canvas.classList.add('is-removing');
setTimeout(function() { canvas.remove(); }, 1000);
}, 1500);
}
document.body.appendChild(link);
link.click();
setTimeout(function() { link.remove(); }, 1000);
};
const setPlaybackRate = function(v) {
const video = document.querySelector('.html5-main-video');
if (!video) { return; }
video.playbackRate = v;
};
const togglePlay = function() {
const video = document.querySelector('.html5-main-video');
if (!video) { return; }
if (video.paused) {
video.play();
} else {
video.pause();
}
};
const seekBy = function(v) {
const video = document.querySelector('.html5-main-video');
if (!video) { return; }
const ct = Math.max(video.currentTime + v, 0);
video.currentTime = ct;
};
let isVerySlow = false;
const onKeyDown = (e) => {
const key = e.key.toLowerCase();
switch (key) {
case 'd':
setPlaybackRate(0.1);
isVerySlow = true;
break;
case 's':
saveScreenShot();
break;
}
};
const onKeyUp = (e) => {
console.log('onKeyUp', e);
const key = e.key.toLowerCase();
switch (key) {
case 'd':
setPlaybackRate(1);
isVerySlow = false;
break;
}
};
const onKeyPress = (e) => {
const key = e.key.toLowerCase();
switch (key) {
case 'w':
togglePlay();
break;
case 'a':
seekBy(isVerySlow ? -0.5 : -5);
break;
}
};
const initDom = function() {
const div = document.createElement('div');
div.id = 'CapTubePreviewContainer';
document.body.appendChild(div);
previewContainer = div;
};
const initialize = function() {
initDom();
window.addEventListener('keydown', onKeyDown);
window.addEventListener('keyup', onKeyUp);
window.addEventListener('keypress', onKeyPress);
};
initialize();
})();