您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Добавляет кнопку для удаления видео из плейлиста на ютубе. Работает с разными языками и устойчив к обновлениям интерфейса.
// ==UserScript== // @name Youtube button to delete a video from a playlist (Fixed & Robust) // @name:en Youtube button to delete a video from a playlist (Fixed & Robust) // @namespace http://tampermonkey.net/ // @version 2.1 // @description:en Adds a button to directly remove videos from the playlist on YouTube. Works across different languages and UI updates. // @description Добавляет кнопку для удаления видео из плейлиста на ютубе. Работает с разными языками и устойчив к обновлениям интерфейса. // @author You // @match https://www.youtube.com/* // @grant none // @license MIT // ==/UserScript== (function() { 'use strict'; console.log('Robust script v2.1 started'); // Уникальный SVG-путь для иконки удаления (корзины). Самый надежный идентификатор. const TRASH_ICON_SVG_PATH = "M11 17H9V8h2v9zm4-9h-2v9h2V8zm4-4v1h-1v16H6V5H5V4h4V3h6v1h4zm-2 1H7v15h10V5z"; // Словарь с переводами для поиска по тексту (запасной вариант). const REMOVE_TEXT = { 'en': 'Remove from', 'ru': 'Удалить из плейлиста', 'de': 'Aus Playlist entfernen', 'fr': 'Retirer de', 'es': 'Quitar de', 'pt': 'Remover da playlist', 'it': 'Rimuovi da', }; /** * Функция для надежного ожидания появления элемента в DOM. * @param {string} selector - CSS селектор для поиска. * @param {number} timeout - Максимальное время ожидания в мс. * @returns {Promise<Element|null>} */ function waitForElement(selector, timeout = 3000) { return new Promise(resolve => { const interval = setInterval(() => { const element = document.querySelector(selector); if (element) { clearInterval(interval); clearTimeout(timer); resolve(element); } }, 100); const timer = setTimeout(() => { clearInterval(interval); console.warn(`waitForElement: Element "${selector}" not found.`); resolve(null); }, timeout); }); } const style = document.createElement('style'); style.textContent = ` .remove-button-custom { display: flex; align-items: center; border: none; background: transparent; color: #aaa; /* Сделал чуть ярче */ cursor: pointer; margin-top: 5px; padding: 0; transition: color 0.2s, transform 0.2s; font-size: 20px; } .remove-button-custom:hover { color: #f1f1f1; } .remove-button-custom:active { transform: scale(0.85); } `; document.head.append(style); function addRemoveButton(videoElement) { if (videoElement.querySelector('.remove-button-custom')) return; const button = document.createElement('button'); button.className = 'remove-button-custom'; button.title = 'Remove from playlist'; // === ГЛАВНОЕ ИСПРАВЛЕНИЕ === // БЫЛО (вызывает ошибку TrustedHTML): button.innerHTML = '🗑️'; // СТАЛО (безопасно): button.textContent = '🗑️'; button.addEventListener('click', async (event) => { event.preventDefault(); event.stopPropagation(); const menuButton = videoElement.querySelector('#button.ytd-menu-renderer'); if (!menuButton) return; menuButton.click(); const menuContainer = await waitForElement('ytd-menu-popup-renderer, iron-dropdown'); if (!menuContainer) { alert('Menu not found. Please try again.'); return; } const menuItems = menuContainer.querySelectorAll('ytd-menu-service-item-renderer'); let removeMenuItem = null; // Способ 1: Поиск по SVG-иконке (самый надежный) removeMenuItem = Array.from(menuItems).find(item => item.querySelector(`path[d="${TRASH_ICON_SVG_PATH}"]`) ); if (removeMenuItem) { console.log('Found remove button by ICON'); } // Способ 2: Поиск по тексту (запасной, если иконка изменится) if (!removeMenuItem) { const lang = document.documentElement.lang.split('-')[0] || 'en'; const removeText = REMOVE_TEXT[lang] || REMOVE_TEXT['en']; removeMenuItem = Array.from(menuItems).find(item => item.innerText.trim().startsWith(removeText) ); if (removeMenuItem) console.log(`Found remove button by TEXT for lang "${lang}"`); } if (removeMenuItem) { removeMenuItem.click(); } else { console.error('Could not find the remove button in the menu.', Array.from(menuItems).map(i => i.innerText)); alert('Script could not find the remove button.'); document.body.click(); // Закрываем меню } }); const metaContainer = videoElement.querySelector('#meta'); if (metaContainer) { metaContainer.appendChild(button); } } function processPage() { document.querySelectorAll('ytd-playlist-video-renderer').forEach(addRemoveButton); } const observer = new MutationObserver((mutations) => { for (const mutation of mutations) { for (const node of mutation.addedNodes) { if (node.nodeType === 1) { if (node.matches('ytd-playlist-video-renderer')) { addRemoveButton(node); } node.querySelectorAll('ytd-playlist-video-renderer').forEach(addRemoveButton); } } } }); observer.observe(document.body, { childList: true, subtree: true }); window.addEventListener('yt-navigate-finish', processPage); // Для надежности запускаем и при первоначальной загрузке if (document.body) { processPage(); } else { document.addEventListener('DOMContentLoaded', processPage); } })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址