Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save bulletinmybeard/ba2699cb11db48517389380a97218846 to your computer and use it in GitHub Desktop.
Save bulletinmybeard/ba2699cb11db48517389380a97218846 to your computer and use it in GitHub Desktop.
Better YouTube Notifications Organizer

A userscript that improves YouTube's notification system by:

  • Eliminating the annoying Important category by moving all notifications from it into More notifications
  • Sorting all notifications by recency (newest first)
  • Reducing the need to check multiple notification categories
// ==UserScript==
// @name         Better YouTube Notifications Organizer
// @namespace    https://rschu.me/
// @homepage     https://rschu.me/
// @version      1.0.0
// @encoding     utf-8
// @description  Combines and sorts YouTube notifications by recency
// @author       Robin Schulz
// @match        *://*.youtube.com/*
// @compatible   chrome
// @compatible   firefox
// @compatible   opera
// @compatible   safari
// @run-at       document-end
// ==/UserScript==

(function() {
  'use strict';
  
  const observeElement = (callback) => {
      const observer = new MutationObserver((mutationsList, observer) => {
          for (const mutation of mutationsList) {
              if (mutation.type === 'childList') {
                  callback();
              }
          }
      });

      if (document.body) {
          observer.observe(document.body, {
              childList: true,
              subtree: true,
          });
      } else {
          new MutationObserver((mutations, obs) => {
              if (document.body) {
                  obs.disconnect();
                  observer.observe(document.body, {
                      childList: true,
                      subtree: true,
                  });
              }
          }).observe(document.documentElement, {
              childList: true
          });
      }

      return observer;
  };

  const convertTimeToMinutes = (timeString) => {
      if (!timeString) {
        return Infinity;
      }
      
      timeString = timeString.trim().toLowerCase();
      
      if (timeString === 'just now') {
        return 0;
      }
      
      const match = timeString.match(/(\d+)\s+(minute|hour|day|week|month|year)s?\s+ago/);
      if (!match) {
        return Infinity;
      }
      
      const value = parseInt(match[1], 10);
      const unit = match[2];
      
      switch (unit) {
          case 'minute': return value;
          case 'hour': return value * 60;
          case 'day': return value * 24 * 60;
          case 'week': return value * 7 * 24 * 60;
          case 'month': return value * 30 * 24 * 60;
          case 'year': return value * 365 * 24 * 60;
          default: return Infinity;
      }
  };

  const moveImportantNotifications = () => {
      const notificationsPanel = document.querySelector('ytd-multi-page-menu-renderer[menu-style="multi-page-menu-style-type-notifications"]');
      if (!notificationsPanel) {
        return;
      }

      const sections = notificationsPanel.querySelectorAll('yt-multi-page-menu-section-renderer');
      if (sections.length < 2) {
        return;
      }
      
      let importantSection = null;
      let moreNotificationsSection = null;
      
      for (const section of sections) {
          const title = section.querySelector('#section-title yt-formatted-string');
          if (!title) {
            continue;
          }
          
          const titleText = title.textContent.trim();
          if (titleText === 'Important') {
              importantSection = section;
          } else if (titleText === 'More notifications') {
              moreNotificationsSection = section;
          }
      }
      
      if (importantSection && moreNotificationsSection) {
          const importantNotifications = Array.from(importantSection.querySelectorAll('ytd-notification-renderer'));
          if (importantNotifications.length === 0) {
            return;
          }
          
          const targetContainer = moreNotificationsSection.querySelector('#items');
          if (!targetContainer) {
            return;
          }
          
          importantNotifications.forEach(notification => {
              targetContainer.insertBefore(notification, targetContainer.firstChild);
          });
          
          importantSection.style.display = 'none';
          
          const allNotifications = Array.from(targetContainer.querySelectorAll('ytd-notification-renderer'));
          
          const sortedNotifications = [...allNotifications];
          
          sortedNotifications.sort((a, b) => {
              const timeA = a.querySelector('.metadata yt-formatted-string:last-child');
              const timeB = b.querySelector('.metadata yt-formatted-string:last-child');
              
              const minutesA = convertTimeToMinutes(timeA ? timeA.textContent : '');
              const minutesB = convertTimeToMinutes(timeB ? timeB.textContent : '');
              
              return minutesA - minutesB;
          });
          
          for (let i = 0; i < sortedNotifications.length; i++) {
              const element = sortedNotifications[i];
              targetContainer.insertBefore(element, targetContainer.children[i]);
          }
      }
  };

  observeElement(() => {
      const notificationsPanel = document.querySelector('ytd-multi-page-menu-renderer[menu-style="multi-page-menu-style-type-notifications"]');
      if (notificationsPanel && notificationsPanel.offsetParent !== null) {
          setTimeout(moveImportantNotifications, 200);
      }
  });
  
  document.addEventListener('click', function(e) {
      if (e.target.closest('yt-icon-button#button.style-scope.ytd-notification-topbar-button-renderer') || 
          e.target.closest('button.style-scope.ytd-notification-topbar-button-renderer')) {
          setTimeout(moveImportantNotifications, 300);
      }
  }, true);
  
  setTimeout(moveImportantNotifications, 500);
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment