Files
live-hub-py/README.md
T

197 lines
9.0 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.
# 直播账号运营后台
斗鱼 / 虎牙账号运营 Web 平台:批量登录拿 Cookie、按工作台跑活动任务、应用宝点券充值。版本见 `pyproject.toml`(当前 0.3.0)。
## 能做什么
- **斗鱼**:极验滑块自动过验、邮箱验证码、批量登录与 CK 检测/重登;精英宝典 / 电竞手册 / 和平小店三套工作台(绑定、开通、充值、兑换);鱼翅可由微信二维码或供应商直充。
- **虎牙**:Cookie / 密码 / App / 短信登录、自动注册、设备绑定、精英宝典、浏览器人工兑换;网页运行 Cookie 与 App 原始凭据(`raw_cookie`)分离,可从原始凭据重建网页 Cookie。
- **应用宝**:和平精英点券扫码登录、选区服角色、支付二维码。Worker 合在 Web 容器内,只监听 `127.0.0.1:8810`。
- **权限**:超级管理员 / 运营 / 客服;可按权限点覆盖。客服只看分配给自己的账号,虎牙侧默认只开放浏览器兑换。
- **安全**:密码、邮箱、Cookie、代理密钥等敏感字段落盘加密;操作写审计日志。
## 项目结构
```
live-hub-py/
├── core/ # 协议客户端(不经过 Web 也可单独调用)
│ ├── douyu/ # 登录、活动、鱼翅直充、代理
│ ├── huya/ # App/Web/短信登录、WSS、设备指纹、网页 Cookie 补齐
│ └── geetest/ # 极验 v3 滑块
├── web/
│ ├── backend/ # FastAPI + SQLAlchemy + Alembic
│ │ ├── routers/ # HTTP / WebSocket
│ │ ├── services/ # 批次 runner(进程内线程池)
│ │ └── migrations/ # 数据库迁移
│ ├── frontend/ # React + Ant Design + Vite
│ └── extension/ # 虎牙浏览器兑换助手
├── services/yyb-worker/ # 应用宝协议运行时(随主镜像部署)
├── tests/ # pytest(跑在真实 MySQL 测试库上)
├── docs/ # 协议与联调文档(结论以「虎牙 Cookie 路线状态」为准)
├── deploy.sh / dev.sh # 生产部署 / 本机热更新
└── docker-compose.yml # 应用容器 + MySQL 8.4
```
## 快速开始
```bash
# Docker 部署(推荐)
./deploy.sh
```
访问 `http://localhost:8800`(compose 默认把容器 8800 映到宿主机 `APP_PORT`,缺省 8000)。默认管理员 `admin / admin123`,生产环境务必改掉。
本机热更新用 `./dev.sh`(或 `./deploy.sh dev`)。它会拉起绑定 `127.0.0.1:8810` 的开发 Worker,后端自动连该地址;Worker 数据在 `data/yyb-worker-dev/`。`Ctrl+C` 会一并停掉。应用日志按日期写到 `logs/app-YYYY-MM-DD.log`,可用 `./dev.sh logs` 跟踪当天文件。
```bash
./deploy.sh # 构建并部署
./deploy.sh logs # 当天持久化应用日志
./deploy.sh logs container # Docker 容器输出(含 Worker)
./deploy.sh stop
./deploy.sh restart
./deploy.sh reset # 重置所有数据(需二次确认)
```
## 时区口径(查库前必读)
**全库时间列一律存 UTC 裸值**(`DATETIME`,无 `TIMESTAMP` 列、无 `CURRENT_TIMESTAMP` 默认值)。MySQL 容器以
`--default-time-zone=+00:00` 启动,因此 **`NOW()` 返回的也是 UTC** —— 这**不是故障**,是刻意对齐存储口径。
| 层 | 看到的时间 | 说明 |
| --- | --- | --- |
| 数据库裸值 / `NOW()` | UTC | 命令行直连就是这个 |
| ORM 读出(`UTCDateTime`) | `+00:00` aware | 读出来永远带时区,比较不会踩 naive/aware 的坑 |
| HTTP 接口返回 | `...+00:00` | 前端按本地时区渲染 |
| 前端显示 | 北京时间(UTC+8) | `dayjs` 自动转换 |
| 应用日志 | 北京时间 | 容器内 `TZ=Asia/Shanghai` |
> ⚠️ **别拿 `SELECT NOW()` 当"真实时间"去和业务时间比对** —— 它比你手表慢 8 小时是正常的。
> 已踩过一次:据此误判"数据库时区错了",实际端到端完全正确。
命令行查库要按北京时间看,用 `CONVERT_TZ`:
```sql
SELECT id, status,
CONVERT_TZ(created_at, '+00:00', '+08:00') AS 创建时间,
CONVERT_TZ(finished_at, '+00:00', '+08:00') AS 完成时间
FROM login_tasks ORDER BY id DESC LIMIT 10;
```
按"北京时间某段"筛选用同样的换算,别直接写本地时间字面量:
```sql
-- 查北京时间 10-03 09:00 之后的任务
SELECT * FROM login_tasks
WHERE created_at >= CONVERT_TZ('2026-10-03 09:00:00', '+08:00', '+00:00');
```
## 运行时与密钥
生产是 **单个应用容器 + 内网 MySQL 8.4**。数据库不映射公网;本机 `./dev.sh` 通过 `127.0.0.1:3307` 连 compose 里的 MySQL。
在项目 `.env` 里准备:
```dotenv
MYSQL_PASSWORD=...
MYSQL_ROOT_PASSWORD=...
JWT_SECRET_KEY=随机密钥
APP_ENCRYPTION_KEY=随机密钥 # 敏感字段加密,更换后历史密文无法解密
YYB_WORKER_KEY=随机密钥 # 本机回环访问 Worker
```
生成随机密钥:
```bash
python3 -c 'import secrets; print(secrets.token_urlsafe(32))'
```
可选:
- `FISH_FIN_RECHARGE_*`:鱼翅供应商直充,只走环境变量,不入库、不回前端。
- `MAIL_ROUNDCUBE_URL`:邮件验证码服务;不填则用代码默认 Roundcube 地址。
- `CORS_ORIGINS`、`COOKIE_SECURE`:HTTPS 部署时按实际填写。
应用宝扫码图和支付二维码只经后台授权接口返回。服务器只需要本仓库,不必再部署 `js_reverse`。Worker 任务数据在 `data/yyb-worker-jobs/`。
## 角色权限
| 角色 | 权限 |
|---|---|
| 超级管理员 | 全部功能 + 用户管理 + 权限分配 + 审计日志 |
| 运营 | 账号管理、批量登录、代理、Cookie、双平台任务、应用宝 |
| 客服 | 仅查看分配给自己的账号;虎牙只保留浏览器兑换 |
## 登录与任务流
斗鱼登录:
```
获取极验参数 → 滑块识别 → 邮箱验证码 → 提交 → Cookie
```
斗鱼工作台按 `handbook_scope`(elite / esports / peace)隔离任务和支付二维码。虎牙精英宝典走活动 WSS;缺少网页设备字段时先 `wsLaunch` 补齐,再把补齐后的 Cookie 回写账号。
进程重启会把内存里丢失的 pending/running 任务标成中断,避免前端被假活跃批次锁死。
登录任务列表支持分页(20/50/100/200/500)与状态筛选;表格支持跨页勾选、表头的
「选择全部 N 条(含其他页)」用于按筛选条件批量操作,以及「清空失败」一键清理。
批量删除**会跳过 pending/running**:要停止在跑的批次请用「停止」,不要删除
(删掉会让批次线程找不到记录)。
## 运行测试
```bash
uv run --group dev pytest # 或 ./dev.sh test
uv run --group dev pytest tests/test_cookie_operations.py
./dev.sh format tests conftest.py
./dev.sh format-check tests conftest.py
./dev.sh type-check # 渐进式 Pyright
docker compose --profile test run --rm test
```
测试跑在**真实 MySQL** 上(不再使用 SQLite):生产是 MySQL,SQLite 与它有方言差异,
曾出现「`ORDER BY ... NULLS FIRST` 本地全绿、生产直接 1064」的事故。因此:
- 先起数据库:`./dev.sh`(docker compose,MySQL 映射到 `127.0.0.1:3307`);
- 测试库默认 `douyu_login_test`,可用 `TEST_MYSQL_DATABASE` 覆盖;**库名与开发库相同时
会被 `tests/support/db.py` 拒绝运行**(每个用例前后会清空所有表,防误清);
- `tests/conftest.py` 在导入应用模块前把连接串指向测试库,并把每用例的表清空交给 autouse fixture;
- 迁移链冒烟见 `tests/test_migrations.py`:它在临时库 `douyu_login_mig_<随机>` 上跑完整
`alembic upgrade head`,跑完 drop。
兑换、下单、支付属于写操作,默认用 mock 做契约测试,不打真实支付。
启用提交/推送门禁(改过前端会跑 TypeScript,与 Docker `npm run build` 的 `tsc -b` 一致):
```bash
./scripts/install-git-hooks.sh
./dev.sh frontend-check # 单独跑前端 TypeScript
```
- **pre-commit**:暂存的 Python 文件做 Ruff 格式检查;改了 `web/frontend/` 则跑 `tsc -b`
- **pre-push**:上述检查 + 全量 pytest
- Pyright 默认不开(噪音大):`TYPECHECK=1 git push`
- 紧急绕过:`git push --no-verify` 或 `SKIP_TESTS=1 git push`
## 技术栈
- 后端:FastAPI + SQLAlchemy + MySQL 8.4(测试同样跑 MySQL)+ JWT
- 前端:React + Ant Design + Vite
- 核心:Python 3.12 + OpenCV + ONNX + pycryptodome + curl-cffi
- 迁移:Alembic
- 部署:Docker Compose
## 代理
在「代理配置」页填写代理 API(JSON)和白名单。移动出口 IP 漂移时,系统会保留多个出口 IP。示例:
```json
{"code":0,"success":"true","msg":"","data":[{"IP":"1.2.3.4","Port":8080}]}
```
白名单错误时接口会带上当前出口 IP,系统按平台凭证自动同步。
## 文档
协议与联调笔记在 `docs/`。当前虎牙 Cookie 行为以 [虎牙 Cookie 路线状态](docs/HUYA_COOKIE路线状态.md) 为准。