// ==UserScript==
// @name Kemono.su y Coomer.su Image Downloader
// @namespace http://tampermonkey.net/
// @version 2.5
// @description Añade botones para descargar todas las imágenes o todos los posts de kemono.su y coomer.su, con soporte multilenguaje, selección de carpeta de descarga, y opción para copiar URLs al portapapeles
// @author luis123456xp
// @license MIT
// @match https://kemono.su/*/user/*
// @match https://coomer.su/*/user/*
// @grant GM_download
// @grant GM_addStyle
// @grant GM_registerMenuCommand
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_setClipboard
// @require https://code.jquery.com/jquery-3.6.0.min.js
// @run-at document-end
// ==/UserScript==
(function($) {
'use strict';
// Detectar el idioma del navegador
const userLang = navigator.language || navigator.userLanguage;
// Definir textos en ambos idiomas
const texts = {
en: {
downloadImagesButton: "Download Images",
downloadAllPostsButton: "Download All Posts",
progressLabel: "Downloaded: {0} / Total: {1}",
noImagesFound: "No images found to download",
noPostsFound: "No posts found to download",
downloadFinished: "Download Finished",
allPostsDownloadFinished: "Download of all posts finished",
setDownloadFolder: "Set Download Folder",
toggleCopyURLs: "Toggle Copy URLs to Clipboard",
urlsCopied: "Image URLs copied to clipboard"
},
es: {
downloadImagesButton: "Descargar imágenes",
downloadAllPostsButton: "Descargar Todos los Post",
progressLabel: "Descargados: {0} / Total: {1}",
noImagesFound: "No se encontraron imágenes para descargar",
noPostsFound: "No se encontraron posts para descargar",
downloadFinished: "Descarga Finalizada",
allPostsDownloadFinished: "Descarga de todos los posts finalizada",
setDownloadFolder: "Configurar Carpeta de Descarga",
toggleCopyURLs: "Activar/Desactivar Copiar URLs al Portapapeles",
urlsCopied: "URLs de imágenes copiadas al portapapeles"
}
};
// Seleccionar el idioma apropiado, por defecto inglés
const lang = userLang.startsWith('es') ? texts.es : texts.en;
// Leer la configuración de carpeta de descarga y el estado de copiar URLs
let downloadFolder = GM_getValue('downloadFolder', '');
let copyURLs = GM_getValue('copyURLs', false);
// Registrar el comando de menú para cambiar la carpeta de descarga
GM_registerMenuCommand(lang.setDownloadFolder, () => {
const folder = prompt(lang.setDownloadFolder, downloadFolder);
if (folder !== null) {
downloadFolder = folder;
GM_setValue('downloadFolder', downloadFolder);
alert(lang.setDownloadFolder + ": " + downloadFolder);
}
});
// Registrar el comando de menú para activar/desactivar copiar URLs
GM_registerMenuCommand(lang.toggleCopyURLs, () => {
copyURLs = !copyURLs;
GM_setValue('copyURLs', copyURLs);
alert(lang.toggleCopyURLs + ": " + (copyURLs ? 'ON' : 'OFF'));
});
// Si la URL contiene 'post/', agregar botón para descargar imágenes de ese post
if (window.location.href.includes('/post/')) {
addDownloadImagesButton();
} else if (window.location.href.includes('/user/')) {
addDownloadAllPostsButton();
}
function addDownloadImagesButton() {
var downloadButton = $(`<button id="downloadImagesButton" style="position:fixed; top:10px; right:10px; z-index:9999;">${lang.downloadImagesButton}</button>`);
var progressLabel = $('<div id="progressLabel" style="position:fixed; top:40px; right:10px; z-index:9999;"></div>');
$('body').append(downloadButton, progressLabel);
$('#downloadImagesButton').on('click', function() {
console.log('Iniciando la descarga de imágenes');
downloadImages(progressLabel);
});
function downloadImages(progressLabel) {
const images = $('div.post__files a.fileThumb').map(function() {
return $(this).attr('href');
}).get();
const totalImages = images.length;
let downloadedImages = 0;
if (totalImages === 0) {
alert(lang.noImagesFound);
return;
}
if (copyURLs) {
GM_setClipboard(images.join('\n'));
alert(lang.urlsCopied);
console.log(lang.urlsCopied);
return;
}
progressLabel.text(lang.progressLabel.replace('{0}', downloadedImages).replace('{1}', totalImages));
console.log(`Total de imágenes encontradas: ${totalImages}`);
images.forEach((imgSrc, index) => {
const imageName = imgSrc.split('/').pop();
const fullPath = downloadFolder ? `${downloadFolder}/${imageName}` : imageName;
GM_download({
url: imgSrc,
name: fullPath,
onload: function() {
downloadedImages++;
progressLabel.text(lang.progressLabel.replace('{0}', downloadedImages).replace('{1}', totalImages));
console.log(`Descargada imagen ${downloadedImages}/${totalImages}: ${imgSrc}`);
if (downloadedImages === totalImages) {
alert(lang.downloadFinished);
}
},
onerror: function(error) {
console.log(`Error al descargar la imagen ${imgSrc}:`, error);
if (downloadedImages + 1 === totalImages) {
alert(lang.downloadFinished);
}
}
});
console.log(`Iniciando descarga de imagen ${index + 1}/${totalImages}: ${imgSrc}`);
});
}
}
function addDownloadAllPostsButton() {
var downloadAllPostsButton = $(`<button id="downloadAllPostsButton" style="position:fixed; top:50px; right:10px; z-index:9999;">${lang.downloadAllPostsButton}</button>`);
var progressLabel = $('<div id="progressLabelAllPosts" style="position:fixed; top:80px; right:10px; z-index:9999;"></div>');
$('body').append(downloadAllPostsButton, progressLabel);
$('#downloadAllPostsButton').on('click', function() {
console.log('Iniciando la descarga de todos los posts');
downloadAllPosts(progressLabel);
});
function downloadAllPosts(progressLabel) {
const postLinks = $('a[href*="/post/"]').map(function() {
return $(this).attr('href');
}).get();
const totalPosts = postLinks.length;
let totalImages = 0;
let downloadedImages = 0;
let processedPosts = 0;
let allImageURLs = [];
console.log(`Total de posts encontrados: ${totalPosts}`);
if (totalPosts === 0) {
alert(lang.noPostsFound);
return;
}
const promises = postLinks.map((postUrl, index) => {
return fetch(postUrl)
.then(response => response.text())
.then(html => {
const parser = new DOMParser();
const doc = parser.parseFromString(html, 'text/html');
const images = $(doc).find('div.post__files a.fileThumb').map(function() {
return $(this).attr('href');
}).get();
allImageURLs = allImageURLs.concat(images);
totalImages += images.length;
if (!copyURLs) {
images.forEach((imgSrc) => {
const imageName = imgSrc.split('/').pop();
const fullPath = downloadFolder ? `${downloadFolder}/${imageName}` : imageName;
GM_download({
url: imgSrc,
name: fullPath,
onload: function() {
downloadedImages++;
progressLabel.text(lang.progressLabel.replace('{0}', downloadedImages).replace('{1}', totalImages));
if (downloadedImages === totalImages && processedPosts === totalPosts) {
alert(lang.allPostsDownloadFinished);
}
},
onerror: function(error) {
console.log(`Error al descargar la imagen ${imgSrc}:`, error);
downloadedImages++;
progressLabel.text(lang.progressLabel.replace('{0}', downloadedImages).replace('{1}', totalImages));
if (downloadedImages === totalImages && processedPosts === totalPosts) {
alert(lang.allPostsDownloadFinished);
}
}
});
});
}
processedPosts++;
})
.catch(error => {
console.log(`Error al obtener el contenido del post ${postUrl}:`, error);
processedPosts++;
});
});
Promise.all(promises).then(() => {
if (copyURLs) {
GM_setClipboard(allImageURLs.join('\n'));
alert(lang.urlsCopied);
console.log(lang.urlsCopied);
} else {
if (processedPosts === totalPosts && downloadedImages === totalImages) {
alert(lang.allPostsDownloadFinished);
}
}
});
}
}
})(window.jQuery);