Greasy Fork

Greasy Fork is available in English.

Yanmaga Downloader + Scroll + Webtoon Merge

Descarga capítulos en yanmaga.jp con scroll automático y opción de merge como webtoon

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

// ==UserScript==
// @name         Yanmaga Downloader + Scroll + Webtoon Merge
// @namespace    yanmaga-downloader
// @version      1.2
// @description  Descarga capítulos en yanmaga.jp con scroll automático y opción de merge como webtoon
// @author       
// @license      MIT
// @match        https://yanmaga.jp/viewer/*
// @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
// ==/UserScript==

(function() {
    'use strict';

    // Espera hasta que carguen las imágenes
    const init = () => {
        const imgs = document.querySelectorAll('img');
        if (imgs.length === 0) return setTimeout(init, 500);
        createUI();
    };
    init();

    function createUI() {
        if (document.getElementById('yanmaga-download-ui')) return;

        const container = document.createElement('div');
        container.id = 'yanmaga-download-ui';
        Object.assign(container.style, {
            position: 'fixed', top: '10px', right: '10px',
            zIndex: 9999, display: 'flex', flexDirection: 'column', gap: '5px'
        });
        document.body.appendChild(container);

        const zipBtn = makeButton('📥 ZIP');
        const webBtn = makeButton('🖼️ Webtoon Merge');
        const scrollBtn = makeButton('⬇️ Auto Scroll');

        container.append(zipBtn, webBtn, scrollBtn);

        zipBtn.onclick = () => downloadZIP(zipBtn);
        webBtn.onclick = () => downloadWebtoon(webBtn);
        scrollBtn.onclick = () => autoScroll(scrollBtn);
    }

    function makeButton(text) {
        const btn = document.createElement('button');
        btn.textContent = text;
        Object.assign(btn.style, {
            background: '#e11d48', color: '#fff',
            padding: '8px 12px', border: 'none',
            borderRadius: '5px', cursor: 'pointer'
        });
        return btn;
    }

    async function downloadZIP(btn) {
        btn.disabled = true; btn.textContent = 'Descargando ZIP...';
        try {
            const imgs = document.querySelectorAll('img');
            const zip = new JSZip();
            let count = 0;
            for (const img of imgs) {
                const url = img.src;
                if (!url) continue;
                const blob = await fetch(url).then(r => r.blob());
                const name = String(++count).padStart(3, '0') + '.jpg';
                zip.file(name, blob);
                console.log(`Añadida ${name} — ${img.naturalWidth}×${img.naturalHeight}`);
            }
            const content = await zip.generateAsync({ type: 'blob' });
            saveAs(content, 'yanmaga_capitulo.zip');
            alert(`Listo: ${count} imágenes en ZIP`);
        } catch(e) {
            console.error(e);
            alert('Error al descargar ZIP');
        }
        btn.disabled = false; btn.textContent = '📥 ZIP';
    }

    async function downloadWebtoon(btn) {
        btn.disabled = true; btn.textContent = 'Generando imagen...';
        try {
            const imgs = [...document.querySelectorAll('img')];
            const bitmaps = await Promise.all(imgs.map(i => fetch(i.src).then(r => r.blob()).then(createImageBitmap)));
            const width = Math.max(...bitmaps.map(b => b.width));
            const height = bitmaps.reduce((a,b) => a + b.height, 0);
            const canvas = document.createElement('canvas');
            canvas.width = width;
            canvas.height = height;
            const ctx = canvas.getContext('2d');
            let y=0;
            for (const bm of bitmaps) {
                ctx.drawImage(bm, 0, y);
                y += bm.height;
            }
            canvas.toBlob(blob => saveAs(blob, 'yanmaga_webtoon.jpg'), 'image/jpeg', 1);
        } catch(e) {
            console.error(e);
            alert('Error al crear imagen webtoon');
        }
        btn.disabled = false; btn.textContent = '🖼️ Webtoon Merge';
    }

    function autoScroll(btn) {
        const imgs = [...document.querySelectorAll('img')];
        if (imgs.length === 0) return alert('No se detectaron imágenes.');
        btn.disabled = true;
        let i = 0;
        const scrollInterval = setInterval(() => {
            if (i >= imgs.length) {
                clearInterval(scrollInterval);
                btn.disabled = false;
                return;
            }
            imgs[i].scrollIntoView({ behavior: 'smooth' });
            i++;
        }, 800);
    }

})();