您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
"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();
- })();