Greasy Fork

Greasy Fork is available in English.

Rumanhua Downloader Turbo V12.2

Tải nhanh ZIP cho rumanhua2.com, nén ổn định, đặt tên chuẩn.

当前为 2026-01-11 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Rumanhua Downloader Turbo V12.2
// @namespace    rumanhua-downloader
// @version      12.2
// @description  Tải nhanh ZIP cho rumanhua2.com, nén ổn định, đặt tên chuẩn.
// @author       User
// @match        *://m.rumanhua2.com/*/*
// @match        *://www.rumanhua2.com/*/*
// @grant        GM_xmlhttpRequest
// @connect      *
// @require      https://cdn.jsdelivr.net/npm/@zip.js/[email protected]/dist/zip.min.js
// ==/UserScript==

(function () {
    'use strict';

    const PARALLEL_DOWNLOADS = 10;

    // --- UI ---
    const ui = document.createElement('div');
    ui.style = "position: fixed; right: 20px; bottom: 20px; z-index: 999999;";
    document.body.appendChild(ui);

    const btn = document.createElement('button');
    btn.innerHTML = '⚡ TẢI ZIP RUMANHUA';
    btn.style = "padding: 15px 25px; background: #e67e22; color: white; border: none; border-radius: 8px; font-weight: bold; cursor: pointer; box-shadow: 0 4px 15px rgba(0,0,0,0.3); font-family: sans-serif;";
    ui.appendChild(btn);

    const status = document.createElement('div');
    status.style = "position: fixed; top: 15px; left: 50%; transform: translateX(-50%); background: #fff; color: #e67e22; padding: 10px 25px; border-radius: 10px; border: 3px solid #e67e22; font-weight: bold; font-family: sans-serif; font-size: 18px; display: none; z-index: 1000000; box-shadow: 0 5px 15px rgba(0,0,0,0.2);";
    document.body.appendChild(status);

    const log = (txt) => { status.style.display = 'block'; status.innerHTML = txt; };

    // --- HÀM LẤY TÊN FILE CHUẨN (Rumanhua2) ---
    function getCleanFileName() {
        try {
            // Rumanhua thường có dạng: 《Tên Truyện》Số Chap - Tên Web
            let fullTitle = document.title;
            let mangaName = "Manga";
            let chapterName = "Chapter";

            // Tách tên truyện nằm trong dấu 《 》
            let matchManga = fullTitle.match(/《(.+?)》/);
            if (matchManga) {
                mangaName = matchManga[1];
            }

            // Tách số chương (thường nằm sau dấu 》 và trước dấu -)
            let matchChap = fullTitle.match(/》(.+?)\s*-/);
            if (matchChap) {
                chapterName = matchChap[1].trim();
            } else {
                // Dự phòng nếu không có dấu gạch ngang
                chapterName = fullTitle.split('》')[1]?.trim() || "Chap";
            }

            return `${mangaName}_${chapterName}`.replace(/[\\/:*?"<>|]+/g, "_").replace(/\s+/g, "_").trim();
        } catch (e) {
            return "Rumanhua_Download_" + Date.now();
        }
    }

    async function fetchImage(url) {
        return new Promise((resolve, reject) => {
            GM_xmlhttpRequest({
                method: 'GET', url: url, responseType: 'arraybuffer',
                onload: (res) => resolve(res.response),
                onerror: (err) => reject(err)
            });
        });
    }

    btn.onclick = async () => {
        // Quét ảnh trong vùng nội dung truyện
        const imgTags = document.querySelectorAll('img');
        let urls = [];

        imgTags.forEach(img => {
            // Rumanhua thường dùng data-src, v-lazy hoặc src trực tiếp
            const src = img.getAttribute('data-src') ||
                        img.getAttribute('data-original') ||
                        img.getAttribute('v-lazy') ||
                        img.src;

            if (src) {
                // Chỉ lấy ảnh có định dạng ảnh và không phải logo/icon rác
                const isImg = src.match(/\.(jpg|jpeg|png|webp|avif)/i);
                const notTrash = !src.includes('logo') && !src.includes('icon') && !src.includes('loading');

                if (isImg && notTrash) {
                    // Chuyển link tương đối thành tuyệt đối nếu cần
                    urls.push(new URL(src, location.href).href);
                }
            }
        });

        urls = [...new Set(urls)];

        if (urls.length === 0) {
            alert("❌ Không tìm thấy ảnh. Hãy chắc chắn bạn đã kéo xuống hết chương!");
            return;
        }

        btn.disabled = true;
        btn.style.background = '#bdc3c7';
        log("🚀 Bắt đầu tải Rumanhua...");

        const zipWriter = new zip.ZipWriter(new zip.BlobWriter("application/zip"));
        let completed = 0;
        let index = 0;

        const worker = async () => {
            while (index < urls.length) {
                const i = index++;
                const url = urls[i];
                try {
                    const data = await fetchImage(url);
                    const ext = url.split('.').pop().split('?')[0] || 'jpg';
                    const name = `${String(i + 1).padStart(3, '0')}.${ext}`;
                    await zipWriter.add(name, new zip.Uint8ArrayReader(new Uint8Array(data)));
                    completed++;
                    log(`📥 Đang nạp: ${completed} / ${urls.length}`);
                } catch (e) {
                    completed++;
                    console.error("Lỗi ảnh:", url);
                }
            }
        };

        await Promise.all(Array(PARALLEL_DOWNLOADS).fill(null).map(worker));

        log("📦 Đang xuất file ZIP...");
        try {
            const zipBlob = await zipWriter.close();
            const a = document.createElement("a");
            a.href = URL.createObjectURL(zipBlob);
            a.download = `${getCleanFileName()}.zip`;
            document.body.appendChild(a);
            a.click();

            setTimeout(() => {
                a.remove();
                URL.revokeObjectURL(a.href);
                log("✅ HOÀN TẤT!");
                btn.disabled = false;
                btn.style.background = '#e67e22';
                setTimeout(() => { status.style.display = 'none'; }, 3000);
            }, 1000);

        } catch (err) {
            alert("Lỗi nén ZIP: " + err.message);
            btn.disabled = false;
            btn.style.background = '#e67e22';
        }
    };
})();// ==UserScript==
// @name         New Userscript
// @namespace    http://tampermonkey.net/
// @version      2026-01-11
// @description  try to take over the world!
// @author       You
// @match        http://www.rumanhua2.com/TRrzzco/IdXVXgXq.html
// @icon         https://www.google.com/s2/favicons?sz=64&domain=rumanhua2.com
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    // Your code here...
})();