您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Added Whitelist/Delist Everyone buttons | cool thing
// ==UserScript== // @name YouTube Bulk Unsubber // @namespace http://tampermonkey.net/ // @version 1.1.0 // @description Added Whitelist/Delist Everyone buttons | cool thing // @author tmg // @match https://www.youtube.com/feed/channels // @grant none // @license MIT // ==/UserScript== (function() { 'use strict'; if (window.location.href != "https://www.youtube.com/feed/channels") { return; } // get whitelist from localStorage or default to empty function getWhitelist() { try { const data = localStorage.getItem('ytWhitelist'); if (data) return JSON.parse(data); } catch(e) {} return []; } // save whitelist back to localStorage function saveWhitelist(list) { localStorage.setItem('ytWhitelist', JSON.stringify(list)); } // add channel name to whitelist function addToWhitelist(name) { const list = getWhitelist(); if (!list.includes(name)) { list.push(name); saveWhitelist(list); } } // remove channel name from whitelist function removeFromWhitelist(name) { let list = getWhitelist(); list = list.filter(n => n !== name); saveWhitelist(list); } function updateWhitelistBtn(name, btn) { const list = getWhitelist(); if (list.includes(name)) { btn.textContent = 'Remove from Whitelist'; btn.style.backgroundColor = '#cc0000'; } else { btn.textContent = 'Add to Whitelist'; btn.style.backgroundColor = '#232323'; } } // toggle whitelist membership function toggleWhitelist(name, btn) { const list = getWhitelist(); if (list.includes(name)) { removeFromWhitelist(name); btn.textContent = 'Add to Whitelist'; btn.style.backgroundColor = '#232323'; } else { addToWhitelist(name); btn.textContent = 'Remove from Whitelist'; btn.style.backgroundColor = '#cc0000'; } } // sleep helper function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } // confirm unsubscribe popup async function waitAndConfirmUnsubscribe() { for (let i = 0; i < 10; i++) { const confirmBtnWrapper = document.querySelector('yt-button-renderer#confirm-button'); if (confirmBtnWrapper) { const confirmBtn = confirmBtnWrapper.querySelector('button'); if (confirmBtn) { confirmBtn.click(); console.log('confirmed unsubscribe popup'); return; } } await sleep(250); } console.log('unsubscribe confirm popup not found'); } // main unsubscribe function async function unsubscribeAll() { let unsubbed = 0; const channelRows = document.querySelectorAll('ytd-channel-renderer'); console.log(`found ${channelRows.length} subscribed channels`); const whitelist = getWhitelist(); for (const channel of channelRows) { try { const nameEl = channel.querySelector('#channel-title, #text-container, a#main-link, a#channel-title'); if (!nameEl) { console.log('no name element found for a channel, skipping'); continue; } const name = nameEl.textContent.trim().split('\n')[0].trim(); if (whitelist.includes(name)) { console.log(`keeping subscribed: ${name}`); continue; } let unsubBtn = channel.querySelector('ytd-subscribe-button-renderer button, yt-button-renderer button'); if (!unsubBtn) { console.log(`unsubscribe button not found for ${name}, skipping`); continue; } const btnText = unsubBtn.textContent.trim().toLowerCase(); if (!btnText.includes('subscribed') && !btnText.includes('unsubscribe')) { console.log(`button text not matching subscribed for ${name}, skipping`); continue; } console.log(`unsubscribing from: ${name}`); unsubbed++; unsubBtn.click(); await waitAndConfirmUnsubscribe(); await sleep(750); } catch (e) { console.error('error processing a channel:', e); } } console.log('unsubscribe process done'); return unsubbed; } function addWhiteListAllAndNonebtn() { // <div id="header-container" class="style-scope ytd-section-list-renderer"> let header = document.querySelector("div#header-container"); let WhitelistAll = document.createElement("button"); WhitelistAll.className = 'dothething'; WhitelistAll.style.backgroundColor = "#454545"; WhitelistAll.textContent = "Whitelist Everyone"; WhitelistAll.style.position = 'relative'; WhitelistAll.style.marginLeft = '8px'; WhitelistAll.style.marginRight = '8px'; WhitelistAll.style.height = "35px"; WhitelistAll.style.padding = '8px'; WhitelistAll.style.fontSize = '15px'; WhitelistAll.style.cursor = 'pointer'; WhitelistAll.style.border = 'none'; WhitelistAll.style.borderRadius = '15px'; WhitelistAll.style.color = 'white'; WhitelistAll.style.fontWeight = 'bold'; WhitelistAll.style.userSelect = 'none'; WhitelistAll.title = 'Put everyone in the whitelist'; WhitelistAll.style.transition = "width 0.3s ease, background-color 0.3s ease"; let WhitelistNone = document.createElement("button"); WhitelistNone.className = 'dothething'; WhitelistNone.style.backgroundColor = "#232323"; WhitelistNone.textContent = "Delist Everyone"; WhitelistNone.style.position = 'relative'; WhitelistNone.style.marginLeft = '8px'; WhitelistNone.style.marginRight = '8px'; WhitelistNone.style.height = "35px"; WhitelistNone.style.padding = '8px'; WhitelistNone.style.fontSize = '15px'; WhitelistNone.style.cursor = 'pointer'; WhitelistNone.style.border = 'none'; WhitelistNone.style.borderRadius = '15px'; WhitelistNone.style.color = 'white'; WhitelistNone.style.fontWeight = 'bold'; WhitelistNone.style.userSelect = 'none'; WhitelistNone.title = 'Remove everyone from the whitelist'; WhitelistNone.style.transition = "width 0.3s ease, background-color 0.3s ease"; WhitelistAll.addEventListener("mousedown", () => { let list = []; // clear EVERYTHING saveWhitelist(list); // -- Set everyone to yes save them NOW const channelRows = document.querySelectorAll('ytd-channel-renderer'); channelRows.forEach(channel => { const name = channel.querySelector('#channel-title, #text-container, a#main-link, a#channel-title').textContent.trim().split('\n')[0].trim(); const button = channel.querySelector(".whitelist-toggle-btn"); toggleWhitelist(name, button); }); }); WhitelistNone.addEventListener("mousedown", () => { let list = []; // clear EVERYTHING saveWhitelist(list); // -- Update the whitelist buttons const channelRows = document.querySelectorAll('ytd-channel-renderer'); channelRows.forEach(channel => { const name = channel.querySelector('#channel-title, #text-container, a#main-link, a#channel-title').textContent.trim().split('\n')[0].trim(); const button = channel.querySelector(".whitelist-toggle-btn"); updateWhitelistBtn(name, button); }); }); header.appendChild(WhitelistAll); header.appendChild(WhitelistNone); } // add whitelist toggle buttons next to channel names function addWhitelistButtons() { const whitelist = getWhitelist(); const channelRows = document.querySelectorAll('ytd-channel-renderer'); channelRows.forEach(channel => { if (channel.querySelector('.whitelist-toggle-btn')) { // button already exists return; } const nameEl = channel.querySelector('#channel-title, #text-container, a#main-link, a#channel-title'); if (!nameEl) return; const name = nameEl.textContent.trim().split('\n')[0].trim(); // create button const btn = document.createElement('button'); btn.className = 'whitelist-toggle-btn'; btn.style.position = 'relative'; btn.style.marginLeft = '8px'; btn.style.marginRight = '8px'; btn.style.height = "35px"; btn.style.padding = '8px'; btn.style.fontSize = '15px'; btn.style.cursor = 'pointer'; btn.style.border = 'none'; btn.style.borderRadius = '15px'; btn.style.color = 'white'; btn.style.fontWeight = 'bold'; btn.style.userSelect = 'none'; btn.style.top = "calc(50% - 8px)"; btn.style.transform = "translateY(-50%)"; btn.title = 'Add/remove from whitelist'; btn.style.transition = "width 0.3s ease, background-color 0.3s ease"; if (whitelist.includes(name)) { btn.textContent = 'Remove from Whitelist'; btn.style.backgroundColor = '#cc0000'; // green-ish } else { btn.textContent = 'Add to Whitelist'; btn.style.backgroundColor = '#232323'; // red-ish } btn.addEventListener('click', () => { toggleWhitelist(name, btn); }); // insert button right after channel name element nameEl.parentNode.insertBefore(btn, nameEl.nextSibling); }); } // create main unsubscribe trigger button function createTriggerButton() { const btn = document.createElement('button'); btn.disabled = false; btn.textContent = 'Unsubscribe +'; btn.style.position = 'fixed'; btn.style.top = '50%'; btn.style.transform = "translateY(-50%)"; btn.style.right = '10px'; btn.style.zIndex = 9999; btn.style.padding = '10px 15px'; btn.style.backgroundColor = '#232323'; btn.style.color = 'white'; btn.style.border = 'none'; btn.style.borderRadius = '5px'; btn.style.cursor = 'pointer'; btn.style.fontWeight = 'bold'; btn.style.fontSize = '14px'; btn.style.boxShadow = '0 2px 5px rgba(0,0,0,0.3)'; btn.style.transition = "background-color 0.3s ease"; btn.addEventListener("mouseenter", () => { if (btn.disabled === false) { btn.style.backgroundColor = "#cc0000"; } }); btn.addEventListener("mouseleave", () => { btn.style.backgroundColor = "#232323"; }); btn.addEventListener('click', () => { btn.disabled = true; btn.style.cursor = "not-allowed"; btn.textContent = 'OK. Please Wait.'; unsubscribeAll().then(result => { btn.textContent = `Done. ${result} channels unsubbed.`; }); }); document.body.appendChild(btn); } // setup mutation observer on the #contents container to add buttons on new channels dynamically function setupObserver() { const container = document.querySelector('div#contents.style-scope.ytd-section-list-renderer'); if (!container) { setTimeout(setupObserver, 1000); return; } const observer = new MutationObserver(() => { addWhitelistButtons(); }); observer.observe(container, { childList: true, subtree: true }); } // init after page load window.addEventListener('load', () => { setTimeout(() => { addWhitelistButtons(); addWhiteListAllAndNonebtn(); createTriggerButton(); setupObserver(); }, 3000); }); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址