remove Youtube clickbait by uday

Replaces YouTube thumbnails with random frames from the videos

  1. // ==UserScript==
  2. // @name remove Youtube clickbait by uday
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.1
  5. // @description Replaces YouTube thumbnails with random frames from the videos
  6. // @author You
  7. // @match *://*.youtube.com/*
  8. // @grant none
  9. // @run-at document-idle
  10. // @license MIT
  11. // ==/UserScript==
  12.  
  13. (function() {
  14. 'use strict';
  15.  
  16. // Function to update thumbnails with random frames
  17. function updateThumbnails(force = false) {
  18. const frameOptions = ['hq1', 'hq2', 'hq3'];
  19. const randomFrame = frameOptions[Math.floor(Math.random() * frameOptions.length)];
  20. const timestamp = Date.now();
  21.  
  22. // Process <img> elements
  23. const imgSelector = force ? 'img' : 'img:not(.random-frame-updated)';
  24. const imgElements = document.querySelectorAll(imgSelector);
  25. for (let i = 0; i < imgElements.length; i++) {
  26. const img = imgElements[i];
  27. if (img.src.match(/https:\/\/i[0-9]?\.ytimg\.com\/(vi|vi_webp)\/.*\/(hq1|hq2|hq3|hqdefault|mqdefault|hq720)(_custom_[0-9]+)?\.jpg/)) {
  28. let newUrl = img.src.replace(/(hq1|hq2|hq3|hqdefault|mqdefault|hq720)(_custom_[0-9]+)?\.jpg/, `${randomFrame}.jpg`);
  29. newUrl += (newUrl.includes('?') ? '&' : '?') + `timestamp=${timestamp}`;
  30. img.src = newUrl;
  31. img.classList.add('random-frame-updated');
  32. }
  33. }
  34.  
  35. // Process background-image elements
  36. const bgSelector = force ? '.ytp-videowall-still-image, .iv-card-image' : '.ytp-videowall-still-image:not(.random-frame-updated), .iv-card-image:not(.random-frame-updated)';
  37. const backgroundImgElements = document.querySelectorAll(bgSelector);
  38. for (let i = 0; i < backgroundImgElements.length; i++) {
  39. const el = backgroundImgElements[i];
  40. const styleAttribute = el.getAttribute('style');
  41. if (styleAttribute && styleAttribute.match(/url\("https:\/\/i[0-9]?\.ytimg\.com\/(vi|vi_webp)\/.*\/(hq1|hq2|hq3|hqdefault|mqdefault|hq720)(_custom_[0-9]+)?\.jpg/)) {
  42. const newStyleAttribute = styleAttribute.replace(/url\("([^"]+)"\)/, (match, url) => {
  43. let newUrl = url.replace(/(hq1|hq2|hq3|hqdefault|mqdefault|hq720)(_custom_[0-9]+)?\.jpg/, `${randomFrame}.jpg`);
  44. newUrl += (newUrl.includes('?') ? '&' : '?') + `timestamp=${timestamp}`;
  45. return `url("${newUrl}")`;
  46. });
  47. el.setAttribute('style', newStyleAttribute);
  48. el.classList.add('random-frame-updated');
  49. }
  50. }
  51. }
  52.  
  53. // Set up dynamic updates
  54. function setupRandomFrameCycling() {
  55. // Initial update for existing thumbnails
  56. updateThumbnails(false);
  57.  
  58. // Observe DOM changes for new thumbnails
  59. const observer = new MutationObserver((mutations) => {
  60. if (mutations.some(mutation => mutation.addedNodes.length > 0)) {
  61. updateThumbnails(false);
  62. }
  63. });
  64. observer.observe(document.body, { childList: true, subtree: true });
  65.  
  66. // Optional: Debounced scroll event for extra coverage
  67. window.addEventListener('scroll', debounce(() => updateThumbnails(false), 500));
  68.  
  69. // Handle YouTube SPA navigation
  70. let lastUrl = location.href;
  71. new MutationObserver(() => {
  72. const url = location.href;
  73. if (url !== lastUrl) {
  74. lastUrl = url;
  75. setTimeout(() => updateThumbnails(false), 1000); // Delay for content load
  76. }
  77. }).observe(document, { subtree: true, childList: true });
  78. }
  79.  
  80. // Debounce utility to limit scroll event frequency
  81. function debounce(func, wait) {
  82. let timeout;
  83. return function(...args) {
  84. clearTimeout(timeout);
  85. timeout = setTimeout(() => func(...args), wait);
  86. };
  87. }
  88.  
  89. // Add a refresh button for manual re-randomization
  90. function createRefreshButton() {
  91. const refreshButton = document.createElement('button');
  92. refreshButton.textContent = '🔄 Refresh Thumbnails';
  93. refreshButton.style.cssText = `
  94. position: fixed;
  95. bottom: 20px;
  96. right: 20px;
  97. z-index: 9999;
  98. padding: 8px 12px;
  99. background-color: #ff0000;
  100. color: white;
  101. border: none;
  102. border-radius: 4px;
  103. cursor: pointer;
  104. font-weight: bold;
  105. box-shadow: 0 2px 5px rgba(0,0,0,0.3);
  106. `;
  107. refreshButton.addEventListener('click', () => updateThumbnails(true));
  108. document.body.appendChild(refreshButton);
  109. }
  110.  
  111. // Start the script
  112. setupRandomFrameCycling();
  113. setTimeout(createRefreshButton, 3000); // Delay to ensure page load
  114. })();

QingJ © 2025

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