// ==UserScript== // @name YNJN Full-Page Large-Images Only // @namespace ynjn-downloader // @version 1.1 // @description Descarga solo las imágenes grandes (por dimensión) de un capítulo en YNJN // @match https://ynjn.jp/* // @require https://cdn.jsdelivr.net/npm/jszip@3/dist/jszip.min.js // @require https://cdn.jsdelivr.net/npm/file-saver@2/dist/FileSaver.min.js // @grant none // @downloadURL none // ==/UserScript== (function() { 'use strict'; // Esperar a que la página cargue por completo function waitForPageLoad(callback) { if (document.readyState === 'complete') { callback(); } else { window.addEventListener('load', callback); } } waitForPageLoad(() => { console.log("📥 [YNJN Downloader] Script activo (solo imágenes grandes)."); // Crear botón flotante const downloadBtn = document.createElement('button'); downloadBtn.textContent = 'Descargar Solo Imágenes Grandes'; downloadBtn.style.cssText = ` position: fixed; top: 10px; right: 10px; z-index: 9999; background: #6e8efb; color: #fff; padding: 8px 12px; border: none; border-radius: 4px; cursor: pointer; font-size: 14px; `; document.body.appendChild(downloadBtn); downloadBtn.addEventListener('click', async () => { downloadBtn.disabled = true; downloadBtn.textContent = 'Cargando imágenes...'; // 1. Hacer auto-scroll para forzar la carga (lazy load) await autoScroll(); // 2. Recolectar solo imágenes grandes const largeImgs = gatherLargeImages(500, 500); // Ajusta 500, 500 según necesites (ancho, alto) if (!largeImgs.length) { alert('⚠️ No se encontraron imágenes grandes. Asegúrate de haber hecho scroll hasta el final.'); resetButton(); return; } // 3. Descargar y crear ZIP try { await downloadAsZip(largeImgs); } catch (err) { console.error('❌ Error al descargar imágenes:', err); alert('⚠️ Error al descargar. Revisa la consola (F12) para más detalles.'); } resetButton(); }); }); /** * Desplazamiento automático para cargar imágenes lazy */ async function autoScroll() { return new Promise(resolve => { let totalHeight = 0; const distance = 500; const timer = setInterval(() => { const scrollTopBefore = document.documentElement.scrollTop; window.scrollBy(0, distance); totalHeight += distance; // Si no avanzó más o llegamos al final, paramos if (document.documentElement.scrollTop === scrollTopBefore || (window.innerHeight + window.scrollY) >= document.body.offsetHeight) { clearInterval(timer); // Esperar un poco extra para que terminen de cargar setTimeout(resolve, 1000); } }, 400); }); } /** * Recolectar imágenes solo si son grandes (por dimensiones) * @param {number} minWidth - ancho mínimo * @param {number} minHeight - alto mínimo * @returns {string[]} - array de URLs de imágenes grandes */ function gatherLargeImages(minWidth, minHeight) { const imgs = Array.from(document.querySelectorAll('img')); const large = []; for (const img of imgs) { // Si la imagen está realmente cargada, podemos ver su tamaño // (naturalWidth/Height) if (img.naturalWidth >= minWidth && img.naturalHeight >= minHeight) { large.push(img.src); } } // Eliminar duplicados return Array.from(new Set(large)); } /** * Descargar imágenes en un ZIP */ async function downloadAsZip(urls) { const zip = new JSZip(); for (let i = 0; i < urls.length; i++) { const url = urls[i]; console.log(`📄 Descargando (${i+1}/${urls.length}):`, url); try { const resp = await fetch(url); const blob = await resp.blob(); // Nombre con 3 dígitos zip.file(`${String(i+1).padStart(3, '0')}.jpg`, blob); } catch (err) { console.error(`Error al descargar ${url}:`, err); } } const zipContent = await zip.generateAsync({ type: 'blob' }); saveAs(zipContent, 'ynjn_manga_big_images.zip'); alert(`✅ Descarga completa: ${urls.length} imágenes grandes.`); } function resetButton() { const btn = document.querySelector('button'); if (btn) { btn.disabled = false; btn.textContent = 'Descargar Solo Imágenes Grandes'; } } })();