Files
fanqie-go/README.md
T
chenxin 1eccebedf9 ✨ feat(cache): 新增 Redis 缓存与 PostgreSQL 后端支持
- 新增 cache.redis 配置(独立 host/port/password/db 字段),启用后正文缓存与音频代理缓存走 Redis,键前缀 fq:cache:/fq:audio:,TTL 自动过期
- 新增 cache.backend: sqlite|postgres 切换,PG 连接用 net/url 构造 DSN,密码特殊字符自动转义;SQLite 顺手启用 WAL 与 busy_timeout
- SQL 方言收敛:q() 将 ? 占位符转换为 $n、INSERT OR IGNORE 与查询再插入统一为 ON CONFLICT、LastInsertId 改为 RETURNING id、建表 DDL 双版本分派
- PG 下 VACUUM 走 autovacuum 说明、状态页大小改查 pg_database_size
- 修复 PG 下设备保存失败:is_valid 列为 INTEGER,写入点补 boolToInt 转换
- 新增 .env 支持:敏感配置(密码/主机/访问密钥)由环境变量覆盖 config.yaml,.env 进 gitignore,仓库附 .env.example 模板
- 新增 openapi.yaml(OpenAPI 3.1):覆盖全部 24 个路径,含参数、响应结构与鉴权方案,README 增加指引
- 删除死代码 InitDevicePoolTable;新增 rebind_test.go 单测
- 更新 README 与 config.yaml 配置示例,go.mod 新增 go-redis/v9 与 pgx/v5 依赖
2026-09-29 20:33:37 +08:00

402 lines
14 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
- **设备密钥池** - 多设备轮换、自动补充
- **SQLite 缓存** - 本地缓存、过期清理、数据库压缩;支持切换 PostgreSQL 与 Redis
- **配置热更新** - 修改配置无需重启
- **访问控制** - 支持 AccessKey 验证
## 项目结构
```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.24+
- 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 /status` | GET | 服务状态(需 AccessKey) |
| `GET /self-info` | GET | 自我信息(需 AccessKey) |
| `GET /vacuum` | GET | 数据库压缩(需 AccessKey) |
### 书籍相关
| 接口 | 方法 | 说明 | 参数 |
| ------ | ------ | ------ | ------ |
| `/search` | GET | 搜索书籍 | `keyword`, `tab_type`, `offset` |
| `/detail` | GET | 书籍详情 | `book_id` |
| `/info` | GET | 书籍详情(同 detail) | `book_id` |
| `/catalog` | GET | 章节目录 | `book_id` |
| `/directory/all_items` | GET | 章节目录(同 catalog) | `book_id` |
| `/multi-detail` | GET | 批量书籍详情 | `book_ids`(逗号分隔) |
### 内容相关
| 接口 | 方法 | 说明 | 参数 |
| ------ | ------ | ------ | ------ |
| `/content` | GET | 章节内容 | `chapter_id`, `book_id` |
| `/multi-content` | GET | 批量章节内容 | `chapter_ids`(逗号分隔) |
| `/item-summary` | GET | 章节摘要 | `book_id`, `chapter_id` |
### 评论相关
| 接口 | 方法 | 说明 | 参数 |
| ------ | ------ | ------ | ------ |
| `/chapter_review` | GET | 章节评论 | `book_id`, `chapter_id` |
| `/review` | GET | 书评列表 | `book_id`, `offset`, `limit` |
| `/review_html` | GET | 评论 HTML | `book_id`, `chapter_id` |
### 分类相关
| 接口 | 方法 | 说明 | 参数 |
| ------ | ------ | ------ | ------ |
| `/category-front` | GET | 分类首页 | - |
| `/category-landing` | GET | 分类详情 | `category_id`, `word_number`, `book_status`, `sort_by`, `offset` |
### 媒体相关
| 接口 | 方法 | 说明 | 参数 |
| ------ | ------ | ------ | ------ |
| `/audio` | GET | 音频内容 | `audio_id`, `tone_id` |
| `/video` | GET | 视频内容 | `video_id` |
| `/manga` | GET | 漫画内容 | `manga_id`, `chapter_id` |
| `/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: "" # 访问密钥(可选)
# 番茄小说配置
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` | 访问密钥,设为空则不验证 | - |
| `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
## 缓存机制
- **SQLite 本地缓存** - 缓存书籍内容和章节数据
- **自动清理** - 定期清理过期缓存
- **数据库压缩** - 支持 VACUUM 操作优化数据库
## 技术栈
- **Go 1.24** - 编程语言
- **Gin** - HTTP 框架(间接依赖)
- **SQLite3** - 本地数据库
- **Viper** - 配置管理
- **goquery** - HTML 解析
## 注意事项
- 本项目仅供学习和研究使用
- 请遵守番茄小说的服务条款
- 请合理使用,避免对官方服务造成影响
- 签名算法和设备注册可能随时失效
## License
MIT License