YouTube - Auto Expand Subscriptions

Automatically expands the "Show more" button in YouTube's subscription sidebar, keeping your subscriptions list fully expanded.

  1. // ==UserScript==
  2. // @name YouTube - Auto Expand Subscriptions
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.3
  5. // @description Automatically expands the "Show more" button in YouTube's subscription sidebar, keeping your subscriptions list fully expanded.
  6. // @author sharmanhall
  7. // @match https://www.youtube.com/*
  8. // @grant none
  9. // @run-at document-idle
  10. // @icon https://www.google.com/s2/favicons?sz=64&domain=youtube.com
  11. // @license MIT
  12. // @copyright 2024, sharmanhall
  13. // @supportURL https://github.com/sharmanhall/youtube-auto-expand/issues
  14. // @homepageURL https://github.com/sharmanhall/youtube-auto-expand
  15. // ==/UserScript==
  16.  
  17. (function() {
  18. 'use strict';
  19.  
  20. const DEBUG = true;
  21. function log(...args) {
  22. if (DEBUG) console.log('[YT-Auto-Expand]', ...args);
  23. }
  24.  
  25. function findShowMoreButton() {
  26. log('Starting button search...');
  27. // Try various selectors
  28. const buttonSelectors = [
  29. 'ytd-guide-collapsible-entry-renderer ytd-guide-entry-renderer#expander-item',
  30. '#items ytd-guide-collapsible-entry-renderer #expander-item',
  31. '#items ytd-guide-section-renderer ytd-guide-collapsible-entry-renderer'
  32. ];
  33.  
  34. for (const selector of buttonSelectors) {
  35. const element = document.querySelector(selector);
  36. if (element) {
  37. const endpoint = element.querySelector('a#endpoint');
  38. if (endpoint) {
  39. const paperItem = endpoint.querySelector('tp-yt-paper-item');
  40. if (paperItem && element.textContent.trim().includes('Show more')) {
  41. log('Found Show more button');
  42. return endpoint;
  43. }
  44. }
  45. }
  46. }
  47. return null;
  48. }
  49.  
  50. function expandSubscriptions() {
  51. const button = findShowMoreButton();
  52. if (button) {
  53. log('Clicking button...');
  54. button.click();
  55. return true;
  56. }
  57. return false;
  58. }
  59.  
  60. // Function to handle retries with delay
  61. function attemptExpansionWithRetry(retriesLeft = 10) {
  62. if (retriesLeft <= 0) {
  63. log('Max retries reached');
  64. return;
  65. }
  66.  
  67. if (!expandSubscriptions()) {
  68. setTimeout(() => {
  69. attemptExpansionWithRetry(retriesLeft - 1);
  70. }, 1000);
  71. }
  72. }
  73.  
  74. // Wait specifically for the guide section to be ready
  75. function waitForGuide() {
  76. log('Setting up guide observer');
  77. // First try to find the guide container
  78. const guideContainer = document.querySelector('tp-yt-app-drawer');
  79. if (!guideContainer) {
  80. // If no container yet, watch for it
  81. const bodyObserver = new MutationObserver((mutations, obs) => {
  82. const container = document.querySelector('tp-yt-app-drawer');
  83. if (container) {
  84. obs.disconnect();
  85. observeGuide(container);
  86. }
  87. });
  88. bodyObserver.observe(document.body, {
  89. childList: true,
  90. subtree: true
  91. });
  92. } else {
  93. observeGuide(guideContainer);
  94. }
  95. }
  96.  
  97. function observeGuide(container) {
  98. log('Guide container found, watching for changes');
  99. // Only watch the guide container for changes
  100. const observer = new MutationObserver((mutations) => {
  101. // Only proceed if we see the section renderer
  102. if (document.querySelector('ytd-guide-section-renderer')) {
  103. // Check if button exists and isn't already clicked
  104. const button = findShowMoreButton();
  105. if (button && button.textContent.includes('Show more')) {
  106. attemptExpansionWithRetry();
  107. }
  108. }
  109. });
  110.  
  111. observer.observe(container, {
  112. childList: true,
  113. subtree: true,
  114. attributes: false, // Don't watch for attribute changes
  115. characterData: false // Don't watch for text changes
  116. });
  117. // Make initial attempt
  118. attemptExpansionWithRetry();
  119. }
  120.  
  121. // Start observing as soon as possible
  122. waitForGuide();
  123. // Also try when the window loads
  124. window.addEventListener('load', () => {
  125. log('Window loaded, making attempt...');
  126. attemptExpansionWithRetry();
  127. });
  128.  
  129. })();