YouTube Mass Select

A simple userscript that adds checkboxes to every YouTube thumbnail. This lets you collect multiple video links at once and either export them as a TXT file.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         YouTube Mass Select
// @namespace    http://tampermonkey.net/
// @version      2.0.1
// @description  A simple userscript that adds checkboxes to every YouTube thumbnail. This lets you collect multiple video links at once and either export them as a TXT file.
// @author       bundie
// @match        https://www.youtube.com/
// @icon         https://www.google.com/s2/favicons?sz=64&domain=youtube.com
// @grant        none
// @license MIT
// ==/UserScript==

(function() {
    'use strict';
    let links = [];
let textBoxShown = false;

const linksTextBoxContainer = document.createElement("div");
const linksTextBoxHandle = document.createElement("div");
const linksTextBox = document.createElement("textarea");
const downloadButton = document.createElement("button");
const getThumbnails = () => Array.from(document.querySelectorAll("div#thumbnail")).concat(Array.from(document.querySelectorAll("ytd-compact-video-renderer"))).concat(Array.from(document.querySelectorAll("ytd-thumbnail")));

// Style for the container
linksTextBoxContainer.style.position = 'fixed';
linksTextBoxContainer.style.bottom = '0';
linksTextBoxContainer.style.right = '0';
linksTextBoxContainer.style.width = '500px';
linksTextBoxContainer.style.height = '700px';
linksTextBoxContainer.style.transition = 'bottom 0.3s';
linksTextBoxContainer.style.zIndex = 4000;
linksTextBoxContainer.style.bottom = '-650px';  // Hide the textbox


// Style for the handle
linksTextBoxHandle.style.padding = '10px';
linksTextBoxHandle.style.backgroundColor = '#007bff';
linksTextBoxHandle.style.color = 'white';
linksTextBoxHandle.style.cursor = 'pointer';
linksTextBoxHandle.style.fontSize = '15px';
linksTextBoxHandle.style.textAlign = 'center';
linksTextBoxHandle.innerText = 'Expand';

// Style for the textarea
linksTextBox.style.width = 'inherit';
linksTextBox.style.height = 'inherit';
linksTextBox.style.display = 'block';

// Style for the download button
downloadButton.innerText = 'Download as Text File';
downloadButton.style.display = 'block';
downloadButton.style.padding = '10px';
downloadButton.style.margin = '10px 0px 10px 0px';
downloadButton.style.width = '100%';

// Render a checkbox on each thumbnail
function renderCheckbox(thumbnail) {
	if (thumbnail.querySelector('input[type="checkbox"]')) return;
	const checkbox = document.createElement("input");
	checkbox.className += 'yt-check';
	checkbox.type = "checkbox";
	checkbox.style.position = 'absolute';
	checkbox.style.zIndex = 300;
	checkbox.style.scale = 2;
	checkbox.onclick = () => { 
		const link = thumbnail.querySelector("a#thumbnail").href;
		if (!checkbox.checked) links = links.filter(x => x !== link);
		else links.push(link);
		linksTextBox.value = links.join("\n");
	};
	thumbnail.insertBefore(checkbox, thumbnail.firstChild);
}

function toggleTextBox() {
	if (textBoxShown) {
		linksTextBoxContainer.style.bottom = '-650px';  // Hide the textbox
		linksTextBoxHandle.innerText = 'Expand';
	} else {
		linksTextBoxContainer.style.bottom = '0';  // Show the textbox
		linksTextBoxHandle.innerText = 'Collapse';
	}
	textBoxShown = !textBoxShown;
}

function downloadTextFile() {
	const text = linksTextBox.value;
	const blob = new Blob([text], { type: 'text/plain' });
	const url = URL.createObjectURL(blob);
	const a = document.createElement('a');
	a.href = url;
	a.download = `links-${new Date().toLocaleString()}.txt`;
	document.body.appendChild(a);
	a.click();
	document.body.removeChild(a);
	URL.revokeObjectURL(url);
}


// Synchronize the links in the textbox with the checked videos
linksTextBox.oninput = () => {
	const links = linksTextBox.value.split("\n");
	// remove checkboxes or add
	getThumbnails().forEach(thumbnail => {
		const href = thumbnail.querySelector("a#thumbnail").href;
		if (!links.includes(href)) thumbnail.querySelector(".yt-check").checked = false;
		if (links.includes(href)) thumbnail.querySelector(".yt-check").checked = true;
	})
}
// Set up the event listener for the handle and download button
linksTextBoxHandle.onclick = toggleTextBox;
downloadButton.onclick = downloadTextFile;

// Append the handle, textarea, and download button to the container
linksTextBoxContainer.append(linksTextBoxHandle, downloadButton, linksTextBox);

// Append the container to the body
document.body.appendChild(linksTextBoxContainer);

// Render checkboxes on all thumbnails
setInterval(() => {
	getThumbnails().forEach(thumbnail => renderCheckbox(thumbnail));
},200)

})();