YouTube Screenshot Button

Adds a button to take a screenshot of the current video frame on YouTube.

  1. // ==UserScript==
  2. // @name YouTube Screenshot Button
  3. // @namespace https://criskkky.carrd.co/
  4. // @version 1.0.0
  5. // @description Adds a button to take a screenshot of the current video frame on YouTube.
  6. // @description:es Añade un botón para tomar una captura de pantalla del fotograma actual del vídeo en YouTube.
  7. // @description:pt Adiciona um botão para tirar uma captura de tela do fotograma atual do vídeo no YouTube.
  8. // @description:fr Ajoute un bouton pour prendre une capture d'écran de l'image vidéo actuelle sur YouTube.
  9. // @description:it Aggiunge un pulsante per scattare uno screenshot del fotogramma video corrente su YouTube.
  10. // @description:uk Додає кнопку для знімка поточного кадру відео на YouTube.
  11. // @description:ru Добавляет кнопку для снятия скриншота текущего кадра видео на YouTube.
  12. // @description:ro Adaugă un buton pentru a face un screenshot al cadrului video curent de pe YouTube.
  13.  
  14. // @author https://criskkky.carrd.co/
  15. // @supportURL https://github.com/criskkky/YT-SS-Button/issues
  16. // @icon https://raw.githubusercontent.com/criskkky/YT-SS-Button/main/static/icon.svg
  17. // @copyright https://github.com/criskkky/
  18. // @license https://github.com/criskkky/YT-SS-Button?tab=License-1-ov-file
  19.  
  20. // @grant none
  21. // @match *://*.youtube.com/*
  22. // ==/UserScript==
  23.  
  24. (function () {
  25. 'use strict';
  26.  
  27. let controls = null;
  28.  
  29. function addScreenshotButton() {
  30. if (!controls) {
  31. controls = document.querySelector('.ytp-right-controls');
  32. }
  33.  
  34. if (!controls || document.querySelector('.ytp-screenshot-button')) {
  35. return;
  36. }
  37.  
  38. const screenshotButton = document.createElement('button');
  39. screenshotButton.className = 'ytp-button ytp-screenshot-button';
  40. screenshotButton.setAttribute('title', 'Take screenshot');
  41. screenshotButton.style.position = 'relative';
  42. screenshotButton.style.bottom = '12px';
  43. screenshotButton.style.width = '44px';
  44.  
  45. const svgElement = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
  46. svgElement.setAttribute('viewBox', '0 0 487 487');
  47. svgElement.setAttribute('width', '24');
  48. svgElement.setAttribute('height', '24');
  49. svgElement.setAttribute('fill', '#ffffff');
  50.  
  51. const pathElement = document.createElementNS('http://www.w3.org/2000/svg', 'path');
  52. pathElement.setAttribute('d', 'M308.1,277.95c0,35.7-28.9,64.6-64.6,64.6s-64.6-28.9-64.6-64.6s28.9-64.6,64.6-64.6S308.1,242.25,308.1,277.95z M440.3,116.05c25.8,0,46.7,20.9,46.7,46.7v122.4v103.8c0,27.5-22.3,49.8-49.8,49.8H49.8c-27.5,0-49.8-22.3-49.8-49.8v-103.9 v-122.3l0,0c0-25.8,20.9-46.7,46.7-46.7h93.4l4.4-18.6c6.7-28.8,32.4-49.2,62-49.2h74.1c29.6,0,55.3,20.4,62,49.2l4.3,18.6H440.3z M97.4,183.45c0-12.9-10.5-23.4-23.4-23.4c-13,0-23.5,10.5-23.5,23.4s10.5,23.4,23.4,23.4C86.9,206.95,97.4,196.45,97.4,183.45z M358.7,277.95c0-63.6-51.6-115.2-115.2-115.2s-115.2,51.6-115.2,115.2s51.6,115.2,115.2,115.2S358.7,341.55,358.7,277.95z');
  53. svgElement.appendChild(pathElement);
  54. screenshotButton.appendChild(svgElement);
  55.  
  56. screenshotButton.addEventListener('click', () => {
  57. const video = document.querySelector('video');
  58. if (video) captureFrame(video);
  59. });
  60.  
  61. controls.insertBefore(screenshotButton, controls.firstChild);
  62. }
  63.  
  64. function captureFrame(video) {
  65. const canvas = document.createElement('canvas');
  66. canvas.width = video.videoWidth;
  67. canvas.height = video.videoHeight;
  68. const ctx = canvas.getContext('2d');
  69. ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
  70.  
  71. const videoTitle = document.title.replace(/\s-\sYouTube$/, '').trim();
  72. const filename = `${videoTitle}.png`;
  73.  
  74. const link = document.createElement('a');
  75. link.href = canvas.toDataURL('image/png');
  76. link.download = filename;
  77. link.click();
  78. }
  79.  
  80. function handleFullscreenChange() {
  81. const screenshotButton = document.querySelector('.ytp-screenshot-button');
  82. if (screenshotButton) {
  83. const isFullscreen = document.fullscreenElement || document.webkitFullscreenElement;
  84. screenshotButton.style.bottom = isFullscreen ? '15px' : '12px';
  85. }
  86. }
  87.  
  88. function initialize() {
  89. document.addEventListener('yt-navigate-finish', () => {
  90. if (window.location.href.includes('watch?v=')) {
  91. addScreenshotButton();
  92. }
  93. });
  94.  
  95. document.addEventListener('fullscreenchange', handleFullscreenChange);
  96.  
  97. // Initial setup
  98. if (window.location.href.includes('watch?v=')) {
  99. addScreenshotButton();
  100. }
  101. }
  102.  
  103. initialize();
  104. })();