docs: 更新 README 与线上部署运维说明,新增 .gitignore

- README: 新架构图/端口表/目录结构/双缓存机制/waitress/部署与验证步骤/版本要点
- docs/部署与运维.md: 线上服务器的实际路径、缓存策略、迁移 8 步、日志与变更记录
- .gitignore: 忽略 source/cache/、tokens.json、cookies.txt、__pycache__
This commit is contained in:
RRRosmontis
2026-09-13 02:26:35 +08:00
parent 212adb1e25
commit 1b2071d78b
3 changed files with 251 additions and 20 deletions
+110 -20
View File
@@ -2,34 +2,124 @@
统一接口服务。线上入口:`https://openapi.rrrosmontis.icu`
聚合层把 **pixiv 图片服务**与 **bilibili 视频服务**收敛到单一对外入口。三个后端进程全部只监听 `127.0.0.1`,对外仅由 nginx 暴露 80/443——即"一个入口、零暴露端口"。
## 架构
```
公网 443/80 nginx (server_name openapi.rrrosmontis.icu)
├── /pixiv/get_image?id=xxx -> 127.0.0.1:9008 main.py 聚合层 -> 127.0.0.1:9007 pixiv
├── /bilibili/get_video?bv=xxx -> 127.0.0.1:9008 main.py 聚合层 -> 127.0.0.1:9006 bilibili
├── /img-master/ /img-original/ -> nginx 直接反代 i.pximg.net(无本地后端)
└── / -> 127.0.0.1:9008(302 跳转文章页)
```
## 端口与进程
| 服务 | 监听 | 入口源码 | 说明 |
|---|---|---|---|
| openapi | `127.0.0.1:9008` | `source/main.py`(aiohttp) | 聚合层,纯转发,**唯一入口** |
| pixiv | `127.0.0.1:9007` | `source/pixiv/pixiv.py`(Flask + waitress) | 图片代理 |
| bilibili | `127.0.0.1:9006` | `source/bilibili/bilibili.py`(aiohttp + yt-dlp) | 视频代理 |
| pixiv-token-refresh | — | `source/pixiv/refresh_token.py` | token 刷新守护(每 30–60 分钟随机) |
| bilibili-refresh | — | `source/bilibili/refresh_cookie.py` | cookie 刷新守护(每 50–70 分钟随机) |
> 历史端口 `9888 / 9088 / 19990` 已于 2026-09-12 废弃,全部改为上述 `900x`。
> pixiv 早期误绑 `0.0.0.0:9088` 对公网裸奔(绕过 nginx 的日志与限流),现已收口为 `127.0.0.1`。
## 结构
```
source/
├── openapi/main.py # 聚合层 (127.0.0.1:9888) /pixiv/get_image /bilibili/get_video
├── main.py # 聚合层 (127.0.0.1:9008),三条路由:/ /pixiv/get_image /bilibili/get_video
├── pixiv/
│ ├── pixiv.py # Pixiv 图片服务 (9088)
│ ├── refresh_token.py # Pixiv OAuth token 刷新守护
│ └── tokens.template.json # Pixiv token 模板
└── bilibili/
├── bilibili.py # bilibili 视频服务 (19990)
├── refresh_cookie.py # cookie 定时刷新守护
├── qr_login.py # 扫码登录获取 cookie
└── qr_login_fast.py
│ ├── pixiv.py # Pixiv 图片服务 (127.0.0.1:9007)
│ ├── refresh_token.py # Pixiv OAuth token 刷新守护
│ └── tokens.template.json # token 模板(实际 tokens.json 不入库)
├── bilibili/
│ ├── bilibili.py # bilibili 视频服务 (127.0.0.1:9006)
│ ├── refresh_cookie.py # cookie 定时刷新守护
│ ├── qr_login.py # 扫码登录获取 cookie
│ └── qr_login_fast.py
└── cache/ # 运行时生成,不入库
├── pixiv/images # 图片缓存
└── bilibili/ # 视频缓存
nginx/
└── openapi.rrrosmontis.icu.conf # nginx 统一入口(/pixiv/ /bilibili/ /img-master/ /img-original/ 图片反代)
└── openapi.rrrosmontis.icu.conf # 统一入口(/pixiv/ /bilibili/ /img-master/ /img-original/)
systemd/
├── openapi.service # 聚合层
├── pixiv.service # Pixiv 图片服务
├── bilibili.service # bilibili 视频服务
├── bilibili-refresh.service # cookie 刷新守护(每 50–70 分钟随机刷新)
└── pixiv-token-refresh.service # Pixiv token 刷新守护(每 30–60 分钟随机刷新)
├── openapi.service # 聚合层
├── pixiv.service # Pixiv 图片服务(waitress --threads=8)
├── bilibili.service # bilibili 视频服务
├── bilibili-refresh.service # cookie 刷新守护
└── pixiv-token-refresh.service # Pixiv token 刷新守护
docs/
└── 部署与运维.md # 线上服务器的路径、缓存、迁移步骤与变更记录
```
## 缓存机制
**pixiv(图片)**:`check_cache()` 以 glob 命中即直接回文件;未命中按 `官方 App API → pixiv.re → pixiv.cat` 三级回退抓取,落盘用 `.tmp` + `os.replace` 原子写。
缓存目录不再硬编码,由模块位置推导:
```python
IMAGE_DIR = (Path(__file__).resolve().parent / "../cache/pixiv/images").resolve()
IMAGE_DIR.mkdir(parents=True, exist_ok=True)
```
即 `source/cache/pixiv/images`;线上常用 `/home/images` 软链指向它,便于访问。
**bilibili(视频)**:以 **BV 号为键**缓存到 `source/cache/bilibili/{BV}.mp4`
- 命中即直接 `FileResponse`,**不再调用 yt-dlp**
- 未命中才下载,且先落到缓存目录内的隐藏暂存目录 `.dl-XXXX`,成功后 `os.replace` 原子落盘
- **无论成功 / 失败 / 超时都会 `shutil.rmtree(tmpdir)`** —— 早期实现只清理 cookie 临时文件、从不清理视频暂存目录,导致每次取视频都把完整视频永久留在 `/tmp`(无上限磁盘泄漏),已修复
- 淘汰策略:单文件 `CACHE_TTL_SECONDS`(默认 7 天)未访问即过期;总量超过 `CACHE_MAX_BYTES`(默认 2 GiB)时按 mtime 从最旧开始删除
- 命中/落盘会在日志打印 `cache HIT / MISS / STORE`(已 `flush=True`,实时可见)
运维接口(只绑本机):
```bash
curl -s 127.0.0.1:9006/bilibili/cache_info
# {cache_dir, cache_max_bytes, cache_ttl_seconds, count, total_bytes, free_bytes, files[]}
```
## 部署
1. token:复制 `source/pixiv/tokens.template.json` 为 `source/pixiv/tokens.json`,填入实际 pixiv token
2. bilibili cookie:放置 `source/bilibili/cookies.txt`(`name=value` 格式),或运行 `qr_login.py` 扫码生成
3. 服务:将 `systemd/*.service` 安装到 `/etc/systemd/system/`,启用并启动 openapi / pixiv / bilibili / bilibili-refresh / pixiv-token-refresh(`systemctl enable --now`)
4. nginx:将 `nginx/openapi.rrrosmontis.icu.conf` 放入 `/etc/nginx/conf.d/`,`nginx -t && systemctl reload nginx`
5. 定时任务:无 cron/timer——bilibili-refresh(每 50–70 分钟刷 cookie)与 pixiv-token-refresh(每 30–60 分钟刷 Pixiv OAuth token,轮换后的 refresh_token 原子落盘)均为常驻守护,内部循环随机间隔,systemd `Restart=always` 兜底
1. **Python 环境**:三服务共用一个环境,需含 `flask`、`waitress`、`aiohttp`、`httpx`、`yt-dlp`
2. **凭据**:
- 复制 `source/pixiv/tokens.template.json` 为 `source/pixiv/tokens.json`(`chmod 600`)并填入实际 pixiv token
- 放置 `source/bilibili/cookies.txt`(`name=value` 格式),或运行 `qr_login.py` 扫码生成
3. **服务**:将 `systemd/*.service` 安装到 `/etc/systemd/system/`,然后
`systemctl daemon-reload && systemctl enable --now openapi pixiv bilibili bilibili-refresh pixiv-token-refresh`
4. **nginx**:将 `nginx/openapi.rrrosmontis.icu.conf` 放入 `/etc/nginx/conf.d/`(需存在 `$connection_upgrade` 的 map 定义),`nginx -t && systemctl reload nginx`
5. **软链**(可选):`ln -s <部署根>/source/cache/pixiv/images /home/images`
6. **定时任务**:无 cron/timer——两个刷新守护均为常驻循环(内部随机间隔),systemd `Restart=always` 兜底
## 验证
```bash
curl -k "https://openapi.rrrosmontis.icu/pixiv/get_image?id=147113746"
curl -k "https://openapi.rrrosmontis.icu/bilibili/get_video?bv=BV16a41157Q4"
curl -kI "https://openapi.rrrosmontis.icu/bilibili/get_video?bv=BV16a41157Q4" # 只看头部,省流量
curl -s 127.0.0.1:9006/bilibili/cache_info
```
端口暴露自检(三个后端都应"不可达",仅 443/80 通):
```bash
for p in 9006 9007 9008; do timeout 3 bash -c "cat < /dev/null > /dev/tcp/<host>/$p" 2>/dev/null \
&& echo "$p 可连通(异常)" || echo "$p 不可达(正常)"; done
```
## 版本要点
- **2026-09-12**
- 端口重排 `9888/9088/19990 → 9008/9007/9006`,全部仅绑 `127.0.0.1`;pixiv 由 `0.0.0.0:9088` 收口
- 主入口 `main.py` 从 `source/openapi/` 上移到 `source/`,systemd `WorkingDirectory` 同步为 `source/`
- pixiv 缓存路径由硬编码 `/home/pixiv/images` 改为相对 `../cache/pixiv/images`
- pixiv 改由 **waitress 线程池**承载(`--threads=8`),替代 Flask 开发服务器(thread-per-request 无上限)
- bilibili 新增 **BV 真缓存**(`../cache/bilibili`,2 GiB / 7 天淘汰),并修复视频暂存目录永不清理导致的 `/tmp` 泄漏
- 新增 `/bilibili/cache_info` 运维接口;缓存日志加 `flush=True`
- **2026-09-02**:新增 pixiv token 刷新守护;补 `/img-original/` 反代(App API 原图路径)
- **2026-07-31**:三服务迁移落位(Python 环境合并为单一 `general`)