网页漫画下载为epub/mobi/pdf等电子书格式

将网页漫画下载下来方便导入墨水屏电子书进行阅读

当前为 2024-11-15 提交的版本,查看 最新版本

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

You will need to install an extension such as Tampermonkey to install this script.

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         网页漫画下载为epub/mobi/pdf等电子书格式
// @namespace    http://tampermonkey.net/
// @version      1.1.0
// @description  将网页漫画下载下来方便导入墨水屏电子书进行阅读
// @author       MornLight
// @match        https://m.rumanhua.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=greasyfork.org
// @grant        GM_xmlhttpRequest
// @require      https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js
// @run-at       document-end
// @license      MIT
// @supportURL   https://duanmorningsir.github.io/
// ==/UserScript==

(function () {
    'use strict';

    // 创建下载按钮和输入框
    function createDownloadButton() {
        const container = document.createElement('div');
        container.style.position = 'fixed';
        container.style.bottom = '20px';
        container.style.right = '20px';
        container.style.zIndex = '1000';
        container.style.display = 'flex';
        container.style.flexDirection = 'column';
        container.style.gap = '12px';
        container.style.backgroundColor = 'rgba(255, 255, 255, 0.9)';
        container.style.padding = '15px';
        container.style.borderRadius = '5px';
        container.style.boxShadow = '0 0 10px rgba(0,0,0,0.1)';

        // 获取总页数
        const totalPages = document.querySelectorAll('div.chapter-img-box').length;

        // 起始页输入框
        const startInput = document.createElement('input');
        startInput.type = 'number';
        startInput.min = '1';
        startInput.max = totalPages;
        startInput.value = '1';
        startInput.placeholder = `起始页(1-${totalPages})`;
        startInput.style.width = '120px';
        startInput.style.padding = '8px';
        startInput.style.border = '1px solid #ccc';
        startInput.style.borderRadius = '5px';
        startInput.style.textAlign = 'center';
        startInput.style.fontSize = '14px';

        // 结束页输入框
        const endInput = document.createElement('input');
        endInput.type = 'number';
        endInput.min = '1';
        endInput.max = totalPages;
        endInput.value = totalPages; // 默认设为最大页数
        endInput.placeholder = `结束页(1-${totalPages})`;
        endInput.style.width = '120px';
        endInput.style.padding = '8px';
        endInput.style.border = '1px solid #ccc';
        endInput.style.borderRadius = '5px';
        endInput.style.textAlign = 'center';
        endInput.style.fontSize = '14px';

        // 添加输入验证
        startInput.addEventListener('change', () => {
            const startVal = parseInt(startInput.value);
            const endVal = parseInt(endInput.value);

            if (startVal < 1) {
                alert('起始页不能小于1');
                startInput.value = '1';
            } else if (startVal > totalPages) {
                alert(`起始页不能大于总页数${totalPages}`);
                startInput.value = '1';
            } else if (startVal > endVal) {
                alert('起始页不能大于结束页');
                startInput.value = endVal;
            }
        });

        endInput.addEventListener('change', () => {
            const startVal = parseInt(startInput.value);
            const endVal = parseInt(endInput.value);

            if (endVal > totalPages) {
                alert(`结束页不能大于总页数${totalPages}`);
                endInput.value = totalPages;
            } else if (endVal < startVal) {
                alert('结束页不能小于起始页');
                endInput.value = startVal;
            }
        });

        // 下载按钮
        const downloadButton = document.createElement('button');
        downloadButton.textContent = '下载指定范围漫画';
        downloadButton.style.padding = '10px';
        downloadButton.style.backgroundColor = '#007bff';
        downloadButton.style.color = '#fff';
        downloadButton.style.border = 'none';
        downloadButton.style.borderRadius = '5px';
        downloadButton.style.cursor = 'pointer';

        // 全部下载按钮
        const downloadAllButton = document.createElement('button');
        downloadAllButton.textContent = '下载整个章节';
        downloadAllButton.style.padding = '10px';
        downloadAllButton.style.backgroundColor = '#28a745';
        downloadAllButton.style.color = '#fff';
        downloadAllButton.style.border = 'none';
        downloadAllButton.style.borderRadius = '5px';
        downloadAllButton.style.cursor = 'pointer';

        // 添加事件监听
        downloadButton.addEventListener('click', () => downloadComic(startInput.value, endInput.value));
        downloadAllButton.addEventListener('click', () => downloadComic());

        container.appendChild(startInput);
        container.appendChild(endInput);
        container.appendChild(downloadButton);
        container.appendChild(downloadAllButton);
        document.body.appendChild(container);
    }

    // 获取章节名称
    function getChapterName() {
        const chapterNameElement = document.querySelector('.chaphead-name h1');
        return chapterNameElement ? chapterNameElement.textContent.trim() : '未知章节';
    }

    // 下载漫画
    async function downloadComic(startPage, endPage) {
        const chapterName = getChapterName();
        const chapterImgBoxes = document.querySelectorAll('div.chapter-img-box');
        const totalPages = chapterImgBoxes.length;

        // 确定起始和结束页
        const start = startPage ? parseInt(startPage, 10) : 1;
        const end = endPage ? parseInt(endPage, 10) : totalPages;

        // 验证页数
        if (start > end || start < 1 || end > totalPages) {
            alert(`请输入有效的页数范围!(1-${totalPages})`);
            return;
        }

        // 创建 PDF 实例
        const pdf = new jspdf.jsPDF();

        // 并行下载图片
        const downloadPromises = [];
        chapterImgBoxes.forEach((box, index) => {
            // 只下载指定范围内的图片
            if (index + 1 >= start && index + 1 <= end) {
                const img = box.querySelector('img');
                if (img && img.dataset.src) {
                    const imgUrl = img.dataset.src;
                    downloadPromises.push(downloadImage(imgUrl, index - start + 1, pdf, end - start + 1));
                }
            }
        });

        // 等待所有图片下载完成
        await Promise.all(downloadPromises);

        // 保存 PDF 文件
        const fileName = end === chapterImgBoxes.length && start === 1
            ? `${chapterName}_全部.pdf`
            : `${chapterName}_${start}-${end}.pdf`;
        pdf.save(fileName);

        // 显示下载完成的提示
        alert(`漫画《${chapterName}》第${start}至${end}页下载完成!`);
    }

    // 下载图片并添加到 PDF
    function downloadImage(url, index, pdf, maxImages) {
        return new Promise((resolve, reject) => {
            GM_xmlhttpRequest({
                method: 'GET',
                url: url,
                responseType: 'blob',
                onload: function (response) {
                    try {
                        const blob = response.response;
                        const reader = new FileReader();
                        reader.onload = function (event) {
                            const imgData = event.target.result;
                            pdf.addImage(imgData, 'JPEG', 0, 0, pdf.internal.pageSize.getWidth(), pdf.internal.pageSize.getHeight());
                            if (index < maxImages - 1) {
                                pdf.addPage();
                            }
                            resolve();
                        };
                        reader.readAsDataURL(blob);
                    } catch (error) {
                        console.error('处理图片时出错:', error);
                        reject(error);
                    }
                },
                onerror: function (error) {
                    console.error('下载图片失败:', error);
                    reject(error);
                }
            });
        });
    }


    // 创建下载按钮和输入框
    createDownloadButton();
})();