YouTube Smaller Thumbnails

Adds two additional thumbnails per row

目前为 2025-04-22 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name YouTube Smaller Thumbnails
  3. // @namespace http://greasyfork.org
  4. // @version 0.0.1
  5. // @description Adds two additional thumbnails per row
  6. // @author you
  7. // @license MIT
  8. // @match *://www.youtube.com/*
  9. // @match *://youtube.com/*
  10. // @run-at document-start
  11. // @grant none
  12. // ==/UserScript==
  13. (function() {
  14. 'use strict';
  15. const DELTA = 2; // Amount of rows to add.
  16. const PROCESSED_FLAG = 'yt-thumbnails-processed';
  17.  
  18. let targetValue = 0
  19.  
  20. function modifyGridStyle(gridElement) {
  21. const currentStyle = gridElement.getAttribute('style');
  22. if (!currentStyle) return;
  23.  
  24. const itemsPerRowMatch = currentStyle.match(/--ytd-rich-grid-items-per-row:\s*(\d+)/);
  25. if (!itemsPerRowMatch) return;
  26.  
  27. const currentValue = parseInt(itemsPerRowMatch[1], 10);
  28.  
  29. if (targetValue === 0) {
  30. targetValue = currentValue + DELTA;
  31. }
  32.  
  33. if (currentValue === targetValue) {
  34. return;
  35. }
  36.  
  37. const newStyle = currentStyle.replace(
  38. /--ytd-rich-grid-items-per-row:\s*\d+/,
  39. `--ytd-rich-grid-items-per-row: ${targetValue}`
  40. );
  41.  
  42. gridElement.setAttribute('style', newStyle);
  43. console.log(`[YouTube Smaller Thumbnails] Modified grid items per row: ${currentValue} -> ${targetValue}`);
  44. }
  45.  
  46. function modifyItemsPerRow(itemElement) {
  47. const currentValue = parseInt(itemElement.getAttribute('items-per-row'), 10);
  48. if (isNaN(currentValue)) return;
  49.  
  50. if (targetValue === 0) {
  51. targetValue = currentValue + DELTA;
  52. }
  53.  
  54. if (currentValue === targetValue) {
  55. return;
  56. }
  57.  
  58. itemElement.setAttribute('items-per-row', targetValue);
  59. console.log(`[YouTube Smaller Thumbnails] Modified item renderer items per row: ${currentValue} -> ${targetValue}`);
  60. }
  61.  
  62. function processExistingElements() {
  63. document.querySelectorAll('ytd-rich-grid-renderer').forEach(gridElement => {
  64. modifyGridStyle(gridElement);
  65. });
  66.  
  67. document.querySelectorAll('ytd-rich-item-renderer').forEach(itemElement => {
  68. modifyItemsPerRow(itemElement);
  69. });
  70. }
  71.  
  72. const observer = new MutationObserver((mutations) => {
  73. mutations.forEach((mutation) => {
  74. if (mutation.addedNodes && mutation.addedNodes.length > 0) {
  75. mutation.addedNodes.forEach((node) => {
  76. if (node.nodeType === Node.ELEMENT_NODE) {
  77. if (node.tagName === 'YTD-RICH-GRID-RENDERER') {
  78. modifyGridStyle(node);
  79. }
  80. if (node.tagName === 'YTD-RICH-ITEM-RENDERER') {
  81. modifyItemsPerRow(node);
  82. }
  83.  
  84. node.querySelectorAll('ytd-rich-grid-renderer').forEach(gridElement => {
  85. modifyGridStyle(gridElement);
  86. });
  87. node.querySelectorAll('ytd-rich-item-renderer').forEach(itemElement => {
  88. modifyItemsPerRow(itemElement);
  89. });
  90. }
  91. });
  92. }
  93.  
  94. if (mutation.type === 'attributes') {
  95. const target = mutation.target;
  96.  
  97. if (target.tagName === 'YTD-RICH-GRID-RENDERER' && mutation.attributeName === 'style') {
  98. modifyGridStyle(target);
  99. }
  100. if (target.tagName === 'YTD-RICH-ITEM-RENDERER' && mutation.attributeName === 'items-per-row') {
  101. modifyItemsPerRow(target);
  102. }
  103. }
  104. });
  105. });
  106.  
  107. function startObserver() {
  108. processExistingElements();
  109. observer.observe(document.documentElement, {
  110. childList: true,
  111. subtree: true,
  112. attributes: true,
  113. attributeFilter: ['style', 'items-per-row']
  114. });
  115.  
  116. console.log('[YouTube Smaller Thumbnails] Observer started');
  117. }
  118.  
  119. if (document.readyState === 'loading') {
  120. document.addEventListener('DOMContentLoaded', startObserver);
  121. } else {
  122. startObserver();
  123. }
  124.  
  125. setInterval(processExistingElements, 3000);
  126. })();