298 lines
12 KiB
Markdown
298 lines
12 KiB
Markdown
# Live Recorder
|
||
|
||
Live Recorder 是一个多平台直播录制系统,支持自动检测开播、实时录制、弹幕采集、通知推送与事件脚本编排。
|
||
|
||
- 后端:`.NET 8 Web API + EF Core + PostgreSQL`
|
||
- 前端:`Vue 3 + TypeScript + Element Plus`
|
||
|
||
当前已适配 **抖音**(Douyin)与 **Bilibili**(部分),架构将平台特有逻辑隔离在 `Platforms` 目录下,新增虎牙、斗鱼、快手等平台无需改动应用层服务。
|
||
|
||
## 目录结构
|
||
|
||
```text
|
||
.
|
||
├─ src
|
||
│ ├─ LiveRecorder.Domain # 实体与枚举
|
||
│ ├─ LiveRecorder.Application # 接口、DTO、应用服务
|
||
│ ├─ LiveRecorder.Infrastructure # 持久层、平台适配器、后台服务
|
||
│ └─ LiveRecorder.WebApi # REST API 与中间件
|
||
├─ frontend # Vue 3 SPA
|
||
│ └─ src
|
||
│ ├─ api / components / composables / router / stores / styles / views
|
||
├─ docker-compose.yml
|
||
├─ Jenkinsfile
|
||
└─ README.md
|
||
```
|
||
|
||
## 核心功能
|
||
|
||
### 直播录制
|
||
|
||
- 支持分享链接与短链解析,自动提取真实房间号
|
||
- 后台轮询检测直播状态,可配置轮询间隔与自动录制开关
|
||
- 支持 `MP4`(单文件)与 `TS`(分段)两种输出格式
|
||
- 内置三种录制模板:`StreamCopy`、`BalancedMp4`、`ArchiveTs`
|
||
- 断线重连:可配置重连开关、最大重连延迟、读写超时
|
||
- 存储守护:启动前检查磁盘剩余空间,不足时拒绝录制
|
||
|
||
### 弹幕采集
|
||
|
||
弹幕通过 WebSocket 实时连接各平台的弹幕服务器,以 XML 格式分段写入文件。
|
||
|
||
- **抖音弹幕**:通过 `webcast/im/fetch/` 获取连接信息,建立 WSS 长连接,使用 `a_bogus` 签名算法(基于 `dycast` 开源项目的 `abogus.js`),支持 Protobuf 解码
|
||
- **Bilibili 弹幕**:通过 Bilibili 直播 WebSocket 协议连接弹幕服务器,支持聊天、进入、关注、礼物等事件
|
||
- 弹幕事件类型:聊天(chat)、礼物(gift)、点赞(like)、进入(enter)、关注(member)等
|
||
- 弹幕录制可按设置只保留聊天弹幕或包含所有事件类型
|
||
- 弹幕文件与视频文件同目录、同名(`.xml` 扩展名),内部以结构化 XML 保存
|
||
|
||
### 通知推送
|
||
|
||
- **邮件通知**:支持 SMTP 配置、SSL、自定义发件人与 HTML 模板
|
||
- 开播提醒:直播间上线时发送
|
||
- 异常提醒:录制异常时发送
|
||
- 模板变量:`{{appName}}`、`{{anchor}}`、`{{title}}`、`{{summary}}`、`{{detail}}` 等
|
||
- **Webhook 通知**:支持自定义 URL、请求头、超时配置
|
||
- 开播事件与异常事件分别可独立开关
|
||
- 支持测试发送验证连通性
|
||
- 负载包含直播间信息、录制任务信息等完整上下文
|
||
|
||
### 事件脚本
|
||
|
||
支持在关键生命周期节点执行自定义脚本(Shell / PowerShell 内联或外部脚本文件):
|
||
|
||
| 事件 | 说明 |
|
||
|------|------|
|
||
| `live_started` | 检测到直播上线时触发 |
|
||
| `live_ended` | 检测到直播下线时触发 |
|
||
| `segment_completed` | 一个录制分片完成时触发 |
|
||
|
||
脚本通过环境变量获取上下文信息:
|
||
|
||
```
|
||
LIVE_RECORDER_EVENT # 事件类型
|
||
LIVE_RECORDER_PLATFORM # 平台名称
|
||
LIVE_RECORDER_LIVE_ROOM_ID # 直播间内部 ID
|
||
LIVE_RECORDER_ROOM_ID # 平台房间号
|
||
LIVE_RECORDER_TITLE # 直播间标题
|
||
LIVE_RECORDER_ANCHOR # 主播昵称
|
||
LIVE_RECORDER_SOURCE_URL # 源 URL
|
||
LIVE_RECORDER_OCCURRED_AT_UTC # 事件发生时间(北京时间)
|
||
LIVE_RECORDER_SEGMENT_FILE_PATH # 分片文件路径(仅 segment_completed)
|
||
LIVE_RECORDER_DANMAKU_FILE_PATH # 弹幕文件路径(仅 segment_completed)
|
||
LIVE_RECORDER_DURATION_SECONDS # 分片时长(仅 segment_completed)
|
||
```
|
||
|
||
支持超时控制与自定义日志输出。
|
||
|
||
### 异常恢复(Recovery)
|
||
|
||
- 自动检测处于 Live 状态但未在录制的直播间
|
||
- 自动检测录制完成但未做最终化(MP4 remux)的任务
|
||
- 支持一键重试录制或逐一恢复
|
||
- 后台轮询调度器同时兼具恢复层功能:当 ffmpeg 异常退出而直播间仍在直播时自动重新创建录制任务
|
||
|
||
### 数据保留清理(Retention)
|
||
|
||
- 可配置保留天数,超期自动清理录制记录、弹幕文件、视频文件与系统日志
|
||
- 支持后台定时清理(每 24 小时执行一次)
|
||
|
||
### 每日回顾(Daily Review)
|
||
|
||
- 按日期查看当天所有录制会话的汇总信息
|
||
- 亮点卡片:最长录制、最多弹幕、最多异常等
|
||
- 时间线视图展示会话与分片时间段
|
||
- 弹幕数量随时间分布的可视化数据
|
||
|
||
### 系统日志
|
||
|
||
- 持久化系统日志,支持按类别、时间筛选
|
||
- 日志关联直播间、录制会话、录制任务
|
||
- 可在前端日志页面实时查看
|
||
|
||
### 前端界面
|
||
|
||
- 登录页
|
||
- 直播间管理(添加、编辑、删除、状态查看、快速录制)
|
||
- 录制任务列表与详情
|
||
- 录制会话列表与详情
|
||
- 日志查看器
|
||
- 每日回顾
|
||
- 异常恢复页面
|
||
- 系统设置(录制、通知、弹幕、事件脚本、保留策略、平台配置)
|
||
- 路由懒加载,Vite vendor chunk 拆分
|
||
|
||
## 适配器架构
|
||
|
||
### 平台适配器接口
|
||
|
||
```csharp
|
||
ILivePlatformAdapter
|
||
├─ ParseRoomAsync(input) # 解析分享链接、提取房间 ID
|
||
├─ GetLiveStatusAsync(roomId) # 获取直播状态、标题、主播名、封面
|
||
└─ GetStreamUrlAsync(roomId) # 获取推流地址
|
||
|
||
ILiveDanmakuAdapter
|
||
├─ CanHandle(platformType) # 判断是否支持该平台
|
||
└─ ConnectAsync(context) # 建立弹幕 WebSocket 连接
|
||
|
||
ILiveDanmakuConnection
|
||
└─ StartAsync(onEvent) # 开始接收弹幕,通过回调推送事件
|
||
```
|
||
|
||
### 抖音适配器
|
||
|
||
- `DouyinHttpClient`:封装 User-Agent、Referer、Cookie、ttwid 管理
|
||
- 分享链接解析、重定向跟随
|
||
- 从 HTML 中提取 `roomId`、`user_unique_id`、主播名、标题(支持新版 `__pace_f` 数据结构)
|
||
- 调用 `webcast/room/web/enter/` 获取直播间元信息
|
||
- 调用 `webcast/im/fetch/` 获取弹幕 WebSocket 连接参数
|
||
- `a_bogus` 签名:通过 Node.js 子进程调用 `abogus.js` 计算请求签名
|
||
- `DouyinLivePlatformAdapter`:解析推流地址,选择画质
|
||
- `DouyinDanmakuAdapter`:WebSocket 弹幕连接管理、心跳保活、自动重连
|
||
|
||
### Bilibili 适配器
|
||
|
||
- `BilibiliHttpClient`:Wbi 签名、分享链接解析
|
||
- `BilibiliLivePlatformAdapter`:直播状态查询,推流地址获取
|
||
- `BilibiliDanmakuAdapter`:弹幕 WebSocket 协议解析
|
||
|
||
## 设置项速览
|
||
|
||
### 录制设置
|
||
| 设置 | 说明 |
|
||
|------|------|
|
||
| FFmpeg 路径 | ffmpeg 可执行文件路径 |
|
||
| 输出根目录 | 录制文件输出根目录 |
|
||
| 输出模板 | 路径模板,支持 `{platform}` `{roomId}` `{anchor}` `{title}` `{sessionId}` `{yyyy}` `{MM}` `{dd}` `{HHmmss}` 等变量;已有主播/日期目录直接复用,同名文件自动追加会话短 ID,绝不静默覆盖 |
|
||
| 默认画质 | 优先选择的流画质 |
|
||
| 保存格式 | MP4 / TS |
|
||
| 保存模式 | 单文件 / 分段 |
|
||
| 分段时长 | 分段模式下的每段时长(秒) |
|
||
| 录制模板 | StreamCopy / BalancedMp4 / ArchiveTs |
|
||
| 重连开关 | 断线后是否自动重连 |
|
||
| 最大重连延迟 | 重连退避最大秒数 |
|
||
| 读写超时 | 网络读写超时秒数 |
|
||
| 存储守护 | 启用磁盘空间检查 |
|
||
| 最低剩余空间 | 存储守护的最低空间阈值(GB) |
|
||
|
||
### 弹幕设置
|
||
| 设置 | 说明 |
|
||
|------|------|
|
||
| 启用弹幕录制 | 录制时是否同时采集弹幕 |
|
||
| 包含非聊天事件 | 是否记录进入、关注、礼物等非聊天弹幕 |
|
||
| 最小轮询间隔 | 弹幕连接重试的最小间隔(毫秒) |
|
||
| 最大重试延迟 | 弹幕连接重试退避最大秒数 |
|
||
|
||
### 通知设置
|
||
| 设置 | 说明 |
|
||
|------|------|
|
||
| 启用邮件通知 | SMTP 邮件通知总开关 |
|
||
| SMTP 服务器 / 端口 / SSL / 账号 | 邮件服务器配置 |
|
||
| 开播提醒 / 异常提醒 | 分别控制是否发送 |
|
||
| HTML 模板 | 可自定义邮件 HTML 模板,支持变量占位 |
|
||
| 启用 Webhook | Webhook 推送总开关 |
|
||
| Webhook URL / 请求头 / 超时 | Webhook 配置 |
|
||
| 开播通知 / 异常通知 | 分别控制是否推送 |
|
||
|
||
### 事件脚本设置
|
||
| 设置 | 说明 |
|
||
|------|------|
|
||
| 启用事件脚本 | 总开关 |
|
||
| 开播脚本 / 下播脚本 / 分片完成脚本 | 分别控制与配置 |
|
||
| 脚本模式 | 内联脚本 / 外部文件 |
|
||
| 超时(秒) | 脚本执行超时限制 |
|
||
|
||
### 保留策略
|
||
| 设置 | 说明 |
|
||
|------|------|
|
||
| 启用保留清理 | 是否开启自动清理 |
|
||
| 保留天数 | 超过此天数的记录将被清理 |
|
||
| 同时删除文件 | 是否删除对应的视频与弹幕文件 |
|
||
|
||
## 运行
|
||
|
||
### 后端
|
||
|
||
```powershell
|
||
dotnet restore LiveRecorder.sln
|
||
dotnet build LiveRecorder.sln --no-restore -m:1
|
||
dotnet run --project src/LiveRecorder.WebApi/LiveRecorder.WebApi.csproj --urls http://localhost:5000
|
||
```
|
||
|
||
默认账号:
|
||
|
||
- 用户名:`admin`
|
||
- 密码:`Admin@123`
|
||
|
||
Swagger:
|
||
|
||
- http://localhost:5000/swagger
|
||
|
||
### 前端
|
||
|
||
```powershell
|
||
cd frontend
|
||
npm install
|
||
npm run dev
|
||
```
|
||
|
||
前端开发服务器:
|
||
|
||
- http://localhost:5173
|
||
|
||
### Docker 部署
|
||
|
||
```powershell
|
||
docker compose up -d
|
||
```
|
||
|
||
- API 服务运行在容器内 `:8080`
|
||
- Nginx 反向代理将 `/api` 转发到 API,其余请求由前端 SPA 处理
|
||
- 默认暴露端口 `HTTP_PORT`(默认 8080)
|
||
- 数据目录 `./data` 与录制目录 `./records` 映射到宿主机
|
||
- 支持多架构构建(`linux/amd64`, `linux/arm64`)
|
||
|
||
### fnOS 原生 FPK
|
||
|
||
```bash
|
||
./scripts/build-fnos-package.sh
|
||
./scripts/smoke-fnos-package.sh \
|
||
artifacts/fnos/liverecorder-1.2.19-x86_64.fpk \
|
||
/path/to/nxsir-postgresql-15.1.1-x86_64.fpk
|
||
```
|
||
|
||
- PostgreSQL 共享服务在独立仓库构建和发布:<https://gitea.nxsir.cn/nanxun/postgresqlfpk>
|
||
- 使用 fnOS 开发者平台提供的官方 `fnpack` 构建;可通过 `FNPACK=/path/to/fnpack` 指定工具路径
|
||
- Live Recorder 与 PostgreSQL 共享服务分别构建为 x86_64 原生 FPK,均不依赖 Docker
|
||
- Live Recorder 直接依赖 `nxsir.postgresql` 和商店版 `nodejs_v22`;fnOS 会通过 `install_dep_apps` 检查并启用依赖
|
||
- PostgreSQL 共享服务只监听 `127.0.0.1:15432`,独立管理界面默认端口为 `15433`
|
||
- 每个应用经回环接入 API 获得独立数据库、独立 SCRAM 角色和随机密码;支持 pgvector
|
||
- PostgreSQL 管理界面有独立管理员登录、客户端/数据库/角色/会话管理、只读 SQL 和手动备份恢复
|
||
- Live Recorder 安装向导会要求设置自身 `admin` 密码,并填写 PostgreSQL 服务的应用接入令牌
|
||
- Live Recorder 1.2.5 仅连接 PostgreSQL 共享服务,不再打包、启动或回退到原内置 PostgreSQL
|
||
- 已删除旧内置 PostgreSQL 自动迁移能力;升级前必须确认应用已经取得共享数据库凭据,遗留数据目录不会被自动删除
|
||
- Node.js 由 fnOS 商店的 `nodejs_v22` 提供,使用 `/var/apps/nodejs_v22/target/bin/node`,Live Recorder FPK 不再内置 Node.js
|
||
- 依赖 fnOS 系统环境同时提供 `ffmpeg` 和 `ffprobe`,安装前请先确认二者可执行
|
||
- Web 管理界面默认使用端口 `18080`
|
||
- PostgreSQL 数据位于其应用持久化目录,手动备份位于共享目录 `postgresql/backups`
|
||
- 录制文件默认保存在 fnOS 共享目录 `liverecorder/records`;可在“设置 → 录制 → 输出根目录”修改
|
||
|
||
更完整的安装、端口与凭据说明见 [docs/postgresql-migration.md](docs/postgresql-migration.md)。
|
||
其他 fnOS 应用接入共享数据库时,请参考独立仓库的 [fnOS PostgreSQL 共享服务接入指南](https://gitea.nxsir.cn/nanxun/postgresqlfpk/src/branch/main/docs/fnos-postgresql-client-integration.md)。
|
||
|
||
## 验证
|
||
|
||
- `dotnet build LiveRecorder.sln --no-restore -m:1`
|
||
- `npm run build`(frontend 目录)
|
||
- `npm run test:e2e`(frontend 目录,覆盖 1920 / 1552 / 1366 / 1024 / 768 / 390)
|
||
- Docker Compose 完整部署验证通过
|
||
|
||
## 后续规划
|
||
|
||
1. 完善 Bilibili 全功能适配,新增虎牙、斗鱼、快手适配器
|
||
2. 按直播间独立配置录制参数
|
||
3. 日志全文搜索与时间范围过滤
|
||
4. 基于 JWT 或外部 SSO 替换轻量 Token 会话
|
||
5. 弹幕回放播放器集成
|
||
6. 录制文件自动上传至 S3/OSS 等对象存储
|