YouTube Volume Mouse Controller

Control YouTube video volume by mouse wheel.

当前为 2019-01-03 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name YouTube Volume Mouse Controller
  3. // @namespace wddd
  4. // @version 1.4.0
  5. // @author wddd
  6. // @license MIT
  7. // @description Control YouTube video volume by mouse wheel.
  8. // @homepage https://github.com/wdwind/YouTubeVolumeMouseController
  9. // @match *://www.youtube.com/*
  10. // ==/UserScript==
  11.  
  12. function getVideo() {
  13. return document.getElementsByTagName("video")[0];
  14. }
  15.  
  16. function run() {
  17. var player = getVideo();
  18. var timer = 0;
  19.  
  20. // detect available wheel event
  21. var support = "onwheel" in document.createElement("div") ? "wheel" : // Modern browsers support "wheel"
  22. document.onmousewheel !== undefined ? "mousewheel" : // Webkit and IE support at least "mousewheel"
  23. "DOMMouseScroll"; // let"s assume that remaining browsers are older Firefox
  24.  
  25. player.addEventListener(support, function (event) {
  26. var originalEvent = event; //.originalEvent;
  27. var volume = player.volume;
  28. var volumeDelta = 0.05;
  29. var deltaY = 0;
  30.  
  31. if (support == "mousewheel") {
  32. deltaY = originalEvent.wheelDelta;
  33. } else {
  34. deltaY = originalEvent.deltaY || originalEvent.detail;
  35. }
  36.  
  37. volume += (deltaY > 0 ? -volumeDelta : volumeDelta);
  38.  
  39. if (player.muted) {
  40. // Unmute first
  41. document.getElementsByClassName("ytp-mute-button")[0].click();
  42. }
  43.  
  44. player.volume = Math.max(0, Math.min(1, volume));
  45.  
  46. document.getElementsByClassName("ytp-volume-panel")[0].setAttribute("aria-valuenow", (player.volume * 100).toFixed(0));
  47. addCss(document.getElementsByClassName("ytp-volume-slider-handle")[0], {left: ((player.volume * 100) * 0.4) + "px"});
  48.  
  49. timer = showSlider(timer);
  50.  
  51. // Prevent the page to scroll
  52. event.preventDefault();
  53. event.stopImmediatePropagation();
  54. return false;
  55. });
  56. }
  57.  
  58. function showSlider(timer) {
  59. if (timer) {
  60. clearTimeout(timer);
  61. }
  62.  
  63. var sliderBar = appendSlideBar();
  64.  
  65. sliderBar.style.display = "block";
  66. timer = setTimeout(function () {
  67. sliderBar.style.display = "none";
  68. }, 1000);
  69.  
  70. sliderBar.innerText = "Volume: " + (getVideo().volume * 100).toFixed(0);
  71.  
  72. return timer;
  73. }
  74.  
  75. function appendSlideBar() {
  76. var sliderBar = document.getElementById("sliderBar");
  77. if (!sliderBar) {
  78. var sliderBarElement = document.createElement("div");
  79. sliderBarElement.id = "sliderBar";
  80.  
  81. document.getElementsByClassName("html5-video-container")[0].appendChild(sliderBarElement);
  82.  
  83. sliderBar = document.getElementById("sliderBar");
  84. addCss(sliderBar, {
  85. "width": "100%",
  86. "height": "20px",
  87. "position": "relative",
  88. "z-index": "9999",
  89. "text-align": "center",
  90. "color": "#fff",
  91. "font-size": "initial",
  92. "opacity": "0.9",
  93. "background-color": "rgba(0,0,0,0.2)",
  94. });
  95. }
  96.  
  97. addCss(sliderBar, {"top": getSliderBarTopProp() + "px"});
  98.  
  99. return sliderBar;
  100. }
  101.  
  102. function addCss(element, css) {
  103. for (var cssAttr in css) {
  104. element.style[cssAttr] = css[cssAttr];
  105. }
  106. }
  107.  
  108. function getSliderBarTopProp() {
  109. var fullScreenTitle = document.getElementsByClassName("ytp-title")[0]; // $(".ytp-title");
  110. if (fullScreenTitle && fullScreenTitle.offsetParent) {
  111. return fullScreenTitle.offsetHeight;
  112. }
  113.  
  114. var videoTop = getVideo().getBoundingClientRect().top;
  115. var headerBoundingBox =
  116. (document.getElementById("masthead-positioner") || document.getElementById("masthead-container")).getBoundingClientRect();
  117. var headerTop = headerBoundingBox.top;
  118. var headerHeight = headerBoundingBox.height;
  119.  
  120. var overlap = (headerHeight + headerTop > 0) ? Math.max(0, headerHeight - videoTop) : 0;
  121.  
  122. return overlap;
  123. }
  124.  
  125. /**
  126. * YouTube use Javascript to navigate between pages. So the script will not work:
  127. * 1. If the script only includes/matches the sub pages (like the video page www.youtube.com/watch?v=...)
  128. * 2. And the user navigates to the sub page from a page which is not included/matched by the script
  129. *
  130. * In the above scenario, the script will not be executed.
  131. *
  132. * To run the script in all cases,
  133. * 1. Include/match the whole YouTube host
  134. * 2. Detect Javascript events, and run the script appropriately
  135. *
  136. * Details:
  137. * * https://stackoverflow.com/questions/32275387/recall-tampermonkey-script-when-page-location-changes/32277150#32277150
  138. * * https://stackoverflow.com/questions/34077641/how-to-detect-page-navigation-on-youtube-and-modify-html-before-page-is-rendered
  139. * * https://github.com/1c7/Youtube-Auto-Subtitle-Download/blob/master/Youtube-Subtitle-Downloader/Tampermonkey.js#L122-L152
  140. */
  141.  
  142. // trigger when navigating to new material design page
  143. window.addEventListener("yt-navigate-finish", function () {
  144. if (window.location.href.includes("/watch?v=")) {
  145. run();
  146. }
  147. });
  148.  
  149. // trigger when navigating to the old page
  150. window.addEventListener("spfdone", function () {
  151. if (window.location.href.includes("/watch?v=")) {
  152. run();
  153. }
  154. });
  155.  
  156. // trigger when directly loading the page
  157. window.addEventListener("DOMContentLoaded", function () {
  158. if (window.location.href.includes("/watch?v=")) {
  159. run();
  160. }
  161. });
  162.  
  163. /**
  164. * Use MutationObserver to cover all edge cases.
  165. * https://stackoverflow.com/a/39803618
  166. *
  167. * This is to handle the use case where navigation happens but <video> has not been loaded yet.
  168. * (In YouTube the contents are loaded asynchronously.)
  169. */
  170. var observer = new MutationObserver(function() {
  171. if (getVideo()) {
  172. observer.disconnect();
  173. run();
  174. }
  175. });
  176.  
  177. observer.observe(document.body, /* config */ {childList: true, subtree: true});

QingJ © 2025

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