Video Element Rate Controller Re-dux

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

当前为 2023-06-01 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Video Element Rate Controller Re-dux
  3. // @namespace https://github.com/mirnhoj/video-element-playbackrate-setter
  4. // @version 2.3
  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.
  19. //
  20. // if you want to change the default playback rate from 1x, change the line
  21. // "var currentPlaybackRate = 1;" to equal something other than 1, like 1.3 to
  22. // have all videos start playing at an increased speed, or 0.7 to have all
  23. // videos start playing at a decreased speed.
  24. //
  25. // if you want change the granularity of the playback rate adjustment, change
  26. // the line "var speedStep = 0.1;" to equal something other than 0.1, like 0.01
  27. // for more granular adjustments, or 0.25 for less granular adjustments.
  28.  
  29.  
  30. // These values are the default values for initialization
  31. let speedStep = 0.1;
  32. let displayTimeMilliSec = 1500;
  33.  
  34. let timeoutID = null;
  35. const infobox = document.createElement('h1');
  36. let showValuesOnVideo = true; // true to show new value on the video
  37. let keyIncreaseSpeed = ']';
  38. let keyReduceSpeed = '[';
  39. let keyResetSpeed = '\\';
  40.  
  41. function getVal(variable) {
  42. let value;
  43. let storage = (localStorage || (sessionStorage ||
  44. (window.content.localStorage ? window.content.localStorage : null)));
  45. try {
  46. switch (variable) {
  47. case 'speedStep':
  48. value = storage.getItem('VERCRspeedStep');
  49. return Number(value);
  50. case 'displayTimeMilliSec':
  51. value = storage.getItem('VERCRdisplayTimeMS');
  52. return Number(value);
  53. case 'keyIncreaseSpeed':
  54. return value;
  55. case 'keyReduceSpeed':
  56. return value;
  57. case 'keyResetSpeed':
  58. return value;
  59. default:
  60. return null;
  61. }
  62. } catch (e) {
  63. if (e.name === 'NS_ERROR_FILE_CORRUPTED') {
  64. storage = sessionStorage || null; // set the new storage if fails
  65. storage.setItem('VERCRspeedStep', speedStep);
  66. storage.setItem('VERCRdisplayTimeMS', displayTimeMilliSec);
  67. }
  68. }
  69. //console.log('Variable "' + variable + '" is ' + value);
  70. }
  71.  
  72. function setVal(variable, value) {
  73. let storage = (localStorage || (sessionStorage ||
  74. (window.content.localStorage ? window.content.localStorage : null)));
  75. try {
  76. switch (variable) {
  77. case 'speedStep':
  78. storage.setItem('VERCRspeedStep', Number(value));
  79. console.log(`Setting "${variable}" to ${value}`);
  80. return value;
  81. case 'displayTimeMilliSec':
  82. storage.setItem('VERCRdisplayTimeMS', Number(value));
  83. console.log(`Setting "${variable}" to ${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', speedStep);
  92. storage.setItem('VERCRdisplayTimeMS', displayTimeMilliSec);
  93. }
  94. }
  95. }
  96.  
  97. function GMsetup() {
  98. if (GM_registerMenuCommand) {
  99. GM_registerMenuCommand('Set adjustment rate', () => {
  100. const curEntry = getVal('speedStep');
  101. 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. 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 = speedStep;
  131. localStorage.setItem('VERCRspeedStep', Number(VERCRspeedStep));
  132. }
  133. if (!VERCRdisplayTimeMS) {
  134. VERCRdisplayTimeMS = displayTimeMilliSec;
  135. localStorage.setItem('VERCRdisplayTimeMS', Number(VERCRdisplayTimeMS));
  136. }
  137. }
  138.  
  139. function showInfobox(rate) {
  140. // update rate indicator.
  141. infobox.innerHTML = `${rate}x`;
  142. // show infobox
  143. infobox.style.visibility = 'visible';
  144. // clear out any previous timers and have the infobox hide after the pre-set time period
  145. window.clearTimeout(timeoutID);
  146. timeoutID = window.setTimeout(() => {
  147. infobox.style.visibility = 'hidden';
  148. }, getVal('displayTimeMilliSec'));
  149. }
  150.  
  151. function setPlaybackRate(rate, shouldShowInfobox) {
  152. // grab the video elements and set their playback rate.
  153. const videoElement = document.getElementsByTagName('video')[0];
  154. videoElement.playbackRate = rate;
  155. // add infobox to dom if it doesn't already exist.
  156. if (videoElement && !document.getElementById('playbackrate-indicator')) {
  157. videoElement.parentElement.appendChild(infobox);
  158. }
  159. if (shouldShowInfobox) {
  160. showInfobox(rate);
  161.  
  162. }
  163. }
  164.  
  165. // mimic vlc keyboard shortcuts
  166. function addKeyListener() {
  167. window.addEventListener('keydown', (event) => {
  168. const key = event.key;
  169. const videoElement = document.getElementsByTagName('video')[0];
  170. let currentPlaybackRate = videoElement.playbackRate;
  171. speedStep = getVal('speedStep');
  172. if (key === keyReduceSpeed) {
  173. currentPlaybackRate = parseFloat((currentPlaybackRate - speedStep).toFixed(3));
  174. console.log(`Raising "currentPlaybackRate" to ${currentPlaybackRate}`);
  175. setPlaybackRate(currentPlaybackRate, showValuesOnVideo);
  176. } else if (key === keyIncreaseSpeed) {
  177. currentPlaybackRate = parseFloat((currentPlaybackRate + speedStep).toFixed(3));
  178. console.log(`Lowering "currentPlaybackRate" to ${currentPlaybackRate}`);
  179. setPlaybackRate(currentPlaybackRate, showValuesOnVideo);
  180. } else if (key === keyResetSpeed) {
  181. currentPlaybackRate = 1;
  182. setPlaybackRate(currentPlaybackRate, showValuesOnVideo);
  183. }
  184. });
  185. }
  186.  
  187. function onReady() {
  188. addKeyListener();
  189. }
  190.  
  191. function wait(time) {
  192. return new Promise((resolve) => {
  193. setTimeout(() => {
  194. resolve();
  195. }, time);
  196. });
  197. }
  198.  
  199. function main() {
  200. init();
  201. GMsetup();
  202. infobox.setAttribute('id', 'playbackrate-indicator');
  203. infobox.style.position = 'absolute';
  204. infobox.style.top = '10%';
  205. infobox.style.right = '10%';
  206. infobox.style.color = 'rgba(255, 0, 0, 1)';
  207. infobox.style.zIndex = '99999'; // ensures that it shows above other elements.
  208. infobox.style.visibility = 'hidden';
  209. infobox.style.marginTop = '3%';
  210. if (document.readyState !== 'loading') {
  211. onReady(); // Or setTimeout(onReady, 0); if you want it consistently async
  212. } else {
  213. document.addEventListener('DOMContentLoaded', onReady);
  214. }
  215. }
  216.  
  217. main();