docs: 完善 README 并修复暗黑模式左侧导航栏可见性
This commit is contained in:
parent
89ba4163fc
commit
c161660b51
349
README.md
349
README.md
@ -1,157 +1,217 @@
|
||||
# Live Recorder
|
||||
|
||||
Live Recorder is a multi-platform live recording system built with:
|
||||
Live Recorder 是一个多平台直播录制系统,支持自动检测开播、实时录制、弹幕采集、通知推送与事件脚本编排。
|
||||
|
||||
- Backend: `.NET 8 Web API + EF Core + SQLite`
|
||||
- Frontend: `Vue 3 + TypeScript + Element Plus`
|
||||
- 后端:`.NET 8 Web API + EF Core + SQLite`
|
||||
- 前端:`Vue 3 + TypeScript + Element Plus`
|
||||
|
||||
The current production-ready adapter is `DouyinLivePlatformAdapter`. The architecture keeps platform-specific logic isolated so Bilibili, Huya, Douyu, and Kuaishou can be added without changing application services.
|
||||
当前已适配 **抖音**(Douyin)与 **Bilibili**(部分),架构将平台特有逻辑隔离在 `Platforms` 目录下,新增虎牙、斗鱼、快手等平台无需改动应用层服务。
|
||||
|
||||
## Architecture
|
||||
## 目录结构
|
||||
|
||||
```text
|
||||
.
|
||||
├─ src
|
||||
│ ├─ LiveRecorder.Domain
|
||||
│ │ ├─ Entities
|
||||
│ │ └─ Enums
|
||||
│ ├─ LiveRecorder.Application
|
||||
│ │ ├─ Abstractions
|
||||
│ │ ├─ Common
|
||||
│ │ ├─ Models
|
||||
│ │ └─ Services
|
||||
│ ├─ LiveRecorder.Infrastructure
|
||||
│ │ ├─ Persistence
|
||||
│ │ ├─ Platforms
|
||||
│ │ │ ├─ Douyin
|
||||
│ │ │ ├─ Bilibili
|
||||
│ │ │ └─ Huya
|
||||
│ │ └─ Services
|
||||
│ └─ LiveRecorder.WebApi
|
||||
│ ├─ Controllers
|
||||
│ └─ Middleware
|
||||
└─ frontend
|
||||
└─ src
|
||||
├─ api
|
||||
├─ components
|
||||
├─ router
|
||||
├─ stores
|
||||
└─ views
|
||||
│ ├─ 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
|
||||
```
|
||||
|
||||
## Core design
|
||||
## 核心功能
|
||||
|
||||
### Domain
|
||||
### 直播录制
|
||||
|
||||
- `LiveRoom`: platform, room id, source URL, title, anchor, cover, availability status
|
||||
- `RecordTask`: recording state, quality, output format, ffmpeg process id, output path
|
||||
- `RecordResult`: final file or segment directory, file size, duration, final status
|
||||
- `SystemLogEntry`: persistent system log
|
||||
- `AppSetting`: runtime settings store
|
||||
- `UserAccount`, `UserSession`: lightweight token-based sign-in
|
||||
- 支持分享链接与短链解析,自动提取真实房间号
|
||||
- 后台轮询检测直播状态,可配置轮询间隔与自动录制开关
|
||||
- 支持 `MP4`(单文件)与 `TS`(分段)两种输出格式
|
||||
- 内置三种录制模板:`StreamCopy`、`BalancedMp4`、`ArchiveTs`
|
||||
- 断线重连:可配置重连开关、最大重连延迟、读写超时
|
||||
- 存储守护:启动前检查磁盘剩余空间,不足时拒绝录制
|
||||
|
||||
### Application
|
||||
### 弹幕采集
|
||||
|
||||
- `ILivePlatformAdapter`
|
||||
- `ParseRoomAsync`
|
||||
- `GetLiveStatusAsync`
|
||||
- `GetStreamUrlAsync`
|
||||
- `ILivePlatformAdapterFactory`
|
||||
- `LiveRoomService`
|
||||
- `RecordService`
|
||||
- `SystemSettingsService`
|
||||
- `SystemLogService`
|
||||
- `AuthService`
|
||||
弹幕通过 WebSocket 实时连接各平台的弹幕服务器,以 XML 格式分段写入文件。
|
||||
|
||||
### Infrastructure
|
||||
- **抖音弹幕**:通过 `webcast/im/fetch/` 获取连接信息,建立 WSS 长连接,使用 `a_bogus` 签名算法(基于 `dycast` 开源项目的 `abogus.js`),支持 Protobuf 解码
|
||||
- **Bilibili 弹幕**:通过 Bilibili 直播 WebSocket 协议连接弹幕服务器,支持聊天、进入、关注、礼物等事件
|
||||
- 弹幕事件类型:聊天(chat)、礼物(gift)、点赞(like)、进入(enter)、关注(member)等
|
||||
- 弹幕录制可按设置只保留聊天弹幕或包含所有事件类型
|
||||
- 弹幕文件与视频文件同目录、同名(`.xml` 扩展名),内部以结构化 XML 保存
|
||||
|
||||
- `DouyinHttpClient`
|
||||
- wraps User-Agent, Referer, Cookie, and `ttwid` handling
|
||||
- `DouyinLivePlatformAdapter`
|
||||
- share-link resolution, room id extraction, status check, stream selection
|
||||
- `FfmpegService`
|
||||
- single file mode, segmented mode, reconnect arguments, recording templates
|
||||
- `LiveRoomPollingBackgroundService`
|
||||
- background polling scheduler for live detection and auto-start recording
|
||||
- `LiveRecorderDbContext`
|
||||
### 通知推送
|
||||
|
||||
### Web API
|
||||
- **邮件通知**:支持 SMTP 配置、SSL、自定义发件人与 HTML 模板
|
||||
- 开播提醒:直播间上线时发送
|
||||
- 异常提醒:录制异常时发送
|
||||
- 模板变量:`{{appName}}`、`{{anchor}}`、`{{title}}`、`{{summary}}`、`{{detail}}` 等
|
||||
- **Webhook 通知**:支持自定义 URL、请求头、超时配置
|
||||
- 开播事件与异常事件分别可独立开关
|
||||
- 支持测试发送验证连通性
|
||||
- 负载包含直播间信息、录制任务信息等完整上下文
|
||||
|
||||
- `AuthController`
|
||||
- `LiveRoomsController`
|
||||
- `RecordTasksController`
|
||||
- `LogsController`
|
||||
- `SettingsController`
|
||||
- `ApiTokenAuthenticationMiddleware`
|
||||
- `ExceptionHandlingMiddleware`
|
||||
### 事件脚本
|
||||
|
||||
## Implemented features
|
||||
支持在关键生命周期节点执行自定义脚本(Shell / PowerShell 内联或外部脚本文件):
|
||||
|
||||
### Douyin adapter
|
||||
| 事件 | 说明 |
|
||||
|------|------|
|
||||
| `live_started` | 检测到直播上线时触发 |
|
||||
| `live_ended` | 检测到直播下线时触发 |
|
||||
| `segment_completed` | 一个录制分片完成时触发 |
|
||||
|
||||
- resolve share links and redirects
|
||||
- extract real `roomId`
|
||||
- call `https://live.douyin.com/webcast/room/web/enter/`
|
||||
- preload `ttwid` when needed
|
||||
- parse both:
|
||||
- `live_core_sdk_data.pull_data.stream_data`
|
||||
- `flv_pull_url / hls_pull_url_map`
|
||||
- select the highest quality by default or respect configured quality
|
||||
脚本通过环境变量获取上下文信息:
|
||||
|
||||
### Background polling scheduler
|
||||
```
|
||||
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)
|
||||
```
|
||||
|
||||
- configurable polling interval
|
||||
- configurable enable/disable switch
|
||||
- configurable auto-start switch
|
||||
- updates room status in background
|
||||
- auto-creates a recording task when a room is live and no task is running
|
||||
- also works as a recovery layer when ffmpeg exits unexpectedly while the room is still live
|
||||
支持超时控制与自定义日志输出。
|
||||
|
||||
### Recording enhancements
|
||||
### 异常恢复(Recovery)
|
||||
|
||||
- save format setting: `MP4` or `TS`
|
||||
- save mode setting:
|
||||
- `SingleFile`
|
||||
- `Segmented`
|
||||
- recording template setting:
|
||||
- `StreamCopy`
|
||||
- `BalancedMp4`
|
||||
- `ArchiveTs`
|
||||
- reconnect tuning:
|
||||
- enable/disable reconnect
|
||||
- max reconnect delay
|
||||
- read/write timeout
|
||||
- 自动检测处于 Live 状态但未在录制的直播间
|
||||
- 自动检测录制完成但未做最终化(MP4 remux)的任务
|
||||
- 支持一键重试录制或逐一恢复
|
||||
- 后台轮询调度器同时兼具恢复层功能:当 ffmpeg 异常退出而直播间仍在直播时自动重新创建录制任务
|
||||
|
||||
### Frontend
|
||||
### 数据保留清理(Retention)
|
||||
|
||||
- login page
|
||||
- live room management
|
||||
- recording task list
|
||||
- recording task detail
|
||||
- log viewer
|
||||
- system settings
|
||||
- route lazy loading
|
||||
- vendor chunk splitting in Vite
|
||||
- 可配置保留天数,超期自动清理录制记录、弹幕文件、视频文件与系统日志
|
||||
- 支持后台定时清理(每 24 小时执行一次)
|
||||
|
||||
## Settings exposed in UI
|
||||
### 每日回顾(Daily Review)
|
||||
|
||||
- ffmpeg path
|
||||
- output root
|
||||
- default quality
|
||||
- live save format
|
||||
- save mode
|
||||
- recording template
|
||||
- segment duration
|
||||
- reconnect switch and reconnect delay
|
||||
- read/write timeout
|
||||
- background polling switch
|
||||
- auto-start-on-live switch
|
||||
- polling interval
|
||||
- Douyin User-Agent / Referer / Cookie
|
||||
- 按日期查看当天所有录制会话的汇总信息
|
||||
- 亮点卡片:最长录制、最多弹幕、最多异常等
|
||||
- 时间线视图展示会话与分片时间段
|
||||
- 弹幕数量随时间分布的可视化数据
|
||||
|
||||
## Run
|
||||
### 系统日志
|
||||
|
||||
### Backend
|
||||
- 持久化系统日志,支持按类别、时间筛选
|
||||
- 日志关联直播间、录制会话、录制任务
|
||||
- 可在前端日志页面实时查看
|
||||
|
||||
### 前端界面
|
||||
|
||||
- 登录页
|
||||
- 直播间管理(添加、编辑、删除、状态查看、快速录制)
|
||||
- 录制任务列表与详情
|
||||
- 录制会话列表与详情
|
||||
- 日志查看器
|
||||
- 每日回顾
|
||||
- 异常恢复页面
|
||||
- 系统设置(录制、通知、弹幕、事件脚本、保留策略、平台配置)
|
||||
- 路由懒加载,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}` `{yyyy}` `{MM}` `{dd}` `{HHmmss}` 等变量 |
|
||||
| 默认画质 | 优先选择的流画质 |
|
||||
| 保存格式 | MP4 / TS |
|
||||
| 保存模式 | 单文件 / 分段 |
|
||||
| 分段时长 | 分段模式下的每段时长(秒) |
|
||||
| 录制模板 | StreamCopy / BalancedMp4 / ArchiveTs |
|
||||
| 重连开关 | 断线后是否自动重连 |
|
||||
| 最大重连延迟 | 重连退避最大秒数 |
|
||||
| 读写超时 | 网络读写超时秒数 |
|
||||
| 存储守护 | 启用磁盘空间检查 |
|
||||
| 最低剩余空间 | 存储守护的最低空间阈值(GB) |
|
||||
|
||||
### 弹幕设置
|
||||
| 设置 | 说明 |
|
||||
|------|------|
|
||||
| 启用弹幕录制 | 录制时是否同时采集弹幕 |
|
||||
| 包含非聊天事件 | 是否记录进入、关注、礼物等非聊天弹幕 |
|
||||
| 最小轮询间隔 | 弹幕连接重试的最小间隔(毫秒) |
|
||||
| 最大重试延迟 | 弹幕连接重试退避最大秒数 |
|
||||
|
||||
### 通知设置
|
||||
| 设置 | 说明 |
|
||||
|------|------|
|
||||
| 启用邮件通知 | SMTP 邮件通知总开关 |
|
||||
| SMTP 服务器 / 端口 / SSL / 账号 | 邮件服务器配置 |
|
||||
| 开播提醒 / 异常提醒 | 分别控制是否发送 |
|
||||
| HTML 模板 | 可自定义邮件 HTML 模板,支持变量占位 |
|
||||
| 启用 Webhook | Webhook 推送总开关 |
|
||||
| Webhook URL / 请求头 / 超时 | Webhook 配置 |
|
||||
| 开播通知 / 异常通知 | 分别控制是否推送 |
|
||||
|
||||
### 事件脚本设置
|
||||
| 设置 | 说明 |
|
||||
|------|------|
|
||||
| 启用事件脚本 | 总开关 |
|
||||
| 开播脚本 / 下播脚本 / 分片完成脚本 | 分别控制与配置 |
|
||||
| 脚本模式 | 内联脚本 / 外部文件 |
|
||||
| 超时(秒) | 脚本执行超时限制 |
|
||||
|
||||
### 保留策略
|
||||
| 设置 | 说明 |
|
||||
|------|------|
|
||||
| 启用保留清理 | 是否开启自动清理 |
|
||||
| 保留天数 | 超过此天数的记录将被清理 |
|
||||
| 同时删除文件 | 是否删除对应的视频与弹幕文件 |
|
||||
|
||||
## 运行
|
||||
|
||||
### 后端
|
||||
|
||||
```powershell
|
||||
dotnet restore LiveRecorder.sln
|
||||
@ -159,16 +219,16 @@ dotnet build LiveRecorder.sln --no-restore -m:1
|
||||
dotnet run --project src/LiveRecorder.WebApi/LiveRecorder.WebApi.csproj --urls http://localhost:5000
|
||||
```
|
||||
|
||||
Default account:
|
||||
默认账号:
|
||||
|
||||
- username: `admin`
|
||||
- password: `Admin@123`
|
||||
- 用户名:`admin`
|
||||
- 密码:`Admin@123`
|
||||
|
||||
Swagger:
|
||||
Swagger:
|
||||
|
||||
- [http://localhost:5000/swagger](http://localhost:5000/swagger)
|
||||
- http://localhost:5000/swagger
|
||||
|
||||
### Frontend
|
||||
### 前端
|
||||
|
||||
```powershell
|
||||
cd frontend
|
||||
@ -176,18 +236,33 @@ npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Frontend dev server:
|
||||
前端开发服务器:
|
||||
|
||||
- [http://localhost:5173](http://localhost:5173)
|
||||
- http://localhost:5173
|
||||
|
||||
## Verified locally
|
||||
### Docker 部署
|
||||
|
||||
```powershell
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
- API 服务运行在容器内 `:8080`
|
||||
- Nginx 反向代理将 `/api` 转发到 API,其余请求由前端 SPA 处理
|
||||
- 默认暴露端口 `HTTP_PORT`(默认 8080)
|
||||
- 数据目录 `./data` 与录制目录 `./records` 映射到宿主机
|
||||
- 支持多架构构建(`linux/amd64`, `linux/arm64`)
|
||||
|
||||
## 验证
|
||||
|
||||
- `dotnet build LiveRecorder.sln --no-restore -m:1`
|
||||
- `npm run build`
|
||||
- `npm run build`(frontend 目录)
|
||||
- Docker Compose 完整部署验证通过
|
||||
|
||||
## Next steps
|
||||
## 后续规划
|
||||
|
||||
1. Implement full adapters for Bilibili, Huya, Douyu, and Kuaishou.
|
||||
2. Add per-room recording preferences instead of relying only on global defaults.
|
||||
3. Add full-text log search and time-range filters.
|
||||
4. Replace lightweight token sessions with JWT or external SSO if needed.
|
||||
1. 完善 Bilibili 全功能适配,新增虎牙、斗鱼、快手适配器
|
||||
2. 按直播间独立配置录制参数
|
||||
3. 日志全文搜索与时间范围过滤
|
||||
4. 基于 JWT 或外部 SSO 替换轻量 Token 会话
|
||||
5. 弹幕回放播放器集成
|
||||
6. 录制文件自动上传至 S3/OSS 等对象存储
|
||||
|
||||
@ -393,7 +393,18 @@ async function handleLogout() {
|
||||
}
|
||||
|
||||
:global(html[data-theme="dark"]) .app-sidebar {
|
||||
background: linear-gradient(180deg, rgba(255, 255, 255, 0.02), rgba(255, 255, 255, 0));
|
||||
background: var(--bg-subtle);
|
||||
border-right-color: var(--border-base);
|
||||
}
|
||||
|
||||
:global(html[data-theme="dark"]) .app-nav-menu :deep(.el-menu-item.is-active) {
|
||||
background: linear-gradient(180deg, rgba(91, 168, 255, 0.18), rgba(91, 168, 255, 0.1));
|
||||
box-shadow: inset 0 0 0 1px rgba(91, 168, 255, 0.2);
|
||||
}
|
||||
|
||||
:global(html[data-theme="dark"]) .app-nav-icon-item.is-active {
|
||||
background: linear-gradient(180deg, rgba(91, 168, 255, 0.18), rgba(91, 168, 255, 0.1));
|
||||
box-shadow: inset 0 0 0 1px rgba(91, 168, 255, 0.2);
|
||||
}
|
||||
|
||||
.app-sidebar--collapsed {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user