MangaPlus Blob Downloader

Descarga imágenes grandes del manga desde MangaPlus, capturando solo imágenes únicas de tipo Blob.

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         MangaPlus Blob Downloader
// @namespace    shadows
// @version      1.7.3
// @description  Descarga imágenes grandes del manga desde MangaPlus, capturando solo imágenes únicas de tipo Blob.
// @author       shadows
// @license      MIT
// @match        https://mangaplus.shueisha.co.jp/*
// @grant        GM_download
// ==/UserScript==

(function() {
    'use strict';

    let blobs = [];
    let imageHashes = new Set();  // Para hacer seguimiento de imágenes únicas por hash
    let downloadedCount = 0;

    // Función para calcular hash a partir de un blob
    async function hashBlob(blob) {
        const arrayBuffer = await blob.arrayBuffer();
        const hashBuffer = await crypto.subtle.digest('SHA-256', arrayBuffer);
        const hashArray = Array.from(new Uint8Array(hashBuffer));
        const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
        return hashHex;
    }

    // Función para guardar blobs como archivos PNG
    function saveBlob(blob, filename) {
        const blobUrl = URL.createObjectURL(blob);
        GM_download({
            url: blobUrl,
            name: filename,
            saveAs: false
        });
    }

    // Función para descargar las imágenes una por una
    function downloadSequentially(index) {
        if (index >= blobs.length) {
            alert(`Descargadas todas las ${blobs.length} imágenes.`);
            return;
        }

        const filename = `pagina-${index + 1}.png`;
        const blob = blobs[index];
        saveBlob(blob, filename);
        downloadedCount++;

        console.log(`Descargada ${filename}`);

        setTimeout(() => {
            downloadSequentially(index + 1);
        }, 1000);  // 1 segundo de retraso entre descargas
    }

    // Función para descargar todas las imágenes almacenadas en blobs
    function downloadImages() {
        if (blobs.length === 0) {
            alert("No se encontraron imágenes. Intenta desplazarte manualmente y vuelve a intentarlo.");
            return;
        }

        downloadedCount = 0;
        downloadSequentially(0);
    }

    // Interceptar la creación de URL para Blob y almacenar blobs únicos
    const originalCreateObjectURL = URL.createObjectURL;
    URL.createObjectURL = function(blob) {
        const url = originalCreateObjectURL(blob);
        if (blob.type.startsWith('image/')) {
            hashBlob(blob).then(hash => {
                if (!imageHashes.has(hash)) {  // Verificar si el hash es único
                    blobs.push(blob);  // Guardar el blob único
                    imageHashes.add(hash);  // Añadir hash al conjunto
                    console.log(`Capturado blob de imagen único: ${url} (hash: ${hash})`);
                } else {
                    console.log(`Blob de imagen duplicado omitido: ${url} (hash: ${hash})`);
                }
            });
        }
        return url;
    };

    // Crear un botón para descargar
    function createDownloadButton() {
        const button = document.createElement('button');
        button.innerText = "Descargar todas las imágenes";
        button.style.position = 'fixed';
        button.style.top = '10px';
        button.style.right = '10px';
        button.style.zIndex = '9999';
        button.style.padding = '10px 20px';
        button.style.backgroundColor = '#28a745';
        button.style.color = 'white';
        button.style.border = 'none';
        button.style.borderRadius = '5px';
        button.style.fontSize = '16px';
        button.style.fontWeight = 'bold';
        button.style.cursor = 'pointer';
        button.style.boxShadow = '0 4px 6px rgba(0,0,0,0.1)';
        document.body.appendChild(button);

        button.addEventListener('click', () => {
            console.log("Botón de descarga pulsado");
            downloadImages();
        });
    }

    // Comprobar si la página está lista y crear el botón
    const interval = setInterval(() => {
        if (document.readyState === "complete") {
            clearInterval(interval);
            console.log("Página completamente cargada, inicializando script.");
            createDownloadButton();
        }
    }, 1000);
})();