Auto-hide video controls almost instantly / really quickly for the Twitch desktop and mobile site

Auto-hides video controls for the Twitch desktop and mobile site after half a second (500 ms) of mouse inactivity over the video player area. Unhide the controls as you would usually do on Twitch.

  1. // ==UserScript==
  2. // @name Auto-hide video controls almost instantly / really quickly for the Twitch desktop and mobile site
  3. // @author NWP
  4. // @description Auto-hides video controls for the Twitch desktop and mobile site after half a second (500 ms) of mouse inactivity over the video player area. Unhide the controls as you would usually do on Twitch.
  5. // @namespace https://gf.qytechs.cn/users/877912
  6. // @version 0.2
  7. // @license MIT
  8. // @match *://*.twitch.tv/*
  9. // @match *://m.twitch.tv/*
  10. // @grant none
  11. // ==/UserScript==
  12.  
  13. (function() {
  14. 'use strict';
  15.  
  16. const idleTime = 500;
  17. let idleTimeoutRegular, idleTimeoutMobile, cursorTimeout;
  18. let currentUrl = window.location.href;
  19.  
  20. function hideElementsRegular() {
  21. const overlay = document.querySelector(".video-player__overlay");
  22. const extraElement = document.querySelector(".kLMGYG .ejeLlX");
  23. if (overlay) overlay.style.display = 'none';
  24. if (extraElement) extraElement.style.display = 'none';
  25. }
  26.  
  27. function showElementsRegular() {
  28. const overlay = document.querySelector(".video-player__overlay");
  29. const extraElement = document.querySelector(".kLMGYG .ejeLlX");
  30. if (overlay) overlay.style.display = '';
  31. if (extraElement) extraElement.style.display = '';
  32. }
  33.  
  34. function hideElementsMobile() {
  35. const overlay = document.querySelector(".video-player__overlay");
  36. if (overlay) overlay.style.display = 'none';
  37. }
  38.  
  39. function showElementsMobile() {
  40. const overlay = document.querySelector(".video-player__overlay");
  41. if (overlay) overlay.style.display = '';
  42. }
  43.  
  44. function hideCursor() {
  45. document.querySelector(".video-player__container").style.cursor = 'none';
  46. }
  47.  
  48. function showCursor() {
  49. document.querySelector(".video-player__container").style.cursor = '';
  50. }
  51.  
  52. function onMouseMoveRegular() {
  53. clearTimeout(idleTimeoutRegular);
  54. clearTimeout(cursorTimeout);
  55. showElementsRegular();
  56. showCursor();
  57. idleTimeoutRegular = setTimeout(hideElementsRegular, idleTime);
  58. const videoPlayer = document.querySelector(".video-player__container");
  59. if (videoPlayer && videoPlayer.matches(':hover')) {
  60. cursorTimeout = setTimeout(hideCursor, idleTime);
  61. }
  62. }
  63.  
  64. function onMouseMoveMobile() {
  65. clearTimeout(idleTimeoutMobile);
  66. clearTimeout(cursorTimeout);
  67. showElementsMobile();
  68. showCursor();
  69. idleTimeoutMobile = setTimeout(hideElementsMobile, idleTime);
  70. const videoPlayer = document.querySelector(".video-player__container");
  71. if (videoPlayer && videoPlayer.matches(':hover')) {
  72. cursorTimeout = setTimeout(hideCursor, idleTime);
  73. }
  74. }
  75.  
  76. function onMouseEnterMobile() {
  77. showElementsMobile();
  78. }
  79.  
  80. function onMouseLeaveMobile() {
  81. hideElementsMobile();
  82. }
  83.  
  84. function sendKeyPress(key) {
  85. const event = new KeyboardEvent('keydown', {
  86. key: key,
  87. keyCode: key === 'F' ? 70 : key === 'Escape' ? 27 : key === 'T' ? 84 : 0, // 'F' = 70, 'ESC' = 27, 'T' = 84
  88. bubbles: true,
  89. altKey: key === 'T' // alt + T for theatre mode
  90. });
  91. document.dispatchEvent(event);
  92. }
  93.  
  94. function handleFullscreenToggle() {
  95. const isFullscreen = document.fullscreenElement != null;
  96. if (isFullscreen) {
  97. document.exitFullscreen();
  98. } else {
  99. const videoPlayer = document.querySelector(".video-player__container");
  100. if (videoPlayer) {
  101. videoPlayer.requestFullscreen();
  102. }
  103. }
  104. }
  105.  
  106. function handleTheatreModeToggle() {
  107. sendKeyPress('T');
  108. }
  109.  
  110. function onDoubleClickRegular() {
  111. const isTheatreMode = document.querySelector("div[data-a-target='root-scroller']").classList.contains("theatre");
  112. if (document.fullscreenElement) {
  113. document.exitFullscreen();
  114. if (isTheatreMode) {
  115. sendKeyPress('T');
  116. }
  117. } else if (isTheatreMode) {
  118. handleFullscreenToggle();
  119. } else {
  120. handleFullscreenToggle();
  121. }
  122. }
  123.  
  124. function onDoubleClickMobile() {
  125. sendKeyPress('F');
  126. }
  127.  
  128. function onFullscreenButtonClick() {
  129. handleFullscreenToggle();
  130. }
  131.  
  132. function onTheatreModeButtonClick() {
  133. handleTheatreModeToggle();
  134. }
  135.  
  136. function setupMouseListener() {
  137. const regularTwitch = document.querySelector("div[data-a-player-state='']");
  138. if (regularTwitch) {
  139. regularTwitch.addEventListener('mousemove', onMouseMoveRegular);
  140. regularTwitch.addEventListener('dblclick', onDoubleClickRegular);
  141. onMouseMoveRegular();
  142. }
  143.  
  144. const mobileTwitch = document.querySelector("div[data-a-target='video-player']");
  145. if (mobileTwitch) {
  146. mobileTwitch.addEventListener('mousemove', onMouseMoveMobile);
  147. mobileTwitch.addEventListener('mouseenter', onMouseEnterMobile);
  148. mobileTwitch.addEventListener('mouseleave', onMouseLeaveMobile);
  149. mobileTwitch.addEventListener('dblclick', onDoubleClickMobile);
  150. onMouseMoveMobile();
  151. }
  152.  
  153. const fullscreenButton = document.querySelector("button[aria-label*='Fullscreen']");
  154. if (fullscreenButton) {
  155. fullscreenButton.addEventListener('click', onFullscreenButtonClick);
  156. }
  157.  
  158. const theatreModeButton = document.querySelector("button[aria-label*='Theatre Mode']");
  159. if (theatreModeButton) {
  160. theatreModeButton.addEventListener('click', onTheatreModeButtonClick);
  161. }
  162.  
  163. document.addEventListener('keydown', (event) => {
  164. if (event.key === 'f' || event.key === 'Escape') {
  165. handleFullscreenToggle();
  166. }
  167. if (event.altKey && event.key === 't') {
  168. handleTheatreModeToggle();
  169. }
  170. });
  171. }
  172.  
  173. function checkUrlChange() {
  174. if (currentUrl !== window.location.href) {
  175. currentUrl = window.location.href;
  176. setupMouseListener();
  177. }
  178. }
  179.  
  180. const observer = new MutationObserver(checkUrlChange);
  181. observer.observe(document.body, { childList: true, subtree: true });
  182.  
  183. window.addEventListener('load', () => {
  184. setTimeout(setupMouseListener, 1000);
  185. });
  186.  
  187. setupMouseListener();
  188. })();

QingJ © 2025

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