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
}
});
})();