YouTube Multi Unsubscribe with Buttons and Checkboxes

Add checkboxes and individual Unsubscribe buttons to YouTube channels for easy bulk and single-channel unsubscribing

  1. // ==UserScript==
  2. // @name YouTube Multi Unsubscribe with Buttons and Checkboxes
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.4
  5. // @description Add checkboxes and individual Unsubscribe buttons to YouTube channels for easy bulk and single-channel unsubscribing
  6. // @author Dannysgonemad
  7. // @match https://www.youtube.com/feed/channels
  8. // @grant none
  9. // @license GNU GPLv3
  10. // ==/UserScript==
  11.  
  12. (function () {
  13. 'use strict';
  14.  
  15. console.log("YouTube Multi Unsubscribe script loaded");
  16.  
  17. function simulateClick(element) {
  18. if (element) {
  19. const event = new MouseEvent('click', {
  20. view: window,
  21. bubbles: true,
  22. cancelable: true,
  23. buttons: 1
  24. });
  25. element.dispatchEvent(event);
  26. }
  27. }
  28.  
  29. async function unsubscribeChannel(channel) {
  30. console.log("Attempting to unsubscribe...");
  31.  
  32. const dropdownButton = channel.querySelector("#notification-preference-button button");
  33. if (!dropdownButton) return;
  34.  
  35. simulateClick(dropdownButton);
  36. await new Promise(resolve => setTimeout(resolve, 300));
  37.  
  38. const unsubscribeMenuItem = [...document.querySelectorAll("tp-yt-paper-item yt-formatted-string")]
  39. .find(el => el.textContent.trim() === "Unsubscribe");
  40.  
  41. if (!unsubscribeMenuItem) return;
  42.  
  43. simulateClick(unsubscribeMenuItem);
  44. await new Promise(resolve => setTimeout(resolve, 300));
  45.  
  46. const confirmButton = document.querySelector("#confirm-button button");
  47. if (confirmButton) {
  48. simulateClick(confirmButton);
  49. console.log("Unsubscribed successfully!");
  50. }
  51. }
  52.  
  53. async function unsubscribeSelectedChannels() {
  54. console.log("Unsubscribing from selected channels...");
  55.  
  56. const selectedCheckboxes = document.querySelectorAll('.custom-unsubscribe-checkbox:checked');
  57.  
  58. for (const checkbox of selectedCheckboxes) {
  59. const channel = checkbox.closest('ytd-channel-renderer');
  60. if (channel) {
  61. await unsubscribeChannel(channel);
  62. await new Promise(resolve => setTimeout(resolve, 500));
  63. }
  64. }
  65. }
  66.  
  67. function ensureUnsubscribeSelectedButton() {
  68. let unsubscribeButton = document.querySelector('#custom-unsubscribe-button');
  69.  
  70. if (!unsubscribeButton) {
  71. unsubscribeButton = document.createElement('button');
  72. unsubscribeButton.id = 'custom-unsubscribe-button';
  73. unsubscribeButton.textContent = "Unsubscribe Selected";
  74. unsubscribeButton.style.cssText = `
  75. position: fixed;
  76. bottom: 20px;
  77. right: 20px;
  78. background-color: #FF0000;
  79. color: #FFFFFF;
  80. border: none;
  81. padding: 12px 20px;
  82. font-size: 16px;
  83. font-weight: bold;
  84. cursor: pointer;
  85. border-radius: 4px;
  86. box-shadow: 0px 2px 5px rgba(0,0,0,0.2);
  87. z-index: 9999;
  88. `;
  89.  
  90. unsubscribeButton.addEventListener('click', unsubscribeSelectedChannels);
  91. document.body.appendChild(unsubscribeButton);
  92. }
  93. }
  94.  
  95. function addUnsubscribeUI() {
  96. console.log("Adding UI elements...");
  97.  
  98. document.querySelectorAll('ytd-channel-renderer').forEach(channel => {
  99. if (!channel.querySelector('.custom-unsubscribe-button')) {
  100. const unsubscribeButton = document.createElement('button');
  101. unsubscribeButton.className = 'custom-unsubscribe-button';
  102. unsubscribeButton.textContent = "Unsubscribe";
  103.  
  104. unsubscribeButton.style.cssText = `
  105. margin-left: 12px;
  106. padding: 8px 12px;
  107. background-color: #FF0000;
  108. color: #FFFFFF;
  109. border: none;
  110. border-radius: 4px;
  111. font-size: 14px;
  112. font-weight: bold;
  113. cursor: pointer;
  114. transition: background-color 0.3s ease;
  115. display: inline-flex;
  116. align-items: center;
  117. justify-content: center;
  118. `;
  119.  
  120. unsubscribeButton.addEventListener('mouseover', () => {
  121. unsubscribeButton.style.backgroundColor = '#CC0000';
  122. });
  123.  
  124. unsubscribeButton.addEventListener('mouseout', () => {
  125. unsubscribeButton.style.backgroundColor = '#FF0000';
  126. });
  127.  
  128. unsubscribeButton.addEventListener('click', () => unsubscribeChannel(channel));
  129.  
  130. const actionButtons = channel.querySelector('#buttons');
  131. if (actionButtons) {
  132. actionButtons.appendChild(unsubscribeButton);
  133. }
  134. }
  135.  
  136. if (!channel.querySelector('.custom-unsubscribe-checkbox')) {
  137. const checkbox = document.createElement('input');
  138. checkbox.type = 'checkbox';
  139. checkbox.className = 'custom-unsubscribe-checkbox';
  140.  
  141. checkbox.style.cssText = `
  142. margin-left: 10px;
  143. transform: scale(1.5);
  144. cursor: pointer;
  145. `;
  146.  
  147. const actionButtons = channel.querySelector('#buttons');
  148. if (actionButtons) {
  149. actionButtons.appendChild(checkbox);
  150. }
  151. }
  152. });
  153.  
  154. ensureUnsubscribeSelectedButton();
  155. }
  156.  
  157. addUnsubscribeUI();
  158.  
  159. const observer = new MutationObserver(addUnsubscribeUI);
  160. const pageManager = document.querySelector('ytd-page-manager');
  161.  
  162. if (pageManager) {
  163. observer.observe(pageManager, { childList: true, subtree: true });
  164. }
  165. })();