YouTube Rich Grid Columns Changer (Override Inline Style)

Override YouTube's inline style for rich grid columns using MutationObserver.

  1. // ==UserScript==
  2. // @name YouTube Rich Grid Columns Changer (Override Inline Style)
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.6
  5. // @description Override YouTube's inline style for rich grid columns using MutationObserver.
  6. // @author fargly
  7. // @match https://www.youtube.com/*
  8. // @grant none
  9. // ==/UserScript==
  10.  
  11. (function() {
  12. 'use strict';
  13.  
  14. // --- Safeguard: Ensure script runs only in the top-level window ---
  15. // This check is crucial to prevent the script from running in sandboxed iframes.
  16. if (window.top !== window) {
  17. return; // Stop script execution immediately if in an iframe
  18. }
  19.  
  20. console.log('Tampermonkey script: Running in the top-level window. Preparing to override YouTube inline styles...');
  21.  
  22. // --- Configuration ---
  23. // Set your desired number of posts per row here.
  24. const newValue = 5; // <--- Set your desired number of posts per row
  25.  
  26. // --- Script Logic ---
  27. // Function to apply the desired style override
  28. function applyGridColumnsOverride() {
  29. // Defensive check, though the initial safeguard should prevent execution in iframes
  30. if (window.top !== window) {
  31. return;
  32. }
  33.  
  34. // Target the element that typically holds YouTube's inline grid styles.
  35. // ytd-rich-grid-renderer is the most probable element for these variables.
  36. const gridElement = document.querySelector('ytd-rich-grid-renderer');
  37.  
  38. if (gridElement) {
  39. // Apply the style directly to the element where YouTube sets its inline styles.
  40. // Setting the property on the element's style object will override
  41. // any value set by YouTube's script for this specific property.
  42. gridElement.style.setProperty('--ytd-rich-grid-posts-per-row', newValue);
  43. // This element needed to be added to change the visual
  44. gridElement.style.setProperty('--ytd-rich-grid-items-per-row', newValue);
  45. console.log(`Tampermonkey script: Attempted to set --ytd-rich-grid-posts-per-row on ytd-rich-grid-renderer to ${newValue}`);
  46.  
  47. // You can optionally inspect the element in the browser's developer tools
  48. // after the script runs to see if the style is applied. It should appear
  49. // within the element's style="..." attribute.
  50.  
  51. } else {
  52. console.log('Tampermonkey script: Could not find the grid element (ytd-rich-grid-renderer).');
  53. // This might happen if the element hasn't loaded yet, or YouTube's structure changed.
  54. }
  55. }
  56.  
  57. // --- MutationObserver to re-apply style if YouTube overrides it ---
  58. let observer = null; // Variable to hold the MutationObserver instance
  59.  
  60. function setupObserver() {
  61. // Disconnect any existing observer before setting up a new one
  62. if (observer) {
  63. observer.disconnect();
  64. observer = null; // Clear the reference
  65. }
  66.  
  67. const gridElement = document.querySelector('ytd-rich-grid-renderer');
  68.  
  69. if (gridElement) {
  70. // Create a new MutationObserver
  71. observer = new MutationObserver((mutations) => {
  72. mutations.forEach((mutation) => {
  73. // We are specifically watching for changes to the 'style' attribute
  74. if (mutation.type === 'attributes' && mutation.attributeName === 'style') {
  75. console.log('Tampermonkey script: Style attribute changed on ytd-rich-grid-renderer. Re-applying override.');
  76. // Re-apply our desired style whenever the style attribute changes
  77. applyGridColumnsOverride();
  78. }
  79. });
  80. });
  81.  
  82. // Start observing the target element for attribute changes
  83. observer.observe(gridElement, {
  84. attributes: true // Configure observer to watch for attribute changes
  85. });
  86.  
  87. console.log('Tampermonkey script: MutationObserver set up on ytd-rich-grid-renderer.');
  88.  
  89. } else {
  90. console.log('Tampermonkey script: Could not find ytd-rich-grid-renderer to set up observer.');
  91. // If the element isn't found immediately, the observer can't be attached.
  92. // We rely on the initial timeout and the yt-navigate-finish listener to find it later.
  93. }
  94. }
  95.  
  96. // --- Execution Triggers ---
  97.  
  98. // 1. Initial attempt after the DOM is loaded and a short delay
  99. window.addEventListener('DOMContentLoaded', () => {
  100. // Use a timeout to give YouTube's elements time to render after DOM is ready
  101. setTimeout(() => {
  102. applyGridColumnsOverride(); // Apply style initially
  103. setupObserver(); // Set up the observer after the element should be present
  104. }, 2000); // 2 second delay - adjust if needed
  105. });
  106.  
  107. // 2. Re-apply style and reset observer on YouTube's internal navigation
  108. // This is necessary because YouTube is a Single Page Application (SPA),
  109. // and the ytd-rich-grid-renderer element might be replaced or updated on navigation.
  110. window.addEventListener('yt-navigate-finish', () => {
  111. console.log('Tampermonkey script: Navigation finished. Re-applying style and attempting to re-set up observer.');
  112. // Use a short delay after navigation to allow new elements to load
  113. setTimeout(() => {
  114. applyGridColumnsOverride(); // Re-apply style on navigation
  115. setupObserver(); // Re-set up observer on the potentially new element
  116. }, 500); // 0.5 second delay after navigation
  117. });
  118.  
  119.  
  120. // --- Cleanup ---
  121. // Disconnect the observer when the page is unloaded to prevent memory leaks.
  122. window.addEventListener('beforeunload', () => {
  123. console.log('Tampermonkey script: Cleaning up observer.');
  124. if (observer) {
  125. observer.disconnect();
  126. }
  127. // Note: Removing event listeners added with anonymous functions or inside other functions
  128. // in SPAs can be complex. Disconnecting the observer is the most critical cleanup here.
  129. });
  130.  
  131.  
  132. })();