Greasy Fork

Greasy Fork is available in English.

hlib图书馆下载

自动下载小说网站的所有章节内容

当前为 2025-04-15 提交的版本,查看 最新版本

// ==UserScript==
// @name         hlib图书馆下载
// @namespace    http://tampermonkey.net/
// @version      1.2
// @license      MIT
// @description  自动下载小说网站的所有章节内容
// @author       liepainian
// @match        https://hlib.cc/n/*
// @grant        GM_xmlhttpRequest
// @grant        GM_download
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_addStyle
// @connect      hlib.cc
// ==/UserScript==

(function () {
  "use strict";

  // 添加下载按钮
  function addDownloadButton() {
    const btn = document.createElement("button");
    btn.id = "tm-download";
    btn.className = "btn btn-primary";
    btn.innerHTML = "📚 一键下载全集";
    btn.style.cssText = `
            position: fixed;
            bottom: 20px;
            right: 20px;
            z-index: 9999;
            box-shadow: 0 2px 5px rgba(0,0,0,0.2);
            padding: 12px 24px;
            font-size: 16px;
        `;
    btn.onclick = startDownload;

    document.body.appendChild(btn);
  }

  // 获取当前章节信息
  function getChapterInfo() {
    try {
      // 获取系列章节链接
      const seriesLinks = [...document.querySelectorAll("#s-pages a")].map((a) => new URL(a.href).pathname);

      // 获取当前章节信息
      const currentChapter = {
        title: document.title.replace(/- \d+$/, "").trim(),
        author: document.querySelector('.list-group-item a[href^="/u/"] span')?.textContent?.trim() || "未知作者",
        series: [...new Set(seriesLinks)], // 去重
        currentUrl: window.location.pathname,
      };

      // 如果当前页面不在系列列表中则添加
      if (!currentChapter.series.includes(currentChapter.currentUrl)) {
        currentChapter.series.unshift(currentChapter.currentUrl);
      }

      return currentChapter;
    } catch (error) {
      console.error("解析章节信息失败:", error);
      return null;
    }
  }

  // 获取单页内容
  async function fetchPageContent(url, page = 1) {
    const pageUrl = page > 1 ? `${url}?p=${page}` : url;

    return new Promise((resolve) => {
      GM_xmlhttpRequest({
        method: "GET",
        url: `https://hlib.cc${pageUrl}`,
        onload: function (response) {
          try {
            const parser = new DOMParser();
            const doc = parser.parseFromString(response.responseText, "text/html");

            // 解析分页信息
            const pageSelect = doc.querySelector("select.form-select");
            const totalPages = pageSelect ? Math.max(...[...pageSelect.options].map((o) => parseInt(o.value))) : 1;

            // 解析正文内容
            const content = doc.getElementById("content")?.innerText || "内容解析失败,请检查选择器";

            resolve({ content, totalPages });
          } catch (e) {
            resolve({ content: `获取页面失败: ${e.message}`, totalPages: 1 });
          }
        },
        onerror: () => resolve({ content: "请求失败,请检查网络", totalPages: 1 }),
      });
    });
  }

  // 下载整个章节
  async function downloadChapter(url) {
    let fullContent = "";
    let currentPage = 1;
    let totalPages = 1;

    do {
      const { content, totalPages: tp } = await fetchPageContent(url, currentPage);
      fullContent += `\n第 ${currentPage} 页\n${content}\n\n`;
      totalPages = tp;

      // 更新按钮进度
      const btn = document.getElementById("tm-download");
      if (btn) {
        btn.innerHTML = `📥 下载中 (${currentPage}/${totalPages})`;
      }

      currentPage++;
      await new Promise((r) => setTimeout(r, 800)); // 降低请求频率
    } while (currentPage <= totalPages);

    return fullContent;
  }

  // 主下载流程
  async function startDownload() {
    try {
      const info = getChapterInfo();
      if (!info) {
        alert("无法解析页面信息,请确认在正确的小说页面");
        return;
      }

      let fullText = `${info.title}\n作者:${info.author}\n\n`;

      for (const [index, chapterUrl] of info.series.entries()) {
        const chapterContent = await downloadChapter(chapterUrl);
        fullText += `\n\n第 ${index + 1} 章\n${chapterContent}`;
      }

      // 生成下载文件
      const blob = new Blob([fullText], { type: "text/plain;charset=utf-8" });
      const filename = `${info.title} - ${info.author}.txt`;

      GM_download({
        url: URL.createObjectURL(blob),
        name: filename,
        saveAs: true,
      });

      // 恢复按钮状态
      const btn = document.getElementById("tm-download");
      if (btn) {
        btn.innerHTML = "✅ 下载完成";
        setTimeout(() => btn.remove(), 3000);
      }
    } catch (error) {
      console.error("下载失败:", error);
      alert(`下载失败: ${error.message}`);
      const btn = document.getElementById("tm-download");
      if (btn) btn.innerHTML = "❌ 下载失败";
    }
  }

  // 启动脚本
  addDownloadButton();
})();