YouTube screenshot

Adds a screenshot button to YouTube video page

  1. // ==UserScript==
  2. // @name YouTube screenshot
  3. // @namespace https://github.com/qiwichupa/userscripts/blob/master/youtube_screenshot__userscript
  4. // @homepage https://greasyfork.org/ru/scripts/455155-youtube-screenshot
  5. // @author qiwichupa
  6. // @version 20221120.2147
  7. // @description Adds a screenshot button to YouTube video page
  8. // @match *://www.youtube.com/*
  9. // @match *://youtube.com/*
  10. // @run-at document-end
  11. // @require http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js
  12. // @grant none
  13. // @license GNU General Public License v2.0 or later
  14. // ==/UserScript==
  15. this.$ = this.jQuery = jQuery.noConflict(true);
  16. $(function () {
  17. "use strict";
  18. addScreenshotSupport();
  19. document.body.addEventListener("yt-navigate-finish", function (event) {
  20. addScreenshotSupport();
  21. });
  22. function addScreenshotSupport(firstLoad) {
  23. if (isVideoPage()) {
  24. waitForElement("upload-info", function () {
  25. addScreenshotButton();
  26. }, 330);
  27. }
  28. }
  29. function waitForElement(elementId, callbackFunction, intervalLength = 330) {
  30. var waitCount = 15000 / intervalLength; // wait 15 seconds maximum
  31. var wait = setInterval(function () {
  32. waitCount--;
  33. if ($("#" + elementId).length > 0) {
  34. callbackFunction();
  35. clearInterval(wait);
  36. } else if (waitCount <= 0) {
  37. console.log("YouTube RSS Feed UserScript - wait for element \"#" + elementId +
  38. "\" failed! Time limit (15 seconds) exceeded.");
  39. clearInterval(wait);
  40. }
  41. }, intervalLength);
  42. }
  43. function isVideoPage() {
  44. return document.URL.indexOf("/watch") !== -1 && document.URL.indexOf("v=") !== -1;
  45. }
  46. function addScreenshotButton() {
  47. if ($("#ScreenshotButton").length > 0) {
  48. $("#ScreenshotButton").remove();
  49. }
  50. $("#subscribe-button")
  51. .css({
  52. "display": "flex",
  53. "flex-flow": "nowrap",
  54. "height": "37px"
  55. })
  56. .prepend(styleOfScreenshotButton());
  57. $("#ScreenshotButton").click (makeScreenshot);
  58. }
  59. function styleOfScreenshotButton() {
  60. return $('<button id="ScreenshotButton" onclick="makeScreenshot()">SHOT</button>')
  61. .css({
  62. "background-color": "#fd9b12",
  63. "border-radius": "3px",
  64. "padding": "10px 16px",
  65. "color": "#ffffff",
  66. "font-size": "14px",
  67. "text-decoration": "none",
  68. "text-transform": "uppercase",
  69. "margin-right": "5px"
  70. });
  71. }
  72. function makeScreenshot () {
  73. // original code: https://github.com/ReeganExE/youtube-screenshot
  74. // and https://github.com/ParticleCore/Iridium
  75. var screen_shot_container;
  76. var canvas;
  77. var video;
  78. var aspect_ratio;
  79. var canvas_context;
  80. var aspect_ratio;
  81. var canvas_width;
  82. var canvas_height;
  83. var base64ImageData;
  84. var filename;
  85. var a;
  86. var img;
  87. if (!(screen_shot_container = document.getElementById("us-screen-shot-container"))) {
  88. screen_shot_container = document.createElement("template");
  89. screen_shot_container.innerHTML =
  90. "<div id='us-screen-shot-container'>" +
  91. " <a target='_blank' download data-locale='title|screen_shot_title'>" +
  92. " <canvas></canvas>" +
  93. " </a>" +
  94. "</div>";
  95. screen_shot_container = screen_shot_container.content;
  96. }
  97. canvas = screen_shot_container.querySelector("canvas");
  98. video = document.querySelector('video');
  99. aspect_ratio = video.videoWidth / video.videoHeight;
  100. // Change the size here
  101. canvas_context = canvas.getContext("2d");
  102. aspect_ratio = video.videoWidth / video.videoHeight;
  103. canvas_width = video.videoWidth;
  104. canvas_height = parseInt(canvas_width / aspect_ratio, 10);
  105. canvas.width = canvas_width;
  106. canvas.height = canvas_height;
  107. canvas_context.drawImage(video, 0, 0, canvas_width, canvas_height);
  108. // Won't work on file:/// URLs. SecurityError: Tainted canvases may not be exported.
  109. base64ImageData = canvas.toDataURL('image/jpeg');
  110. filename = 'snap-' + canvas.width + 'x' + canvas.height + '-' + video.currentTime + '.jpg';
  111. // Wrap <img> in link to download image because
  112. // the context menu Save Image as... is blocked for security reasons
  113. a = document.createElement('a');
  114. a.download = filename;
  115. a.href = base64ImageData;
  116. img = document.createElement('img');
  117. img.src = base64ImageData;
  118. img.alt = filename;
  119. img.title = 'Click to save ' + filename;
  120. window.open().document.body.appendChild(a).appendChild(img);
  121. }
  122. });