Files
fanqie-go/README.md
T
chenxin 7da9184937 🚀 deploy(build): 新增一键部署脚本与构建工具链
- 新增 deploy.sh:编译部署、systemd/Nginx 初始化、软链接版本管理与交互式回滚、部署后 /healthz 健康自检、certbot 自动申请 HTTPS 证书与续期重载 Hook
- 新增 .deploy.env.example 部署配置模板,.deploy.env(不入库)覆盖脚本默认值,路径默认由 APP_NAME 派生,CERT_EMAIL 默认 admin@域名
- 新增 Makefile:build / build-linux 交叉编译 / test(含 go vet)/ clean
- main.go 新增 Version/BuildTime 变量,使 -ldflags -X 注入生效并在启动日志打印
- systemd 工作目录改为代码目录,修复 config.yaml/.env/cache.db 相对路径加载失败
- .gitignore 忽略 .deploy.env 与 fanqie-* 编译产物;README 新增部署章节与 HTTPS 说明
2026-10-09 15:49:02 +08:00

446 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 番茄小说 API
Go 语言实现的番茄小说非官方 API 服务,完整实现了签名算法、设备注册、密钥管理等核心功能。
## 功能特性
### 核心功能
- **书籍搜索** - 关键词搜索,支持分页
- **书籍详情** - 获取书籍基本信息、封面、作者等
- **章节目录** - 获取完整章节列表
- **章节内容** - 获取正文内容,支持纯文本/HTML模式
- **批量接口** - 支持批量获取书籍详情和章节内容
### 内容类型
- 📖 小说/电子书
- 🎨 漫画
- 🎵 音频/有声书
- 🎬 视频
### 评论功能
- 章节段评(段落评论)
- 书籍书评
- 评论 HTML 渲染
### 分类体系
- 分类首页数据
- 分类详情页(支持筛选、排序、分页)
### 技术特性
- **签名算法** - Gorgon、8404、Argus、Ladon、Khronos
- **设备密钥池** - 多设备轮换、自动补充
- **多级缓存** - 正文/详情/目录等 24 小时缓存,搜索/分类短缓存;存储后端可选 SQLite / PostgreSQL / Redis
- **配置热更新** - 修改配置无需重启
- **访问控制** - AccessKey 验证(常量时间比较防时序攻击),可扩展保护全部业务接口
- **优雅退出** - 超时保护、信号驱动的平滑关闭
- **错误规范** - 统一 JSON 错误响应,缺参 400 / 服务端错误 500
## 项目结构
```tree
fanqie-go/
├── cmd/fanqie/ # 程序入口
│ └── main.go # 主函数,初始化服务
├── config/ # 配置文件
│ └── config.yaml # 配置文件
├── emoji/ # 表情图片静态资源
├── internal/
│ ├── algos/ # 签名算法实现
│ │ ├── gorgon.go # Gorgon 签名算法
│ │ ├── algo8404.go # 8404 签名算法
│ │ ├── argus.go # Argus 签名算法
│ │ ├── ladon.go # Ladon 签名算法
│ │ ├── signer.go # 签名管理器
│ │ ├── switcher.go # 算法切换器
│ │ ├── sm3.go # SM3 哈希算法
│ │ ├── simon.go # Simon 对称加密
│ │ ├── pkcs7.go # PKCS7 填充
│ │ ├── protobuf.go # Protobuf 协议
│ │ └── bytebuf.go # 字节缓冲区
│ ├── common/ # 公共工具
│ │ ├── logger.go # 日志工具
│ │ ├── http.go # HTTP 工具
│ │ └── utils.go # 通用工具
│ ├── config/ # 配置管理
│ │ ├── config.go # 配置加载
│ │ └── watcher.go # 配置热更新
│ ├── fqapi/ # API 封装层
│ │ ├── cache_manager.go # SQLite 缓存管理
│ │ ├── device_key_pool.go # 设备密钥池
│ │ ├── device_register.go # 设备注册
│ │ ├── register_key.go # 密钥注册
│ │ ├── dhcry.go # DH 加密交换
│ │ ├── ttencrypt.go # TTEncrypt 加密
│ │ ├── search.go # 搜索接口
│ │ ├── detail.go # 书籍详情
│ │ ├── catalog.go # 章节目录
│ │ ├── content.go # 章节内容
│ │ ├── multi_content.go # 批量内容
│ │ ├── multi_detail.go # 批量详情
│ │ ├── item_summary.go # 章节摘要
│ │ ├── category_front.go # 分类首页
│ │ ├── category_landing.go # 分类详情
│ │ ├── audio.go # 音频
│ │ ├── video.go # 视频
│ │ ├── manga.go # 漫画
│ │ ├── manga_proxy.go # 漫画代理
│ │ ├── review.go # 评论
│ │ ├── content_parser.go # 内容解析
│ │ ├── content_utils.go # 内容工具
│ │ ├── emoji.go # 表情管理
│ │ ├── device_config.go # 设备配置
│ │ └── gorgon_utils.go # Gorgon 请求封装
│ └── handlers/ # HTTP 处理器
│ ├── common.go # 通用处理
│ ├── book.go # 书籍接口
│ ├── content.go # 内容接口
│ ├── media.go # 媒体接口
│ ├── review.go # 评论接口
│ ├── category.go # 分类接口
│ ├── manga_proxy.go # 漫画代理
│ └── status.go # 状态页面
└── go.mod # Go 模块定义
```
## 快速开始
### 环境要求
- Go 1.25+
- SQLite3
### 安装运行
```bash
# 克隆项目
git clone https://github.com/cyqddx/fanqie-go.git
cd fanqie-go
# 运行服务
go run ./cmd/fanqie
```
服务默认启动在 `http://0.0.0.0:40180`
## API 接口文档
机器可读的完整接口定义见 [openapi.yaml](openapi.yaml)(OpenAPI 3.1,可直接导入 Swagger UI / Apifox / Postman)。
### 基础接口
| 接口 | 方法 | 说明 |
| ------ | ------ | ------ |
| `GET /` | GET | 服务首页 |
| `GET /healthz` | GET | 存活探针(不校验密钥,供容器/反代使用) |
| `GET /status` | GET | 服务状态(需 AccessKey) |
| `GET /self-info` | GET | 自我信息(需 AccessKey) |
| `POST /vacuum` | POST | 数据库压缩(需 AccessKey) |
### 书籍相关
| 接口 | 方法 | 说明 | 参数 |
| ------ | ------ | ------ | ------ |
| `/search` | GET | 搜索书籍 | `query`(或 `key`), `tab_type`, `offset`(`search_tabs` 仅返回匹配 `tab_type` 的 tab) |
| `/detail` | GET | 书籍详情 | `book_id` |
| `/info` | GET | 书籍详情(同 detail) | `book_id` |
| `/catalog` | GET | 章节目录 | `book_id` |
| `/directory/all_items` | GET | 章节目录(同 catalog) | `book_id` |
| `/multi-detail` | GET | 批量书籍详情 | `book_id`(逗号分隔) |
### 内容相关
| 接口 | 方法 | 说明 | 参数 |
| ------ | ------ | ------ | ------ |
| `/content` | GET | 章节内容 | `item_id` |
| `/multi-content` | GET | 批量章节内容 | `book_id`, `item_ids`(逗号分隔) |
| `/item-summary` | GET | 章节摘要 | `book_id`, `item_ids`(逗号分隔) |
### 评论相关
| 接口 | 方法 | 说明 | 参数 |
| ------ | ------ | ------ | ------ |
| `/chapter_review` | GET | 章节评论 | `book_id`, `item_id` |
| `/review` | GET | 书评列表 | `book_id`, `item_id`, `para`, `comment_id`, `offset`, `limit` |
| `/review_html` | GET | 评论 HTML | `book_id`, `item_id`, `para` |
### 分类相关
| 接口 | 方法 | 说明 | 参数 |
| ------ | ------ | ------ | ------ |
| `/category-front` | GET | 分类首页 | - |
| `/category-landing` | GET | 分类详情 | `category_id`, `word_number`, `book_status`, `sort_by`, `offset` |
### 媒体相关
| 接口 | 方法 | 说明 | 参数 |
| ------ | ------ | ------ | ------ |
| `/audio` | GET | 音频内容 | `item_ids`, `tone_id`, `output` |
| `/video` | GET | 视频内容 | `item_ids` |
| `/manga` | GET | 漫画内容 | `item_ids`(或 `item_id`), `show_html`, `output` |
| `/manga/image/{itemID}/{index}` | GET | 漫画图片 | 路径参数 |
## 内容获取示例
### 搜索书籍
```bash
GET http://localhost:40180/search?keyword=斗罗大陆
```
### 获取书籍详情
```bash
GET http://localhost:40180/detail?book_id=xxx
```
### 获取章节目录
```bash
GET http://localhost:40180/catalog?book_id=xxx
```
### 获取章节内容
```bash
GET http://localhost:40180/content?book_id=xxx&chapter_id=xxx
```
支持以下 URL 参数覆盖默认配置:
| 参数 | 说明 | 可选值 |
| ------ | ------ | ------ |
| `text_mode` | 文本模式 | `plain`(纯文本), `html`(HTML) |
| `img_mode` | 图片模式 | `remove`(移除), `keep`(保留) |
| `review_mode` | 评论模式 | `remove`(移除), `keep`(保留) |
### 批量获取
```bash
GET http://localhost:40180/multi-detail?book_ids=id1,id2,id3
GET http://localhost:40180/multi-content?chapter_ids=id1,id2,id3
```
## 配置说明
### 完整配置项
配置文件位于 `config/config.yaml`:
```yaml
# 服务器配置
server:
host: "0.0.0.0" # 监听地址
port: "40180" # 监听端口
access_key: "" # 访问密钥(可选)
protect_all: false # 业务接口也要求访问密钥(公网部署建议开启)
# 番茄小说配置
fanqie:
# 签名算法: "gorgon" / "8404"
algorithm: "gorgon"
# 签名方法:
# - "sign2": X-Gorgon + X-Khronos
# - "sign4": X-Gorgon + X-Ladon + X-Argus + X-Khronos
signature: "sign4"
# 内容处理
content:
remove_images: false # 移除图片
remove_image_desc: true # 移除图片描述
remove_blank_lines: true # 移除空行
remove_html_tags: true # 移除 HTML 标签
remove_chapter_title: true # 移除章节标题
add_paragraph_indent: false # 添加段落缩进
double_newline: false # 段落间双换行
enable_review: true # 启用段评
# 漫画处理
manga:
# 输出模式:
# - "proxy": 代理模式
# - "url": 直接返回图片 URL
# - "data_uri": Base64 编码
output_mode: "url"
# 缓存配置
cache:
enabled: true # 启用缓存
backend: sqlite # 存储后端: sqlite | postgres
sqlite_path: "./cache.db" # SQLite 路径(backend 为 sqlite 时使用)
# PostgreSQL连接配置(backend 为 postgres 时使用)
postgres:
host: "127.0.0.1" # 主机
port: 5432 # 端口
user: "postgres" # 用户名
password: "" # 密码
database: "fanqie" # 数据库名
sslmode: "disable" # SSL 模式: disable | prefer | require
redis: # Redis 缓存(正文缓存与音频代理缓存,统计数据/设备池仍在 SQL 库)
enabled: false
host: "127.0.0.1" # 主机
port: 6379 # 端口
password: "" # 密码
db: 0 # 数据库编号
cleanup_enabled: true # 启用自动清理
cleanup_seconds: 86400 # 清理间隔(秒)
# 设备密钥池
device_key_pool:
enabled: true # 启用设备池
initial_size: 20 # 初始设备数
min_size: 10 # 最小设备数
max_size: 30 # 最大设备数
```
### 敏感配置(.env)
密码等敏感值不建议写进 `config.yaml`(会进 git 历史)。复制 `.env.example` 为 `.env` 填入真实值即可,`.env` 已被 gitignore:
```bash
cp .env.example .env
```
支持的环境变量(优先于 `config.yaml` 对应项):
| 环境变量 | 覆盖配置 | 说明 |
| -------- | -------- | ---- |
| `FQ_SERVER_ACCESS_KEY` | `server.access_key` | 服务访问密钥 |
| `FQ_PG_HOST` | `cache.postgres.host` | PostgreSQL 主机 |
| `FQ_PG_USER` | `cache.postgres.user` | PostgreSQL 用户名 |
| `FQ_PG_PASSWORD` | `cache.postgres.password` | PostgreSQL 密码 |
| `FQ_PG_DATABASE` | `cache.postgres.database` | PostgreSQL 数据库名 |
| `FQ_REDIS_HOST` | `cache.redis.host` | Redis 主机 |
| `FQ_REDIS_PASSWORD` | `cache.redis.password` | Redis 密码 |
已有环境变量优先于 `.env` 文件中的值。
### 配置说明表
| 配置项 | 说明 | 默认值 |
| ------ | ------ | ------ |
| `server.host` | HTTP 服务监听地址 | `0.0.0.0` |
| `server.port` | HTTP 服务监听端口 | `40180` |
| `server.access_key` | 访问密钥,设为空则不验证 | - |
| `server.protect_all` | 业务接口是否也要求访问密钥 | `false` |
| `fanqie.algorithm` | 签名算法 `gorgon` / `8404` | `gorgon` |
| `fanqie.signature` | 签名方法 `sign2` / `sign4` | `sign4` |
| `fanqie.content.*` | 正文内容处理选项 | 见上文 |
| `fanqie.manga.output_mode` | 漫画输出模式 | `url` |
| `cache.enabled` | 是否启用正文内容缓存 | `true` |
| `cache.backend` | SQL 存储后端 `sqlite` / `postgres` | `sqlite` |
| `cache.sqlite_path` | SQLite 数据库路径 | `./cache.db` |
| `cache.postgres.host` | PostgreSQL 主机 | `127.0.0.1` |
| `cache.postgres.port` | PostgreSQL 端口 | `5432` |
| `cache.postgres.user` | PostgreSQL 用户名 | `postgres` |
| `cache.postgres.password` | PostgreSQL 密码 | 空 |
| `cache.postgres.database` | PostgreSQL 数据库名 | `fanqie` |
| `cache.postgres.sslmode` | SSL 模式 | `disable` |
| `cache.redis.enabled` | 启用 Redis 缓存(正文与音频代理缓存走 Redis) | `false` |
| `cache.redis.host` | Redis 主机 | `127.0.0.1` |
| `cache.redis.port` | Redis 端口 | `6379` |
| `cache.redis.password` | Redis 密码 | 空 |
| `cache.redis.db` | Redis 数据库编号 | `0` |
| `device_key_pool.enabled` | 是否启用设备密钥池 | `true` |
| `device_key_pool.initial_size` | 初始设备数量 | `20` |
| `device_key_pool.min_size` | 最小设备数量 | `10` |
| `device_key_pool.max_size` | 最大设备数量 | `30` |
## 签名算法详解
### 算法实现
项目实现了番茄小说的核心签名算法:
| 算法 | 文件 | 说明 |
| ------ | ------ | ------ |
| **Gorgon** | `algos/gorgon.go` | 核心签名算法,生成 X-Gorgon、X-Khronos、X-SS-REQ-Ticket |
| **8404** | `algos/algo8404.go` | 另一种签名算法实现 |
| **Argus** | `algos/argus.go` | 增强签名,包含 ProtoBuf、SM3、Simon、AES 加密 |
| **Ladon** | `algos/ladon.go` | 附加签名,基于 MD5 变换 |
| **Khronos** | 内嵌于 Gorgon | 时间戳签名 |
### 签名方法
- **sign2**: X-Gorgon + X-Khronos(基础签名)
- **sign4**: X-Gorgon + X-Ladon + X-Argus + X-Khronos(完整签名)
## 设备密钥池
项目实现了设备密钥池管理:
- **自动注册** - 启动时自动注册多个设备
- **密钥轮换** - 请求时自动切换设备
- **自动补充** - 设备数量低于阈值时自动注册新设备
- **持久化存储** - 设备信息保存到 SQLite
## 缓存机制
- **接口缓存** - 命中直接返回,不打上游(Redis 启用时优先走 Redis)
- **自动清理** - 定期清理过期缓存(Redis 由 TTL 自动过期)
- **数据库压缩** - 支持 VACUUM 操作优化数据库
| 接口 | 缓存时长 |
| ------ | ------ |
| `/content` | 24 小时 |
| `/detail`、`/info`、`/catalog`、`/multi-detail`、`/item-summary` | 24 小时 |
| `/search`、`/category-front`、`/category-landing` | 10 分钟 |
| `/audio` 代理链接 | 2 小时(匹配 CDN 有效期) |
失败响应不缓存;评论类接口为动态数据,不缓存。
## 部署
### Linux 服务器(deploy.sh 一键部署)
```bash
# 首次:编译 + 部署 + 写入 systemd/nginx 配置
./deploy.sh v1.0.0 --init
# 日常:拉取代码 + 编译 + 部署 + 重启
./deploy.sh v1.0.0
# 版本管理
./deploy.sh --list # 列出已部署版本
./deploy.sh --rollback v1.0.0 # 回滚到指定版本
# 服务运维
sudo systemctl status fanqie
sudo journalctl -u fanqie -f
```
部署结构:二进制存于 `/opt/fanqie/bin/`,`fanqie-current` 软链接指向当前版本(保留最近 5 个),systemd 守护 + Nginx 反代,部署后自动做 `/healthz` 健康检查。
首次 `--init` 时若服务器装有 certbot,会自动申请 HTTPS 证书并配置 80→443 跳转(邮箱默认 `admin@域名`,可用 `.deploy.env` 的 `CERT_EMAIL` 覆盖);续期由 `certbot.timer` 自动完成,续期后经 deploy-hook 重载 Nginx。
### 本地交叉编译
```bash
make build-linux VERSION=v1.0.0 # 产物 fanqie-v1.0.0-linux,scp 到服务器即可运行
```
## 技术栈
- **Go 1.25** - 编程语言
- **net/http** - 标准库 HTTP 服务(超时保护 + 优雅退出)
- **SQLite3 / PostgreSQL / Redis** - 缓存与存储
- **Viper** - 配置管理
- **goquery** - HTML 解析
## 注意事项
- 本项目仅供学习和研究使用
- 请遵守番茄小说的服务条款
- 请合理使用,避免对官方服务造成影响
- 签名算法和设备注册可能随时失效
## License
MIT License