Greasy Fork

Greasy Fork is available in English.

hlib图书馆下载

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==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();
})();