Select and Copy Gallery URLs

Select and copy multiple gallery URLs by clicking on elements

// ==UserScript==
// @name         Select and Copy Gallery URLs
// @namespace    Violentmonkey Scripts
// @version      1.8.1
// @description  Select and copy multiple gallery URLs by clicking on elements
// @author       K0ng2
// @match        https://exhentai.org/*
// @match        https://e-hentai.org/*
// @match        https://koharu.to/*
// @match        https://nhentai.net/*
// @grant        GM.setClipboard
// @license MIT
// ==/UserScript==

(function () {
	'use strict';

	// Default highlight color
	const defaultHighlightColor = 'yellow';

	// Configuration for different websites
	const config = {
		'exhentai.org': {
			gallerySelector: '.gl1t',
			linkSelector: 'a',
		},
		'e-hentai.org': {
			gallerySelector: '.gl1t',
			linkSelector: 'a',
			highlightColor: 'lightcoral',
		},
		'koharu.to': {
			gallerySelector: 'article.border',
			linkSelector: 'a',
			highlightColor: 'lightcoral',
		},
		'nhentai.net': {
			gallerySelector: 'div.gallery',
			linkSelector: 'a',
		},
	};
	// Determine the current host and load the corresponding configuration
	const currentHost = window.location.host;
	const currentConfig = config[currentHost];

	if (!currentConfig) {
		console.warn('No configuration found for this website.');
		return;
	}

	let isSelecting = false;
	let selectedGalleries = new Set();

	// Create the "Select Galleries" button
	const selectButton = document.createElement('button');
	selectButton.innerText = 'Select Galleries';
	selectButton.style.position = 'fixed';
	selectButton.style.top = '10px';
	selectButton.style.left = '10px';
	selectButton.style.zIndex = 1000;
	selectButton.style.padding = '10px';
	selectButton.style.backgroundColor = '#4CAF50';
	selectButton.style.color = 'white';
	selectButton.style.border = 'none';
	selectButton.style.cursor = 'pointer';
	document.body.appendChild(selectButton);

	// Create the "Select All" button
	const selectAllButton = document.createElement('button');
	selectAllButton.innerText = 'Select All';
	selectAllButton.style.position = 'fixed';
	selectAllButton.style.top = '10px';
	selectAllButton.style.left = '130px';
	selectAllButton.style.zIndex = 1000;
	selectAllButton.style.padding = '10px';
	selectAllButton.style.backgroundColor = '#2196F3';
	selectAllButton.style.color = 'white';
	selectAllButton.style.border = 'none';
	selectAllButton.style.cursor = 'pointer';
	selectAllButton.style.display = 'none';
	document.body.appendChild(selectAllButton);

	// Create the "Clear All" button
	const clearAllButton = document.createElement('button');
	clearAllButton.innerText = 'Clear All';
	clearAllButton.style.position = 'fixed';
	clearAllButton.style.top = '10px';
	clearAllButton.style.left = '250px';
	clearAllButton.style.zIndex = 1000;
	clearAllButton.style.padding = '10px';
	clearAllButton.style.backgroundColor = '#FF9800';
	clearAllButton.style.color = 'white';
	clearAllButton.style.border = 'none';
	clearAllButton.style.cursor = 'pointer';
	clearAllButton.style.display = 'none';
	document.body.appendChild(clearAllButton);

	// Create the "Finish" button
	const finishButton = document.createElement('button');
	finishButton.innerText = 'Finish';
	finishButton.style.position = 'fixed';
	finishButton.style.top = '10px';
	finishButton.style.left = '370px';
	finishButton.style.zIndex = 1000;
	finishButton.style.padding = '10px';
	finishButton.style.backgroundColor = '#f44336';
	finishButton.style.color = 'white';
	finishButton.style.border = 'none';
	finishButton.style.cursor = 'pointer';
	finishButton.style.display = 'none';
	document.body.appendChild(finishButton);

	// Function to toggle selection mode
	selectButton.addEventListener('click', () => {
		isSelecting = !isSelecting;
		if (isSelecting) {
			finishButton.style.display = 'block';
			selectAllButton.style.display = 'block';
			clearAllButton.style.display = 'block';
			selectButton.innerText = 'Cancel';
			enableSelection();
		} else {
			finishButton.style.display = 'none';
			selectAllButton.style.display = 'none';
			clearAllButton.style.display = 'none';
			selectButton.innerText = 'Select Galleries';
			disableSelection();
			selectedGalleries.clear();
		}
	});

	// Function to enable selection
	function enableSelection() {
		const gridElements = document.querySelectorAll(currentConfig.gallerySelector);
		gridElements.forEach(element => {
			const linkElement = element.querySelector(currentConfig.linkSelector);
			linkElement.dataset.href = linkElement.href; // Store the href in a data attribute
			linkElement.removeAttribute('href'); // Temporarily remove the href

			element.style.cursor = 'pointer';
			element.addEventListener('click', selectGallery);
		});
	}

	// Function to disable selection
	function disableSelection() {
		const gridElements = document.querySelectorAll(currentConfig.gallerySelector);
		gridElements.forEach(element => {
			const linkElement = element.querySelector(currentConfig.linkSelector);
			if (linkElement.dataset.href) {
				linkElement.href = linkElement.dataset.href; // Restore the href
				delete linkElement.dataset.href; // Clean up the data attribute
			}

			element.style.cursor = 'default';
			element.removeEventListener('click', selectGallery);
			element.style.backgroundColor = ''; // Reset background color
		});
	}

	// Function to handle gallery selection
	function selectGallery(event) {
		if (isSelecting) {
			event.preventDefault(); // Prevent the default anchor click behavior

			const element = event.currentTarget;
			const url = element.querySelector(currentConfig.linkSelector).dataset.href;
			const highlightColor = currentConfig.highlightColor || defaultHighlightColor;

			if (selectedGalleries.has(url)) {
				selectedGalleries.delete(url);
				element.style.backgroundColor = ''; // Reset background color
			} else {
				selectedGalleries.add(url);
				element.style.backgroundColor = highlightColor; // Change background color to indicate selection
			}
		}
	}

	// Function to handle "Select All"
	selectAllButton.addEventListener('click', () => {
		const gridElements = document.querySelectorAll(currentConfig.gallerySelector);
		gridElements.forEach(element => {
			const url = element.querySelector(currentConfig.linkSelector).dataset.href;
			const highlightColor = currentConfig.highlightColor || defaultHighlightColor;

			if (!selectedGalleries.has(url)) {
				selectedGalleries.add(url);
				element.style.backgroundColor = highlightColor; // Set background color
			}
		});
	});

	// Function to handle "Clear All"
	clearAllButton.addEventListener('click', () => {
		const gridElements = document.querySelectorAll(currentConfig.gallerySelector);
		gridElements.forEach(element => {
			const url = element.querySelector(currentConfig.linkSelector).dataset.href;

			if (selectedGalleries.has(url)) {
				selectedGalleries.delete(url);
				element.style.backgroundColor = ''; // Reset background color
			}
		});
	});

	// Function to copy selected URLs
	finishButton.addEventListener('click', async () => {
		const urls = Array.from(selectedGalleries).join('\n');
		try {
			await GM.setClipboard(urls);
			alert('Copied URLs:\n' + urls);
		} catch (error) {
			alert('Failed to copy URLs: ' + error.message);
		}
		finishButton.style.display = 'none';
		selectAllButton.style.display = 'none';
		clearAllButton.style.display = 'none';
		selectButton.innerText = 'Select Galleries';
		disableSelection();
		selectedGalleries.clear();
	});
})();