Skip to content

Repository files navigation

epubforge

把杂乱的 TXT 小说转成规范的 EPUB 3 —— 真目录、真元数据、真排版。

CI Release License

English: README.en.md

一个命令,把这样的文件:

仙逆.txt   13 MB · GB18030 编码 · 夹杂广告水印 · 没有元数据

变成这样的电子书:

仙逆 - 耳根.epub   1198 章两级目录 · 完整元数据 · 官方封面 · 通过 EPUB 规范校验

目录


安装

Releases 下载对应平台的压缩包。解压即用,没有任何运行时依赖,不需要装 Python、Java 或别的东西。

下面的命令里 v0.1.0 是版本号,请替换成 Releases 页面 上的最新版本。

macOS

# Apple Silicon(M1/M2/M3/M4)
curl -LO https://github.com/shinycheng/epubforge/releases/download/v0.1.0/epubforge-v0.1.0-aarch64-apple-darwin.tar.gz
tar xzf epubforge-v0.1.0-aarch64-apple-darwin.tar.gz

# Intel Mac 把上面的 aarch64 换成 x86_64

# 首次运行会被 Gatekeeper 拦下,解除隔离标记:
xattr -d com.apple.quarantine ./epubforge

# 装到 PATH 里,以后任何目录都能直接用
sudo mv epubforge /usr/local/bin/
epubforge --version

