YouTube Volume Control with Memory and Draggable UI

Set YouTube volume manually on a scale of 1-100, remember last set volume, and inject the UI to the left of the volume slider on the video player. Syncs the slider, disables invalid inputs, and adds debugging.

当前为 2024-10-26 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name YouTube Volume Control with Memory and Draggable UI
  3. // @namespace http://tampermonkey.net/
  4. // @version 2.8
  5. // @description Set YouTube volume manually on a scale of 1-100, remember last set volume, and inject the UI to the left of the volume slider on the video player. Syncs the slider, disables invalid inputs, and adds debugging.
  6. // @author Nick2bad4u
  7. // @match *://www.youtube.com/*
  8. // @icon https://www.google.com/s2/favicons?sz=64&domain=youtube.com
  9. // @grant GM.getValue
  10. // @grant GM.setValue
  11. // @license UnLicense
  12. // ==/UserScript==
  13.  
  14. (async function() {
  15. 'use strict';
  16.  
  17. // Default volume if none is saved
  18. let previousVolume = await GM.getValue('youtubeVolume', 50);
  19.  
  20. // Create input element for volume control
  21. const volumeInput = document.createElement('input');
  22. volumeInput.type = 'number';
  23. volumeInput.min = 0;
  24. volumeInput.max = 100;
  25. volumeInput.value = previousVolume;
  26.  
  27. // Set input field styles to resemble YouTube's UI
  28. volumeInput.style.width = '30px';
  29. volumeInput.style.marginRight = '10px';
  30. volumeInput.style.backgroundColor = 'rgba(255, 255, 255, 0.0)';
  31. volumeInput.style.color = 'white';
  32. volumeInput.style.border = '0px solid rgba(255, 255, 255, 0.0)';
  33. volumeInput.style.borderRadius = '4px';
  34. volumeInput.style.zIndex = 9999;
  35. volumeInput.style.height = '24px';
  36. volumeInput.style.fontSize = '16px';
  37. volumeInput.style.padding = '0 4px';
  38. volumeInput.style.transition = 'border-color 0.3s, background-color 0.3s';
  39. volumeInput.style.outline = 'none';
  40. volumeInput.style.position = 'relative';
  41. volumeInput.style.top = '13px';
  42.  
  43. // Change border color on focus
  44. volumeInput.addEventListener('focus', () => {
  45. volumeInput.style.borderColor = 'rgba(255, 255, 255, 0.6)';
  46. });
  47.  
  48. volumeInput.addEventListener('blur', () => {
  49. volumeInput.style.borderColor = 'rgba(255, 255, 255, 0.3)';
  50. });
  51.  
  52. // Change background color on hover
  53. volumeInput.addEventListener('mouseenter', () => {
  54. volumeInput.style.backgroundColor = 'rgba(0, 0, 0, 0.8)';
  55. });
  56.  
  57. volumeInput.addEventListener('mouseleave', () => {
  58. volumeInput.style.backgroundColor = 'rgba(255, 255, 255, 0.0)';
  59. });
  60.  
  61. // Prevent YouTube hotkeys when typing in the input
  62. volumeInput.addEventListener('keydown', function(event) {
  63. event.stopPropagation();
  64. console.log('Keydown event in volume input, stopping propagation.');
  65. });
  66.  
  67. // Function to set the volume based on input value
  68. async function setVolume() {
  69. const player = document.querySelector('video');
  70. if (player) {
  71. let volumeValue = volumeInput.value;
  72.  
  73. // Validate input (must be between 0 and 100)
  74. if (volumeValue < 0) volumeValue = 0;
  75. if (volumeValue > 100) volumeValue = 100;
  76. volumeInput.value = volumeValue;
  77.  
  78. // Set the player volume and save to Tampermonkey storage
  79. player.volume = volumeValue / 100;
  80. await GM.setValue('youtubeVolume', volumeValue);
  81. console.log(`Volume set to ${volumeValue} and saved to Tampermonkey storage.`);
  82.  
  83. // Sync YouTube's volume slider UI
  84. const volumeSlider = document.querySelector('.ytp-volume-slider-handle');
  85. if (volumeSlider) {
  86. volumeSlider.style.left = `${volumeValue}%`;
  87. console.log('YouTube volume slider updated.');
  88. }
  89. }
  90. }
  91.  
  92. // Event listener for input change (manually changing the volume in the input box)
  93. volumeInput.addEventListener('input', setVolume);
  94.  
  95. // Function to update the input field when YouTube's player volume is changed
  96. async function updateVolumeInput() {
  97. const player = document.querySelector('video');
  98. if (player) {
  99. const currentVolume = Math.round(player.volume * 100);
  100. volumeInput.value = currentVolume;
  101. await GM.setValue('youtubeVolume', currentVolume);
  102. console.log(`Volume input updated to ${currentVolume} from video player.`);
  103.  
  104. // Show 0 if the video is muted
  105. if (player.muted) {
  106. volumeInput.value = 0;
  107. }
  108. }
  109. }
  110.  
  111. // Function to handle mute changes
  112. async function handleMuteChange() {
  113. const player = document.querySelector('video');
  114. if (player) {
  115. if (player.muted) {
  116. volumeInput.value = 0; // Show 0 when muted
  117. } else {
  118. volumeInput.value = previousVolume; // Restore previous volume when unmuted
  119. player.volume = previousVolume / 100; // Set the player volume back to previous
  120. }
  121. console.log(`Mute state changed: muted = ${player.muted}`);
  122. }
  123. }
  124.  
  125. // Inject the input box into YouTube's control bar
  126. function injectVolumeControl() {
  127. const volumeSliderPanel = document.querySelector('.ytp-volume-panel');
  128. if (volumeSliderPanel) {
  129. volumeSliderPanel.parentNode.insertBefore(volumeInput, volumeSliderPanel);
  130. setVolume(); // Set initial volume
  131. const player = document.querySelector('video');
  132. if (player) {
  133. player.addEventListener('volumechange', updateVolumeInput);
  134. player.addEventListener('mute', handleMuteChange);
  135. player.addEventListener('unmute', handleMuteChange);
  136. console.log('Volume input injected and event listeners attached.');
  137. }
  138. } else {
  139. console.log('Volume panel not found, retrying...');
  140. setTimeout(injectVolumeControl, 500);
  141. }
  142. }
  143.  
  144. // Inject the volume control when the page is ready
  145. injectVolumeControl();
  146.  
  147. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址