Greasy Fork

Greasy Fork is available in English.

Yanmaga Manga Capture & ZIP (mejorado)

Captura imágenes completas del manga en yanmaga.jp, guarda en galería y descarga en ZIP.

当前为 2025-06-17 提交的版本,查看 最新版本

// ==UserScript==
// @name         Yanmaga Manga Capture & ZIP (mejorado)
// @namespace    yanmaga-capture
// @version      1.9
// @description  Captura imágenes completas del manga en yanmaga.jp, guarda en galería y descarga en ZIP.
// @author       ChatGPT
// @match        https://yanmaga.jp/viewer/*
// @require      https://cdn.jsdelivr.net/npm/jszip@3/dist/jszip.min.js
// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/FileSaver.min.js
// @grant        none
// @license      MIT
// ==/UserScript==

(function () {
    'use strict';

    const capturedImages = [];
    const container = document.createElement('div');
    container.style = 'position: fixed; top: 10px; right: 10px; z-index: 10000; display: flex; flex-direction: column; gap: 6px;';

    const captureBtn = document.createElement('button');
    captureBtn.textContent = '📸 Capturar páginas';
    const zipBtn = document.createElement('button');
    zipBtn.textContent = '⬇️ Descargar ZIP';
    const clearBtn = document.createElement('button');
    clearBtn.textContent = '🗑️ Limpiar galería';

    [captureBtn, zipBtn, clearBtn].forEach(btn => {
        btn.style = 'padding: 6px 10px; background: #222; color: #fff; border: none; border-radius: 4px; cursor: pointer;';
        container.appendChild(btn);
    });
    document.body.appendChild(container);

    const gallery = document.createElement('div');
    gallery.style = 'position: fixed; bottom: 10px; left: 10px; background: rgba(255,255,255,0.95); padding: 10px; max-height: 50vh; overflow-y: auto; z-index: 9999; border: 1px solid #ccc; border-radius: 6px;';
    document.body.appendChild(gallery);

    function addToGallery(img, index) {
        const wrapper = document.createElement('div');
        wrapper.style = 'margin-bottom: 8px;';
        const label = document.createElement('div');
        label.textContent = `📄 Página ${String(index + 1).padStart(3, '0')} - ${img.naturalWidth}x${img.naturalHeight}`;
        label.style = 'font-size: 12px; margin-bottom: 4px;';
        wrapper.appendChild(label);
        wrapper.appendChild(img);
        img.style.maxWidth = '120px';
        gallery.appendChild(wrapper);
    }

    async function wait(ms) {
        return new Promise(resolve => setTimeout(resolve, ms));
    }

    captureBtn.onclick = async () => {
        capturedImages.length = 0;
        gallery.innerHTML = '';

        const allImgs = [...document.querySelectorAll('img')];
        const mangaPages = allImgs.filter(img =>
            img.src.includes('/viewer/pages/') || img.src.includes('/viewer/image?') || img.src.includes('/pages/')
        );

        if (mangaPages.length === 0) {
            alert('No se encontraron imágenes visibles. Intentando forzar carga...');
            await wait(2000); // Espera 2 segundos
        }

        for (let idx = 0; idx < mangaPages.length; idx++) {
            const img = mangaPages[idx];
            const fullImage = new Image();
            fullImage.crossOrigin = 'anonymous';
            fullImage.src = img.src;

            await new Promise((resolve, reject) => {
                fullImage.onload = () => {
                    const canvas = document.createElement('canvas');
                    canvas.width = fullImage.naturalWidth;
                    canvas.height = fullImage.naturalHeight;
                    const ctx = canvas.getContext('2d');
                    ctx.drawImage(fullImage, 0, 0);
                    canvas.toBlob(blob => {
                        if (blob) {
                            capturedImages.push({
                                name: `pagina_${String(idx + 1).padStart(3, '0')}_${fullImage.naturalWidth}x${fullImage.naturalHeight}.jpg`,
                                blob: blob,
                                thumb: fullImage
                            });
                            addToGallery(fullImage, idx);
                            resolve();
                        } else reject('No se pudo crear el blob.');
                    }, 'image/jpeg');
                };
                fullImage.onerror = () => reject(`No se pudo cargar la imagen ${fullImage.src}`);
            });
        }

        if (capturedImages.length === 0) {
            alert('No se capturó ninguna imagen.');
        } else {
            alert(`Capturadas ${capturedImages.length} páginas.`);
        }
    };

    zipBtn.onclick = async () => {
        if (capturedImages.length === 0) {
            alert('No hay imágenes capturadas.');
            return;
        }

        const zip = new JSZip();
        for (let i = 0; i < capturedImages.length; i++) {
            const { name, blob } = capturedImages[i];
            zip.file(name, blob);
        }

        const blobZip = await zip.generateAsync({ type: 'blob' });
        saveAs(blobZip, 'yanmaga_manga.zip');
    };

    clearBtn.onclick = () => {
        capturedImages.length = 0;
        gallery.innerHTML = '';
        alert('Galería limpiada.');
    };
})();