Video Element Rate Controller Re-dux

Add keyboard shortcuts that will increase/decrease the playback rate for video elements.

当前为 2024-12-04 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Video Element Rate Controller Re-dux
  3. // @namespace https://github.com/mirnhoj/video-element-playbackrate-setter
  4. // @version 2.5
  5. // @description Add keyboard shortcuts that will increase/decrease the playback rate for video elements.
  6. // @include http*://*.youtube.com/*
  7. // @include http*://*.gfycat.com/*
  8. // @include http*://*.vimeo.com/*
  9. // @include https://www.facebook.com/video.php*
  10. // @include https://www.facebook.com/*/videos/*
  11. // @include https://www.kickstarter.com/*
  12. // @grant GM_registerMenuCommand
  13.  
  14. // ==/UserScript==
  15. /* jshint esversion: 6 */
  16. //
  17. // if you want to extend the functionality of this script to other sites
  18. // besides youtube, add additional @include keys to the metadata block or to
  19. // the "User includes" or "User matches" sections in the Settings.
  20. //
  21. // if you want to change the default playback rate from 1x, change the line
  22. // "var currentPlaybackRate = 1;" to equal something other than 1, like 1.3 to
  23. // have all videos start playing at an increased speed, or 0.7 to have all
  24. // videos start playing at a decreased speed.
  25. //
  26. // if you want change the granularity of the playback rate adjustment, change
  27. // the line "var speedStep = 0.1;" to equal something other than 0.1, like 0.01
  28. // for more granular adjustments, or 0.25 for less granular adjustments.
  29.  
  30. // These values are the default values for initialization
  31. const defaults = {
  32. speedStep: 0.1,
  33. displayTimeMilliSec: 1500
  34. };
  35.  
  36. // script variables
  37. let timeoutID = null;
  38. let showValuesOnVideo = true; // true to show new value on the video
  39. let keyIncreaseSpeed = ']';
  40. let keyReduceSpeed = '[';
  41. let keyResetSpeed = '\\';
  42. const infoboxId = 'playbackrate-indicator';
  43.  
  44. function getVal(variable) {
  45. let value;
  46. let storage = (localStorage || (sessionStorage ||
  47. (window.content.localStorage ? window.content.localStorage : null)));
  48. try {
  49. switch (variable) {
  50. case 'speedStep':
  51. value = storage.getItem('VERCRspeedStep');
  52. return Number(value);
  53. case 'displayTimeMilliSec':
  54. value = storage.getItem('VERCRdisplayTimeMS');
  55. return Number(value);
  56. case 'keyIncreaseSpeed':
  57. return value;
  58. case 'keyReduceSpeed':
  59. return value;
  60. case 'keyResetSpeed':
  61. return value;
  62. default:
  63. return null;
  64. }
  65. } catch (e) {
  66. if (e.name === 'NS_ERROR_FILE_CORRUPTED') {
  67. storage = sessionStorage || null; // set the new storage if fails
  68. storage.setItem('VERCRspeedStep', defaults.speedStep);
  69. storage.setItem('VERCRdisplayTimeMS', defaults.displayTimeMilliSec);
  70. }
  71. }
  72. }
  73.  
  74. function setVal(variable, value) {
  75. let storage = (localStorage || (sessionStorage ||
  76. (window.content.localStorage ? window.content.localStorage : null)));
  77. try {
  78. switch (variable) {
  79. case 'speedStep':
  80. storage.setItem('VERCRspeedStep', Number(value));
  81. return value;
  82. case 'displayTimeMilliSec':
  83. storage.setItem('VERCRdisplayTimeMS', Number(value));
  84. return value;
  85. default:
  86. return null;
  87. }
  88. } catch (e) {
  89. if (e.name === 'NS_ERROR_FILE_CORRUPTED') {
  90. storage = sessionStorage || null; // set the new storage if fails
  91. storage.setItem('VERCRspeedStep', defaults.speedStep);
  92. storage.setItem('VERCRdisplayTimeMS', defaults.displayTimeMilliSec);
  93. }
  94. }
  95. }
  96.  
  97. function GMsetup() {
  98. if (GM_registerMenuCommand) {
  99. GM_registerMenuCommand('Set adjustment rate', () => {
  100. const curEntry = getVal('speedStep');
  101. let speedStep = prompt('New adjustment rate:\n(e.g., 0.1 = 10% faster)', curEntry);
  102. if (speedStep !== null) {
  103. while (isNaN(speedStep)) {
  104. speedStep = prompt('Please input a valid number!\n\nNew adjustment rate:\n(e.g., 0.1 = 10% faster)', curEntry);
  105. }
  106. setVal('speedStep', speedStep);
  107. }
  108. });
  109. // GM_registerMenuCommand('Video Rate Re-dux: Set keyboard shortcuts', () => {
  110. // const curEntry = `${getVal('keyIncreaseSpeed')}, ${getVal('keyReduceSpeed')}, ${getVal('keyResetSpeed')}`;
  111. // // W.I.P.
  112. // });
  113. GM_registerMenuCommand('Set display timeout', () => {
  114. const curEntry = getVal('displayTimeMilliSec');
  115. let displayTimeMilliSec = prompt('New display timeout length (in milliseconds):', curEntry);
  116. if (displayTimeMilliSec !== null) {
  117. while (isNaN(displayTimeMilliSec)) {
  118. displayTimeMilliSec = prompt('Please input a valid number!\n\nNew display timeout length (in milliseconds):', curEntry);
  119. }
  120. setVal('displayTimeMilliSec', displayTimeMilliSec);
  121. }
  122. });
  123. }
  124. }
  125.  
  126. function init() {
  127. let VERCRspeedStep = localStorage.getItem('VERCRspeedStep');
  128. let VERCRdisplayTimeMS = localStorage.getItem('VERCRdisplayTimeMS');
  129. if (!VERCRspeedStep) {
  130. VERCRspeedStep = defaults.speedStep;
  131. localStorage.setItem('VERCRspeedStep', Number(VERCRspeedStep));
  132. }
  133. if (!VERCRdisplayTimeMS) {
  134. VERCRdisplayTimeMS = defaults.displayTimeMilliSec;
  135. localStorage.setItem('VERCRdisplayTimeMS', Number(VERCRdisplayTimeMS));
  136. }
  137. }
  138.  
  139. function getInfobox(videoElement) {
  140. if (!videoElement) return;
  141. let infoboxEl = document.getElementById(infoboxId);
  142. if (!infoboxEl) {
  143. // create and add infobox to dom if it doesn't already exist.
  144. infoboxEl = document.createElement('h1');
  145. infoboxEl.setAttribute('id', infoboxId);
  146. infoboxEl.style.position = 'absolute';
  147. infoboxEl.style.top = '10%';
  148. infoboxEl.style.right = '10%';
  149. infoboxEl.style.color = 'rgba(255, 0, 0, 1)';
  150. infoboxEl.style.zIndex = '99999'; // ensures that it shows above other elements.
  151. infoboxEl.style.visibility = 'hidden';
  152. infoboxEl.style.marginTop = '3%';
  153. }
  154. if (videoElement.parentElement !== infoboxEl.parentElement)
  155. videoElement.parentElement.appendChild(infoboxEl);
  156. return infoboxEl;
  157. }
  158.  
  159. // update rate indicator.
  160. function showInfobox(videoElement, rate) {
  161. const infobox = getInfobox(videoElement);
  162. infobox.innerHTML = `${rate}x`;
  163. // show infobox
  164. infobox.style.visibility = 'visible';
  165. // clear out any previous timers and have the infobox hide after the pre-set time period
  166. window.clearTimeout(timeoutID);
  167. timeoutID = window.setTimeout(() => {
  168. infobox.style.visibility = 'hidden';
  169. }, getVal('displayTimeMilliSec'));
  170. }
  171.  
  172. function setPlaybackRate(videoElement, rate, shouldShowInfobox) {
  173. // grab the video elements and set their playback rate.
  174. if (!videoElement) return;
  175. videoElement.playbackRate = rate;
  176. if (shouldShowInfobox) showInfobox(videoElement, rate);
  177. }
  178.  
  179. // mimic vlc keyboard shortcuts
  180. function addKeyListener() {
  181. window.addEventListener('keydown', (event) => {
  182. let videoElement, modification = 0;
  183. switch (event.key) {
  184. case keyReduceSpeed:
  185. modification = -1;
  186. break;
  187. case keyIncreaseSpeed:
  188. modification = 1;
  189. break;
  190. case keyResetSpeed:
  191. videoElement = document.getElementsByTagName('video')[0];
  192. setPlaybackRate(videoElement, 1, showValuesOnVideo);
  193. return;
  194. default:
  195. return;
  196. }
  197. videoElement = document.getElementsByTagName('video')[0];
  198. if (!videoElement) return;
  199. const currentPlaybackRate = videoElement.playbackRate;
  200. const speedStep = getVal('speedStep');
  201. const newPlaybackRate = parseFloat((currentPlaybackRate + (speedStep * modification)).toFixed(3));
  202. // console.log(`Raising "playbackRate" from ${currentPlaybackRate} to ${newPlaybackRate}`);
  203. setPlaybackRate(videoElement, newPlaybackRate, showValuesOnVideo);
  204. });
  205. }
  206.  
  207. function onReady() { addKeyListener(); }
  208.  
  209. function main() {
  210. init();
  211. GMsetup();
  212. if (document.readyState !== 'loading') {
  213. onReady(); // Or setTimeout(onReady, 0); if you want it consistently async
  214. } else {
  215. document.addEventListener('DOMContentLoaded', onReady);
  216. }
  217. }
  218.  
  219. main();