Enhanced YouTube Userscript with Themes, Decorations, Button Animations, and Timer

Adds multiple features including ad skipping, mute toggle, captions toggle, playback speed control, and more with a moveable and fixed GUI for YouTube. Includes notifications for feature toggles, theme decorations, button animations, and a video timer. Press Shift + S to hide/show the menu.

  1. // ==UserScript==
  2. // @name Enhanced YouTube Userscript with Themes, Decorations, Button Animations, and Timer
  3. // @namespace http://tampermonkey.net/
  4. // @version 3.8
  5. // @description Adds multiple features including ad skipping, mute toggle, captions toggle, playback speed control, and more with a moveable and fixed GUI for YouTube. Includes notifications for feature toggles, theme decorations, button animations, and a video timer. Press Shift + S to hide/show the menu.
  6. // @author Wadawg117
  7. // @match https://www.youtube.com/*
  8. // @icon https://www.youtube.com/s/desktop/fa72b5c3/img/favicon_32x32.png
  9. // @grant none
  10. // ==/UserScript==
  11.  
  12. (function() {
  13. 'use strict';
  14.  
  15. // Create the main container for the GUI
  16. const container = document.createElement('div');
  17. container.style.position = 'fixed';
  18. container.style.top = '50%';
  19. container.style.left = '50%';
  20. container.style.width = '300px'; // Slightly larger width
  21. container.style.height = 'auto'; // Adjust height automatically based on content
  22. container.style.transform = 'translate(-50%, -50%)'; // Center the container
  23. container.style.zIndex = '1000';
  24. container.style.padding = '10px'; // Slightly larger padding
  25. container.style.backgroundColor = 'rgba(0, 0, 0, 0.8)';
  26. container.style.border = '2px solid #ff0000';
  27. container.style.borderRadius = '10px';
  28. container.style.color = '#ffffff';
  29. container.style.display = 'grid';
  30. container.style.gridTemplateColumns = 'repeat(2, auto)';
  31. container.style.gap = '10px';
  32. container.style.cursor = 'move';
  33.  
  34. // Create the notification popup container
  35. const popupContainer = document.createElement('div');
  36. popupContainer.style.position = 'fixed';
  37. popupContainer.style.bottom = '20px';
  38. popupContainer.style.right = '20px';
  39. popupContainer.style.padding = '10px';
  40. popupContainer.style.backgroundColor = 'rgba(0, 0, 0, 0.8)';
  41. popupContainer.style.border = '2px solid #ff0000';
  42. popupContainer.style.borderRadius = '10px';
  43. popupContainer.style.color = '#ffffff';
  44. popupContainer.style.display = 'none';
  45. popupContainer.style.zIndex = '1001';
  46.  
  47. // Append the popup container to the body
  48. document.body.appendChild(popupContainer);
  49.  
  50. // Function to show the notification popup
  51. const showPopup = (message) => {
  52. popupContainer.innerText = message;
  53. popupContainer.style.display = 'block';
  54. setTimeout(() => {
  55. popupContainer.style.display = 'none';
  56. }, 2000);
  57. };
  58.  
  59. // Create buttons for different features
  60. const createButton = (label, onClick) => {
  61. const button = document.createElement('button');
  62. button.innerText = label;
  63. button.style.padding = '5px';
  64. button.style.backgroundColor = '#ff0000';
  65. button.style.color = '#ffffff';
  66. button.style.border = '1px solid #000000'; // Black outline
  67. button.style.borderRadius = '5px';
  68. button.style.cursor = 'pointer';
  69. button.style.transition = 'transform 0.2s';
  70. button.addEventListener('click', () => {
  71. button.style.transform = 'scale(0.95)';
  72. setTimeout(() => {
  73. button.style.transform = 'scale(1)';
  74. onClick();
  75. }, 200);
  76. });
  77. return button;
  78. };
  79.  
  80. // Feature functions
  81. const toggleComments = () => {
  82. const commentsSection = document.getElementById('comments');
  83. if (commentsSection) {
  84. const isHidden = commentsSection.style.display === 'none';
  85. commentsSection.style.display = isHidden ? '' : 'none';
  86. showPopup(isHidden ? 'Turned on Comments' : 'Turned off Comments');
  87. }
  88. };
  89.  
  90. const toggleDescription = () => {
  91. const descriptionSection = document.querySelector('#meta-contents');
  92. if (descriptionSection) {
  93. const isHidden = descriptionSection.style.display === 'none';
  94. descriptionSection.style.display = isHidden ? '' : 'none';
  95. showPopup(isHidden ? 'Turned on Description' : 'Turned off Description');
  96. }
  97. };
  98.  
  99. const toggleRelatedVideos = () => {
  100. const relatedVideosSection = document.querySelector('#related');
  101. if (relatedVideosSection) {
  102. const isHidden = relatedVideosSection.style.display === 'none';
  103. relatedVideosSection.style.display = isHidden ? '' : 'none';
  104. showPopup(isHidden ? 'Turned on Related Videos' : 'Turned off Related Videos');
  105. }
  106. };
  107.  
  108. const skipAds = () => {
  109. const adSkipButton = document.querySelector('.ytp-ad-skip-button');
  110. if (adSkipButton) {
  111. adSkipButton.click();
  112. showPopup('Skipped Ad');
  113. } else {
  114. showPopup('No ad found');
  115. }
  116. };
  117.  
  118. const toggleMute = () => {
  119. const muteButton = document.querySelector('.ytp-mute-button');
  120. if (muteButton) {
  121. const isMuted = document.querySelector('video').muted;
  122. muteButton.click();
  123. showPopup(isMuted ? 'Turned off Mute' : 'Turned on Mute');
  124. }
  125. };
  126.  
  127. const toggleCaptions = () => {
  128. const captionsButton = document.querySelector('.ytp-subtitles-button');
  129. if (captionsButton) {
  130. captionsButton.click();
  131. showPopup('Toggled Captions');
  132. }
  133. };
  134.  
  135. const increasePlaybackSpeed = () => {
  136. const video = document.querySelector('video');
  137. if (video) {
  138. video.playbackRate = Math.min(video.playbackRate + 0.25, 2);
  139. showPopup(`Playback Speed: ${video.playbackRate.toFixed(2)}x`);
  140. }
  141. };
  142.  
  143. const decreasePlaybackSpeed = () => {
  144. const video = document.querySelector('video');
  145. if (video) {
  146. video.playbackRate = Math.max(video.playbackRate - 0.25, 0.25);
  147. showPopup(`Playback Speed: ${video.playbackRate.toFixed(2)}x`);
  148. }
  149. };
  150.  
  151. const resetPlaybackSpeed = () => {
  152. const video = document.querySelector('video');
  153. if (video) {
  154. video.playbackRate = 1.0;
  155. showPopup('Playback Speed Reset to 1.0x');
  156. }
  157. };
  158.  
  159. // Theme changer function
  160. const changeTheme = (theme) => {
  161. removeExistingDecorations();
  162. switch (theme) {
  163. case '0':
  164. container.style.backgroundColor = 'rgba(0, 0, 0, 0.8)';
  165. container.style.border = '2px solid #ff0000';
  166. addDefaultDecoration();
  167. showPopup('Default theme activated');
  168. break;
  169. case '1':
  170. container.style.backgroundColor = 'rgba(255, 0, 127, 0.8)';
  171. container.style.border = '2px solid #ff69b4';
  172. addValentineDecoration();
  173. showPopup('Valentine theme activated');
  174. break;
  175. case '2':
  176. container.style.backgroundColor = 'rgba(255, 0, 0, 0.8)';
  177. container.style.border = '2px solid #ff0000';
  178. addYouTubeDecoration();
  179. showPopup('YouTube theme activated');
  180. break;
  181. case '3':
  182. container.style.backgroundColor = 'rgba(255, 165, 0, 0.8)';
  183. container.style.border = '2px solid #ffa500';
  184. addHalloweenDecoration();
  185. showPopup('Halloween theme activated');
  186. break;
  187. case '4':
  188. container.style.backgroundColor = 'rgba(0, 128, 0, 0.8)';
  189. container.style.border = '2px solid #008000';
  190. addChristmasDecoration();
  191. showPopup('Christmas theme activated');
  192. break;
  193. }
  194. };
  195.  
  196. // Add decorations for each theme
  197. const addDefaultDecoration = () => {
  198. // No decorations for default theme
  199. };
  200.  
  201. const addValentineDecoration = () => {
  202. for (let i = 0; i < 10; i++) {
  203. const heart = document.createElement('div');
  204. heart.innerHTML = '❤️';
  205. heart.classList.add('decoration');
  206. heart.style.position = 'fixed';
  207. heart.style.left = `${Math.random() * 100}%`;
  208. heart.style.top = `${Math.random() * 100}%`;
  209. heart.style.animation = 'float 5s infinite';
  210. heart.style.fontSize = '24px';
  211. heart.style.zIndex = '1000';
  212. document.body.appendChild(heart);
  213. }
  214. };
  215.  
  216. const addYouTubeDecoration = () => {
  217. for (let i = 0; i < 10; i++) {
  218. const youtubeIcon = document.createElement('div');
  219. youtubeIcon.innerHTML = '🎥';
  220. youtubeIcon.classList.add('decoration');
  221. youtubeIcon.style.position = 'fixed';
  222. youtubeIcon.style.left = `${Math.random() * 100}%`;
  223. youtubeIcon.style.top = `${Math.random() * 100}%`;
  224. youtubeIcon.style.animation = 'float 5s infinite';
  225. youtubeIcon.style.fontSize = '24px';
  226. youtubeIcon.style.zIndex = '1000';
  227. document.body.appendChild(youtubeIcon);
  228. }
  229. };
  230.  
  231. const addHalloweenDecoration = () => {
  232. for (let i = 0; i < 10; i++) {
  233. const pumpkin = document.createElement('div');
  234. pumpkin.innerHTML = '🎃';
  235. pumpkin.classList.add('decoration');
  236. pumpkin.style.position = 'fixed';
  237. pumpkin.style.left = `${Math.random() * 100}%`;
  238. pumpkin.style.top = `${Math.random() * 100}%`;
  239. pumpkin.style.animation = 'float 5s infinite';
  240. pumpkin.style.fontSize = '24px';
  241. pumpkin.style.zIndex = '1000';
  242. document.body.appendChild(pumpkin);
  243. }
  244. };
  245.  
  246. const addChristmasDecoration = () => {
  247. for (let i = 0; i < 10; i++) {
  248. const snowflake = document.createElement('div');
  249. snowflake.innerHTML = '❄️';
  250. snowflake.classList.add('decoration');
  251. snowflake.style.position = 'fixed';
  252. snowflake.style.left = `${Math.random() * 100}%`;
  253. snowflake.style.top = `${Math.random() * 100}%`;
  254. snowflake.style.animation = 'float 5s infinite';
  255. snowflake.style.fontSize = '24px';
  256. snowflake.style.zIndex = '1000';
  257. document.body.appendChild(snowflake);
  258. }
  259. };
  260.  
  261. // Remove existing decorations
  262. const removeExistingDecorations = () => {
  263. const decorations = document.querySelectorAll('.decoration');
  264. decorations.forEach(deco => {
  265. deco.remove();
  266. });
  267. };
  268.  
  269. // Create the theme slider
  270. const createThemeSlider = () => {
  271. const sliderContainer = document.createElement('div');
  272. sliderContainer.style.gridColumn = 'span 2';
  273. sliderContainer.style.display = 'flex';
  274. sliderContainer.style.flexDirection = 'column';
  275. sliderContainer.style.alignItems = 'center';
  276. sliderContainer.style.marginTop = '10px';
  277.  
  278. const sliderLabel = document.createElement('label');
  279. sliderLabel.innerText = 'Select Theme:';
  280. sliderLabel.style.marginBottom = '5px';
  281. sliderContainer.appendChild(sliderLabel);
  282.  
  283. const slider = document.createElement('input');
  284. slider.type = 'range';
  285. slider.min = '0';
  286. slider.max = '4';
  287. slider.value = '0';
  288. slider.style.width = '100%';
  289. slider.oninput = (e) => changeTheme(e.target.value);
  290. sliderContainer.appendChild(slider);
  291.  
  292. const themeNames = ['Default', 'Valentine', 'YouTube', 'Halloween', 'Christmas'];
  293. const themeName = document.createElement('div');
  294. themeName.innerText = themeNames[slider.value];
  295. sliderContainer.appendChild(themeName);
  296.  
  297. slider.addEventListener('input', (e) => {
  298. themeName.innerText = themeNames[e.target.value];
  299. });
  300.  
  301. // Prevent dragging when interacting with the slider
  302. slider.addEventListener('mousedown', (e) => {
  303. e.stopPropagation();
  304. });
  305.  
  306. return sliderContainer;
  307. };
  308.  
  309. // Create the video timer
  310. const createVideoTimer = () => {
  311. const timer = document.createElement('div');
  312. timer.style.position = 'fixed';
  313. timer.style.top = '10px';
  314. timer.style.left = '10px';
  315. timer.style.padding = '10px'; // Increased padding for larger size
  316. timer.style.backgroundColor = 'rgba(0, 0, 0, 0.5)';
  317. timer.style.color = '#ffffff';
  318. timer.style.borderRadius = '5px';
  319. timer.style.fontSize = '16px'; // Increased font size
  320. timer.style.zIndex = '1000';
  321. document.body.appendChild(timer);
  322.  
  323. const updateTimer = () => {
  324. const video = document.querySelector('video');
  325. if (video) {
  326. const timeLeft = video.duration - video.currentTime;
  327. const minutes = Math.floor(timeLeft / 60);
  328. const seconds = Math.floor(timeLeft % 60);
  329. timer.innerText = `Time Left: ${minutes}:${seconds < 10 ? '0' : ''}${seconds}`;
  330. } else {
  331. timer.innerText = 'Time Left: --:--';
  332. }
  333. requestAnimationFrame(updateTimer);
  334. };
  335.  
  336. updateTimer();
  337. };
  338.  
  339. // Append buttons to the container
  340. const buttons = [
  341. { label: 'Toggle Comments', action: toggleComments },
  342. { label: 'Toggle Description', action: toggleDescription },
  343. { label: 'Toggle Related Videos', action: toggleRelatedVideos },
  344. { label: 'Skip Ads', action: skipAds },
  345. { label: 'Toggle Mute', action: toggleMute },
  346. { label: 'Toggle Captions', action: toggleCaptions },
  347. { label: 'Increase Speed', action: increasePlaybackSpeed },
  348. { label: 'Decrease Speed', action: decreasePlaybackSpeed },
  349. { label: 'Reset Speed', action: resetPlaybackSpeed }
  350. ];
  351.  
  352. buttons.forEach(button => {
  353. container.appendChild(createButton(button.label, button.action));
  354. });
  355.  
  356. container.appendChild(createThemeSlider());
  357.  
  358. // Make the container moveable
  359. let isMouseDown = false;
  360. let offsetX, offsetY;
  361.  
  362. container.addEventListener('mousedown', (e) => {
  363. isMouseDown = true;
  364. offsetX = e.clientX - container.getBoundingClientRect().left;
  365. offsetY = e.clientY - container.getBoundingClientRect().top;
  366. container.style.cursor = 'grabbing';
  367. });
  368.  
  369. document.addEventListener('mousemove', (e) => {
  370. if (isMouseDown) {
  371. container.style.left = `${e.clientX - offsetX}px`;
  372. container.style.top = `${e.clientY - offsetY}px`;
  373. container.style.transform = ''; // Remove the centering transform
  374. }
  375. });
  376.  
  377. document.addEventListener('mouseup', () => {
  378. isMouseDown = false;
  379. container.style.cursor = 'move';
  380. });
  381.  
  382. // Append the container to the body
  383. document.body.appendChild(container);
  384.  
  385. // Create and append the video timer
  386. createVideoTimer();
  387.  
  388. // Keyboard shortcut to hide/show the menu
  389. let isMenuVisible = true;
  390. document.addEventListener('keydown', (e) => {
  391. if (e.shiftKey && e.key === 'S') {
  392. isMenuVisible = !isMenuVisible;
  393. container.style.display = isMenuVisible ? 'grid' : 'none';
  394. }
  395. });
  396.  
  397. // Add CSS for floating animation
  398. const style = document.createElement('style');
  399. style.innerHTML = `
  400. @keyframes float {
  401. 0% { transform: translateY(0); }
  402. 50% { transform: translateY(-20px); }
  403. 100% { transform: translateY(0); }
  404. }
  405. `;
  406. document.head.appendChild(style);
  407. })();