您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Adds or removes all songs in the current playlist to/from your library with auto-scroll, counters, a tooltip, and a female TTS voice notification when completed.
- // ==UserScript==
- // @name Add and Remove Songs from Library on YouTube Music
- // @version 1.7
- // @license MIT
- // @description Adds or removes all songs in the current playlist to/from your library with auto-scroll, counters, a tooltip, and a female TTS voice notification when completed.
- // @author Casket Pizza
- // @match https://music.youtube.com/*
- // @grant none
- // @namespace https://greasyfork.org/users/1374050
- // ==/UserScript==
- (function() {
- 'use strict';
- let songCounter = 0;
- let counterElement;
- // Scroll to bottom of the page to load all songs
- async function scrollToBottom() {
- return new Promise((resolve) => {
- let lastScrollHeight = 0;
- const interval = setInterval(() => {
- window.scrollTo(0, document.body.scrollHeight); // Scroll to bottom
- let newScrollHeight = document.body.scrollHeight;
- if (newScrollHeight !== lastScrollHeight) {
- lastScrollHeight = newScrollHeight; // Update last height
- } else {
- clearInterval(interval); // Stop scrolling when no more new songs load
- resolve();
- }
- }, 1000); // Check every 1 second
- });
- }
- // Function to add "+" and "-" buttons next to the search bar
- function addButtons() {
- const searchBar = document.querySelector('ytmusic-search-box');
- if (!searchBar) return; // Ensure search bar exists
- const existingPlusButton = document.getElementById('addAllToLibraryButton');
- const existingMinusButton = document.getElementById('removeAllFromLibraryButton');
- if (existingPlusButton || existingMinusButton) return; // Avoid adding multiple buttons
- // Create "+" button to add all songs
- const plusButton = document.createElement('button');
- plusButton.id = 'addAllToLibraryButton';
- plusButton.innerHTML = '+';
- plusButton.style.fontSize = '20px';
- plusButton.style.marginLeft = '10px';
- plusButton.style.cursor = 'pointer';
- plusButton.style.background = 'none';
- plusButton.style.border = 'none';
- plusButton.style.color = 'white';
- plusButton.title = 'Click to add all songs to library'; // Tooltip for Add
- // Create "-" button to remove all songs
- const minusButton = document.createElement('button');
- minusButton.id = 'removeAllFromLibraryButton';
- minusButton.innerHTML = '-';
- minusButton.style.fontSize = '20px';
- minusButton.style.marginLeft = '10px';
- minusButton.style.cursor = 'pointer';
- minusButton.style.background = 'none';
- minusButton.style.border = 'none';
- minusButton.style.color = 'white';
- minusButton.title = 'Click to remove all songs from library'; // Tooltip for Remove
- // Insert the buttons next to the search bar
- searchBar.parentNode.insertBefore(plusButton, searchBar.nextSibling);
- searchBar.parentNode.insertBefore(minusButton, plusButton.nextSibling);
- // Add counter display in bottom-right corner
- counterElement = document.createElement('div');
- counterElement.id = 'songCounter';
- counterElement.style.position = 'fixed';
- counterElement.style.bottom = '80px'; // Move it up to avoid overlap with the media player
- counterElement.style.right = '20px';
- counterElement.style.fontSize = '16px';
- counterElement.style.color = 'white';
- counterElement.style.background = '#333';
- counterElement.style.padding = '10px';
- counterElement.style.borderRadius = '5px';
- counterElement.style.display = 'none'; // Hidden initially
- document.body.appendChild(counterElement);
- // Add event listener for "+" button to add all songs to the library
- plusButton.addEventListener('click', async function() {
- await scrollToBottom(); // Scroll to the bottom to load all songs
- songCounter = 0; // Reset counter
- counterElement.innerHTML = `Songs added: ${songCounter}`;
- counterElement.style.display = 'block'; // Show counter
- var song = document.body.querySelectorAll(".dropdown-trigger.style-scope.ytmusic-menu-renderer");
- for (var i = 0; i < song.length; i++) {
- song[i].click();
- var dropdown = document.body.querySelector("ytmusic-menu-popup-renderer[slot='dropdown-content']");
- if (dropdown != undefined) {
- var addSong = dropdown.querySelector("tp-yt-paper-listbox#items")
- .querySelector("ytmusic-toggle-menu-service-item-renderer.style-scope.ytmusic-menu-popup-renderer");
- if (addSong != null) {
- var actualAddSong = addSong.querySelector('yt-formatted-string.text.style-scope.ytmusic-toggle-menu-service-item-renderer');
- if (actualAddSong != null && actualAddSong.innerHTML == 'Save to library') {
- addSong.click();
- songCounter++; // Increase counter
- counterElement.innerHTML = `Songs added: ${songCounter}`;
- console.log(`Song ${songCounter} saved to library`);
- await new Promise(r => setTimeout(r, 200)); // Wait for the action to complete
- }
- }
- }
- await new Promise(r => setTimeout(r, 100)); // Avoid overloading the system
- }
- // Play TTS notification when the process is complete
- playTTS("Songs added.");
- });
- // Add event listener for "-" button to remove all songs from the library
- minusButton.addEventListener('click', async function() {
- await scrollToBottom(); // Scroll to the bottom to load all songs
- songCounter = 0; // Reset counter
- counterElement.innerHTML = `Songs removed: ${songCounter}`;
- counterElement.style.display = 'block'; // Show counter
- var song = document.body.querySelectorAll(".dropdown-trigger.style-scope.ytmusic-menu-renderer");
- for (var i = 0; i < song.length; i++) {
- song[i].click();
- var dropdown = document.body.querySelector("ytmusic-menu-popup-renderer[slot='dropdown-content']");
- if (dropdown != undefined) {
- var removeSong = dropdown.querySelector("tp-yt-paper-listbox#items")
- .querySelector("ytmusic-toggle-menu-service-item-renderer.style-scope.ytmusic-menu-popup-renderer");
- if (removeSong != null) {
- var actualRemoveSong = removeSong.querySelector('yt-formatted-string.text.style-scope.ytmusic-toggle-menu-service-item-renderer');
- if (actualRemoveSong != null && actualRemoveSong.innerHTML == 'Remove from library') {
- removeSong.click();
- songCounter++; // Increase counter
- counterElement.innerHTML = `Songs removed: ${songCounter}`;
- console.log(`Song ${songCounter} removed from library`);
- await new Promise(r => setTimeout(r, 200)); // Wait for the action to complete
- }
- }
- }
- await new Promise(r => setTimeout(r, 100)); // Avoid overloading the system
- }
- // Play TTS notification when the process is complete
- playTTS("Songs removed.");
- });
- }
- // Function to use TTS to say custom message with a female voice
- function playTTS(message) {
- const utterance = new SpeechSynthesisUtterance(message);
- utterance.lang = 'en-US';
- utterance.pitch = 1;
- utterance.rate = 1;
- // Select a female voice if available
- const voices = speechSynthesis.getVoices();
- const femaleVoice = voices.find(voice => voice.name.includes('Female') || voice.gender === 'female' || voice.name.includes('Samantha')); // Adjust for common female names
- if (femaleVoice) {
- utterance.voice = femaleVoice;
- }
- speechSynthesis.speak(utterance);
- }
- // Run the addButtons function when the page is loaded
- window.addEventListener('load', function() {
- // Wait for voices to be loaded and then add the buttons
- speechSynthesis.onvoiceschanged = addButtons;
- });
- // Reset counter and hide it after each button click
- window.addEventListener('beforeunload', function() {
- songCounter = 0;
- if (counterElement) {
- counterElement.style.display = 'none'; // Hide the counter on navigation/reload
- }
- });
- })();