Windows

  1. 下载 epubforge-v0.1.0-x86_64-pc-windows-msvc.zip(ARM 版 Windows 用 aarch64-...zip
  2. 解压,得到 epubforge.exe
  3. epubforge.exe 和你的 txt 放同一个文件夹
  4. 在该文件夹地址栏输入 powershell 回车,然后:
.\epubforge.exe "我的小说.txt"

想在任意目录使用,把 exe 所在文件夹加进系统环境变量 Path

Linux

# x86_64,静态链接版,任何发行版都能跑
curl -LO https://github.com/shinycheng/epubforge/releases/download/v0.1.0/epubforge-v0.1.0-x86_64-unknown-linux-musl.tar.gz
tar xzf epubforge-v0.1.0-x86_64-unknown-linux-musl.tar.gz
chmod +x epubforge
sudo mv epubforge /usr/local/bin/

ARM64 机器(树莓派 64 位、AWS Graviton)用 aarch64-unknown-linux-musl

Docker

不想装东西就用这个:

docker run --rm -v "$PWD:/work" ghcr.io/shinycheng/epubforge 我的小说.txt

-v "$PWD:/work" 把当前目录挂进容器,转换结果会出现在当前目录。镜像里预装了中文字体,封面能正常渲染。

从源码编译

cargo install --git https://github.com/shinycheng/epubforge

验证下载完整性

每个压缩包都配了 .sha256 校验文件:

shasum -a 256 -c epubforge-v0.1.0-aarch64-apple-darwin.sha256

五分钟上手

第一步:直接转换

把 txt 拖到某个文件夹,然后:

epubforge 我的小说.txt

就这样。EPUB 会生成在和 txt 相同的目录,文件名是 书名 - 作者.epub

想指定输出目录:

epubforge 我的小说.txt -o ~/Books

第二步:转换前先看看

转换是有损的 —— 会删广告、合并换行、切分章节。在正式转换前,先用 inspect 预览它打算怎么处理,这一步不产生任何文件:

epubforge inspect 我的小说.txt

想看更详细的(全部被删除的行、更多章节预览、编码候选打分):

epubforge inspect 我的小说.txt -v

如果预览结果不对(章节数明显不对、正文被删了),先按下面 常见任务 里的方法调整参数,别急着转。

第三步:补全元数据

TXT 里通常只有书名,作者都未必有。加 --scrape 联网补齐简介、标签、完结状态和官方封面:

epubforge 我的小说.txt --scrape

它会搜索并列出候选让你选。不想被打断就加 --scrape-auto 自动采用最佳匹配。

这就是全部日常用法了。 下面是各种具体情况的处理方法。


看懂转换报告

每次转换都会打印一份报告。逐行解释:

📖 《仙逆》 — 耳根
  编码  gb18030  置信度 100%
  清洗  清除广告 101 行 / 64 类 · 折叠空行 107
  结构  1198 章  [cn-chapter] · 6,449,219 字
  刮削  qidian · 仙逆 / 耳根  匹配度 72
        补全 作者·日期·简介·标签 · 封面已下载
  输出  仙逆 - 耳根.epub  (8.8 MB, 1207 个条目)
  校验  通过(检查了 1203 个文档)
  提示  章节序号有 30 处跳号(52→62, 64→71...),源文件可能缺章
  耗时  4.64s
含义 什么时候该警觉
编码 识别出的原文编码和把握程度 置信度低于 70% 会标黄;出现「N 个字符无法解码」说明有乱码,试试 --encoding 手动指定
清洗 删了多少广告、合并了多少硬换行 广告「类别数」远大于实际广告种类(比如 200 多类但每类只命中 1 次)→ 可能误删了正文,用 -v 查看被删的行
结构 切出多少卷/章,用的哪个识别模式,总字数 章节数明显不对,或出现「未识别到标题,已按字数切分」→ 需要自定义正则
刮削 匹配到的书、补全了哪些字段 「未应用」说明没找到足够可信的匹配,可以用 --scrape-url 直接指定
输出 文件路径和大小 ——
校验 产物是否符合 EPUB 规范 出现「错误」说明产物有问题,请提 issue
提示 各类警告 跳号通常是源文件本身缺章,不是工具的问题

inspect -v 还会额外显示:

  章节模式打分
   ✔ cn-chapter        1198 处  得分 0.822  序号连续度 98%  平均 5,386 字
     num-only           312 处  得分 0.000  已排除:匹配过于密集,疑似匹配到正文

这是章节识别的决策过程 —— 打勾的是选中的模式,被排除的会说明原因。识别错了就看这里,能直接看出是哪个模式赢了、为什么。


常见任务

批量转换整个书库

# 转换目录下所有 txt(不含子目录)
epubforge ./小说 -o ./epub输出

# 递归处理子目录
epubforge ./小说 -r -o ./epub输出

# 限制并行数(默认按 CPU 核数)
epubforge ./小说 -r -o ./epub输出 -j 4

已存在的输出文件会被跳过,不会覆盖。要重新生成加 -f

epubforge ./小说 -r -o ./epub输出 -f

批量质检,只挑出有问题的:

epubforge ./小说 -r --json | jq '.[] | select(.outputs[].errors > 0)'

联网补全元数据

# 用推断出的书名+作者搜索
epubforge 我的小说.txt --scrape

# txt 里没有书名作者,自己指定(同时作为搜索词)
epubforge 未知.txt --scrape --title "仙逆" --author "耳根"

# 搜索匹配不准,直接给书籍页链接
epubforge 我的小说.txt --scrape-url "https://www.qidian.com/book/1209977/"

# 批量:不询问,自动采用最佳匹配
epubforge ./小说 -r --scrape --scrape-auto

# 只要元数据,不要下载封面(用自动生成的)
epubforge 我的小说.txt --scrape --no-cover-download

补全的字段:作者、简介、分类标签、完结状态、更新日期、封面

几个要点:

  • 刮到的值只填空缺。你在命令行或配置文件里指定的任何字段都不会被覆盖。
  • 单本转换且在终端里会列出候选让你选;批量或加 --scrape-auto 则自动。
  • --scrape-url 支持起点的各种链接形式,也支持任何实现了 og:novel 标准的小说站(大部分中文小说站都实现了)。
  • 默认两次请求间隔 1.5 秒,--scrape-delay 3000 可以调慢。
  • 失败不影响转换 —— 网络不通、搜不到,照常出 EPUB,只在报告里写一行。

章节识别不对

先用 inspect -v 看模式打分,判断是哪种情况。

情况一:识别出的章节数明显偏少或为 0

你的 txt 用了非常规的章节标题格式。用 --chapter-pattern 给一条正则:

# 假设你的章节标题长这样:◆◆◆ 12 ◆◆◆
epubforge book.txt --chapter-pattern '^\s*◆◆◆\s*(?P<num>\d+)\s*◆◆◆\s*$'

# 长这样:☆、第一章 相遇
epubforge book.txt --chapter-pattern '^\s*☆、第(?P<num>[一二三四五六七八九十百千]+)章\s*(?P<title>.*)$'

命名捕获组 num(序号)和 title(标题)会被使用,num 用于检测跳号。

想完全弃用内置模式库、只用你的:加 --only-custom-patterns

情况二:正文中的句子被误当成章节标题

正常情况下打分机制会排除它们。如果还是发生了,收紧标题宽度限制(配置文件里的 max_heading_width),或者用 --chapter-pattern 给一条更严格的正则。

情况三:完全识别不出章节

默认会按字数切分成若干「节」,保证阅读器还能正常翻页。想改变这个行为:

epubforge book.txt --fallback single   # 整本作为一章
epubforge book.txt --fallback fail     # 直接报错,不生成文件

情况四:不想要卷结构

epubforge book.txt --no-volumes    # 输出单级目录

编码乱码

工具会自动检测编码,覆盖 UTF-8 / UTF-16 / GB18030 / Big5 / Shift_JIS / EUC-KR 等。如果报告里置信度很低或出现乱码:

epubforge book.txt --encoding gbk        # 简体中文常见
epubforge book.txt --encoding big5       # 繁体中文常见
epubforge book.txt --encoding utf-16le

inspect -v 会列出所有编码候选和它们的得分,能看出第二名是谁:

  编码候选
    gb18030      得分 1.040  替换字符 0
    Big5         得分 0.780  替换字符 2926
    EUC-KR       得分 0.432  替换字符 3979
    UTF-8        得分 0.000  替换字符 152311

「替换字符」是解码失败留下的 的个数 —— 数量越大越说明这个编码是错的。

广告没清干净 / 清过头了

没清干净 —— 加自己的规则。在 txt 同目录建 epubforge.toml

[clean]
extra_ad_patterns = [
  '本文首发于.*论坛',
  '^\s*订阅本章.*$',
]

清过头了(正文被删) —— 先用 -v 确认删了什么:

epubforge inspect book.txt -v

把误删的内容加进白名单:

[clean]
keep_patterns = ['未完待续']

或者干脆关掉广告清除:

epubforge book.txt --no-ads

内置规则刻意保守。曾经有一条规则会命中任何在结尾附近出现「制作/整理/校对」的行 —— 这些是普通动词,在修仙题材里满篇都是,结果删掉了上万字正文。那条规则已经整个移除。准则是:留下一条广告是瑕疵,删掉一段正文是数据丢失。

封面

# 默认:按书名确定性生成一张(同一本书永远同一张)
epubforge book.txt

# 用自己的图
epubforge book.txt --cover 封面.jpg

# 联网下载官方封面
epubforge book.txt --scrape

# 不要封面
epubforge book.txt --no-cover

排版

内置样式表只定义结构,不定义外观 —— 不设字体、字号、颜色,全部交给阅读器,所以暗色模式自动就是对的。

想完全替换样式:

epubforge book.txt --css 我的样式.css

想在内置样式基础上追加,用配置文件:

[output]
extra_css = "p { line-height: 1.9; }"

其他排版相关开关:

epubforge book.txt --no-title-page   # 不生成书名页
epubforge book.txt --no-epub2        # 不生成 toc.ncx(放弃老设备兼容)

繁简转换

epubforge book.txt --convert-to hant   # 转繁体
epubforge book.txt --convert-to hans   # 转简体
epubforge book.txt --convert-to tw     # 繁体 + 台湾用词
epubforge book.txt --convert-to hk     # 繁体 + 香港用词
epubforge book.txt --convert-to cn     # 简体 + 大陆用词

是词汇级转换,不是简单的字符映射(「滑鼠」↔「鼠标」这类会正确处理)。

分卷输出与文件名

# 每卷输出一个独立 EPUB,自动关联成系列
epubforge book.txt --split-volumes

# 自定义文件名
epubforge book.txt --filename "{author} - {title}"
epubforge book.txt --filename "{series}{series_index} {title}"

可用占位符:{title} {author} {series} {series_index} {stem}(原文件名)。


配置文件

命令行参数适合临时调整。整个书库的固定设置放配置文件更方便。

生成一份带完整注释的模板:

epubforge init

放在 txt 同目录,命名规则:

文件名 作用范围
epubforge.toml 该目录下所有 txt
我的小说.epubforge.toml 只对 我的小说.txt 生效

优先级从低到高:预设 → 配置文件 → 命令行参数

profile = "webnovel"    # webnovel | published | lightnovel | raw

[meta]
series = "山海三部曲"
series_index = 1
tags = ["玄幻", "完结"]

[clean]
join_hard_wraps = "auto"           # auto | always | never
extra_ad_patterns = ['本文首发于.*论坛']
keep_patterns = ['未完待续']        # 白名单,永不当作广告
convert = "none"                   # none | hans | hant | tw | hk | cn

[detect]
volumes = true
min_chapter_chars = 150
max_heading_width = 60
fallback = "split"                 # split | single | fail

[output]
filename = "{title} - {author}"
cover = "auto"                     # "auto" | "none" | { file = "cover.jpg" }
epub2_compat = true
split_volumes = false

四个预设

--profile 或配置文件里的 profile 选择:

预设 适用 行为
webnovel 网络小说(默认) 全部清洗开启,识别卷/章两级结构
published 出版书 不合并换行(尊重原排版),广告阈值放宽
lightnovel 轻小说 允许更短的章节
raw 只要结构 不清广告、不改标点、不合并换行

参数速查

输入输出

参数 说明
-o, --output-dir <DIR> 输出目录,默认与输入同目录
--filename <模板> 文件名模板
-r, --recursive 递归处理子目录
-j, --jobs <N> 并行任务数
-f, --force 覆盖已存在的输出

元数据

参数 说明
--title --author 书名、作者(也用作刮削搜索词)
--description --publisher 简介、出版方
--series --series-index <N> 系列名、系列序号
--tags <标签,标签> 标签,逗号分隔
--language <BCP47> 语言标记,如 zh-Hans

联网刮削

参数 说明
--scrape 开启联网补全元数据
--scrape-url <URL> 直接指定书籍链接,跳过搜索
--scrape-auto 不询问,采用最佳匹配
--no-cover-download 不下载官方封面
--scrape-delay <毫秒> 请求间隔,默认 1500

文本处理

参数 说明
--encoding <标签> 强制指定输入编码
--no-ads 不清除广告行
--join-wraps <auto|always|never> 硬换行合并策略
--no-punctuation 不做标点规范化
--convert-to <变体> 繁简转换

结构识别

参数 说明
--chapter-pattern <正则> 自定义章节标题正则,可重复
--volume-pattern <正则> 自定义卷标题正则,可重复
--only-custom-patterns 忽略内置模式库
--no-volumes 不识别卷结构
--fallback <split|single|fail> 识别不到章节时的处理

产物

参数 说明
--cover <文件> / --no-cover 指定封面 / 不要封面
--css <文件> 替换内置样式表
--split-volumes 每卷一个 EPUB
--no-title-page --no-epub2 不生成书名页 / toc.ncx
--no-validate --epubcheck 跳过校验 / 额外调用 epubcheck

其他

参数 说明
--config <文件> 指定配置文件
--profile <预设> 选择预设
-v -q --json 详细 / 静默 / JSON 输出

退出码0 成功 · 1 转换失败 · 2 转换成功但校验有错误(适合 CI 使用)


疑难排查

转出来全是乱码 → 编码识别错了。epubforge inspect book.txt -v 看编码候选,然后 --encoding gbk--encoding big5 手动指定。

目录里只有一条「第 1 节」 → 没识别出章节标题,退回按字数切分了。用 inspect -v 看模式打分,然后用 --chapter-pattern 给一条自定义正则。

正文缺了一段 → 被当成广告删了。inspect -v 会列出所有被删除的行,把误删的内容加进配置文件的 keep_patterns,或者 --no-ads 关掉。

目录里章节标题都是「第一章」没有标题内容 → 你的 txt 本身就是这样。工具不会凭空补标题。

报告说「章节序号有 N 处跳号」 → 源文件缺章。这是提示不是错误,通常是盗版打包本身不全。

每段之间没有空行,挤在一起 → 这是中文电子书的正常排版(首行缩进两字、段间无空行)。想改用配置文件的 extra_cssp { margin-bottom: 0.6em }

macOS 提示「无法打开,因为无法验证开发者」xattr -d com.apple.quarantine ./epubforge

刮削一直失败 → 检查网络能否访问目标站点。也可能是站点结构变了 —— 这种情况刮削会失败但转换照常完成。可以改用 --scrape-url 直接给链接。

封面上的中文是方块 → 系统缺中文字体。工具会自动降级为 SVG 封面。装个中文字体,或用 --cover 指定图片。


工作原理

一句话版本:每一步都能解释自己的决定,宁可少做也不猜。

读入 → 编码识别 → 元数据推断 → 清洗 → 结构识别 → [联网补全] → 生成 EPUB → 校验
  • 编码识别:用每种候选编码解一遍,给解码结果打分(乱码有明显指纹),比从字节猜可靠。
  • 清洗:统计检测硬折行并还原段落;广告用规则库 + 高频重复识别,每一条删除都写进报告。
  • 结构识别:不是一条正则,而是一个模式库,按产出结果打分择优(序号是否连续、章节是否均匀、是否覆盖全文)。
  • 元数据:文件名 → 正文头部 → 刮削 → 配置文件 → 命令行,逐层覆盖,报告标注每项来源。
  • 排版:样式表只定义结构,字体字号颜色留给阅读器。
  • 校验:产物重新打开逐项检查,包括每个文档的 XML 良构性。

想看更细的设计取舍,见 CHANGELOG 的 Design notes 一节。


已知限制

  • 只吃纯文本,不解析 HTML / Markdown。
  • 不自动识别诗歌、书信块(误判率太高)。
  • 不做脚注配对([1] 与章末注释的关联)。
  • 插图只支持指定或下载的封面,不扫描同目录图片。
  • 不会用官方目录修正本地章节标题 —— 试过,真实书籍的序号跨卷重排、重复、缺号,不可靠,已移除。

开发

cargo test --all-features
cargo clippy --all-targets --all-features -- -D warnings
cargo fmt --all -- --check
cargo build --release

端到端测试会在内存里构造一个真实脏度的样本 —— GB18030 编码、抓取器头部、36 列硬折行、每章三种广告水印、三卷结构外加楔子和番外 —— 转换后逐项断言产物的容器结构、目录嵌套、元数据和正文内容。

src/
  encoding.rs   编码检测(候选打分)
  clean.rs      清洗管线
  detect.rs     章节与卷识别
  meta.rs       元数据推断
  book.rs       结构化数据模型
  cover.rs      封面生成
  epub.rs       EPUB 3 打包
  validate.rs   产物校验
  report.rs     报告渲染
  config.rs     配置与预设
  scrape/       联网刮削

License

MIT

About

txt - epub

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages