Don't Change YouTube Speed on Long Click

Stops YouTube from changing video speed to 2x when you hold down the mouse button.

  1. // ==UserScript==
  2. // @name Don't Change YouTube Speed on Long Click
  3. // @namespace Violentmonkey Scripts
  4. // @description Stops YouTube from changing video speed to 2x when you hold down the mouse button.
  5. // @match https://*.youtube.com/*
  6. // @include https://www.youtube.com/*
  7. // @include https://m.youtube.com/*
  8. // @grant none
  9. // @version 1.3
  10. // @author Jupiter Liar
  11. // @license CC BY
  12. // @description 05/04/2024, 10:25:00 PM
  13. // ==/UserScript==
  14.  
  15. var speedmasterVisibility = false;
  16. var debug = true;
  17.  
  18. if (speedmasterVisibility == false) {
  19. // Create a stylesheet
  20. var style = document.createElement('style');
  21. style.id = "speedmaster-hide";
  22. style.type = 'text/css';
  23.  
  24. // Create a text node containing the CSS rule
  25. var cssText = document.createTextNode('.ytp-speedmaster-overlay { display: none; }');
  26.  
  27. // Append the text node to the style element
  28. style.appendChild(cssText);
  29.  
  30. // Append the stylesheet to the head
  31. document.head.appendChild(style);
  32. }
  33.  
  34.  
  35. // Function to log messages with a timestamp
  36. function log(message) {
  37. if (debug) {
  38. console.log(`[${new Date().toLocaleTimeString()}] ${message}`);
  39. }
  40. }
  41.  
  42. // Function to monitor playback speed changes
  43. function monitorPlaybackSpeed() {
  44. // Store the previous computed display property value
  45. var previousDisplay = '';
  46.  
  47. // Store the previous playback speed
  48. var previousSpeed = '';
  49. var revertSpeed = '';
  50.  
  51. // Function to check if playback speed has changed to 2 and revert if necessary
  52. function checkPlaybackSpeed(revertIfNeeded = false) {
  53. var currentSpeed;
  54. if (document.querySelector("video")) {
  55. currentSpeed = document.querySelector("video").playbackRate;
  56. }
  57. log("revertIfNeeded: " + revertIfNeeded);
  58.  
  59. // Log the current playback speed
  60. log(`Current playback speed: ${currentSpeed}`);
  61.  
  62. // Function to handle mouse-up and touchend events
  63. function handleMouseUpOrTouchEnd() {
  64. // Play the video
  65. if (document.querySelector("video")) {
  66. document.querySelector("video").play();
  67. document.querySelector("video").playbackRate = revertSpeed;
  68. } else {
  69. log("No video found.");
  70. }
  71.  
  72. // Detach the event listeners
  73. document.removeEventListener('mouseup', handleMouseUpOrTouchEnd);
  74. document.removeEventListener('touchend', handleMouseUpOrTouchEnd);
  75.  
  76. // Revert the playback speed to the previous value
  77. localStorage.setItem("yt_playbackspeed", revertSpeed);
  78. if (document.querySelector("video")) {
  79. document.querySelector("video").playbackRate = revertSpeed;
  80. } else {
  81. log("No video found.");
  82. }
  83. }
  84.  
  85. // Check if the playback speed has changed to 2
  86. if (revertIfNeeded) {
  87. log("Playback speed changed to 2 detected. Reverting...");
  88. revertSpeed = previousSpeed;
  89.  
  90. // Revert the playback speed to the previous value
  91. localStorage.setItem("yt_playbackspeed", revertSpeed);
  92. if (document.querySelector("video")) {
  93. document.querySelector("video").playbackRate = revertSpeed;
  94. } else {
  95. log("No video found.");
  96. }
  97.  
  98. // Log the playback speed to which it has been reverted
  99. log(`Playback speed reverted to ${revertSpeed}.`);
  100.  
  101. // Set up event listeners for mouse-up and touchend events
  102. document.addEventListener('mouseup', handleMouseUpOrTouchEnd);
  103. document.addEventListener('touchend', handleMouseUpOrTouchEnd);
  104. }
  105.  
  106. // Update the previous playback speed
  107. previousSpeed = currentSpeed;
  108. }
  109.  
  110. // Function to handle mutation events
  111. function handleMutation(mutationsList) {
  112. log("Handling mutations...");
  113. mutationsList.forEach(function(mutation) {
  114. // log("Mutation type:", mutation.type);
  115. if (mutation.type === 'attributes' && mutation.attributeName === 'style') {
  116. // Get the computed style of the child element of .ytp-speedmaster-overlay
  117. log("Mutation observed. Looking for child element...");
  118. var childElement = document.querySelector('.ytp-speedmaster-overlay > *');
  119. log("Child element:", childElement);
  120. var playerControlChildren = document.querySelectorAll('#player-control-container ytm-custom-control .tooltip-container');
  121. if (childElement) {
  122. var computedStyle = window.getComputedStyle(childElement);
  123. var currentDisplay = computedStyle.getPropertyValue('display');
  124.  
  125. // Check if the computed display property has changed
  126. if (currentDisplay !== previousDisplay) {
  127. log(`Computed display property changed to: ${currentDisplay}`);
  128. // Update the previous display value
  129. previousDisplay = currentDisplay;
  130.  
  131. // Check if the display property is no longer "none"
  132. if (currentDisplay !== 'none') {
  133. log("Speedmaster overlay detected. Checking playback speed...");
  134. // Pass true to indicate reverting should be performed
  135. checkPlaybackSpeed(true);
  136. }
  137. }
  138. } else if (playerControlChildren) {
  139. // Check if the player control container exists
  140.  
  141. // Loop through all child elements of the player control container
  142. playerControlChildren.forEach(function(child) {
  143. // Check if any child element contains the text "2x"
  144. if (child.innerText.includes('2x')) {
  145. log("Playback speed increased detected in player control container.");
  146. checkPlaybackSpeed(true);
  147. }
  148. });
  149. }
  150. }
  151. });
  152. }
  153.  
  154.  
  155.  
  156. // Function to check if the speedmaster overlay exists
  157. function checkSpeedmasterOverlay() {
  158. var speedmasterOverlay = document.querySelector('.ytp-speedmaster-overlay > *');
  159. return speedmasterOverlay !== null;
  160. }
  161.  
  162. // Define a flag to track whether the overlay has been detected
  163. var overlayDetected = false;
  164.  
  165. // Monitor for changes to the style attribute of the speedmaster overlay's child element
  166. var speedmasterObserver = new MutationObserver(function (mutationsList) {
  167. log("Mutation observed.");
  168. handleMutation(mutationsList);
  169. });
  170.  
  171. // Create an observer for changes to the document
  172. var observer = new MutationObserver(function(mutationsList) {
  173. mutationsList.forEach(function(mutation) {
  174. if (mutation.type === 'childList' && !overlayDetected) {
  175. // Check if the speedmaster overlay exists whenever a node is added
  176. if (checkSpeedmasterOverlay()) {
  177. log("Speedmaster overlay detected.");
  178. // Set the flag to true to indicate detection
  179. overlayDetected = true;
  180. // Disconnect the observer before handling mutations
  181. observer.disconnect();
  182. speedmasterObserver.observe(document.querySelector('.ytp-speedmaster-overlay'), {
  183. attributes: true,
  184. subtree: true
  185. });
  186. }
  187. }
  188. });
  189. });
  190.  
  191.  
  192. // Start observing the document
  193. observer.observe(document.documentElement, { childList: true, subtree: true });
  194.  
  195. // Function to check playback speed when user interaction occurs
  196. function handleUserInteraction() {
  197. log("User interaction detected. Checking playback speed...");
  198. checkPlaybackSpeed(); // Pass true to indicate reverting should be performed
  199. }
  200.  
  201. // List of event types to listen for
  202. var eventTypes = ['mousedown', 'touchstart', 'keydown'];
  203.  
  204. // Add event listeners for each event type
  205. eventTypes.forEach(function(eventType) {
  206. document.addEventListener(eventType, handleUserInteraction);
  207. });
  208. }
  209.  
  210. // Call the function to monitor playback speed
  211. monitorPlaybackSpeed();