formatting and comments
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
# 组件开发指南
|
||||
|
||||
组件是“一个直播源上的独立功能实例”。当前内建
|
||||
`danmaku_overlay`,未来礼物墙、点歌姬或统计组件都应使用同一套契约。
|
||||
|
||||
## 一个组件由什么组成
|
||||
|
||||
| 部分 | Rust 契约 | 职责 |
|
||||
| -------- | --------------------- | ------------------------------------------------- |
|
||||
| 定义 | `ComponentDefinition` | kind、设置版本、默认值、校验、迁移、订阅 |
|
||||
| 投影 | `EventProjection` | 把 `LiveEvent` 转成浏览器消息,不执行持久化副作用 |
|
||||
| Handler | `EventHandler` | 可选的数据库写入、点歌或外部动作 |
|
||||
| 实例 | `ComponentInstance` | owner、source、kind、名称、设置和启用状态 |
|
||||
| 实时通道 | `EventHub` | 按 component ID 隔离的有界广播 |
|
||||
| 前端 | React renderer/editor | 管理设置、测试与 OBS 展示 |
|
||||
|
||||
## 新增组件步骤
|
||||
|
||||
1. 选择稳定、全小写的 kind,例如 `gift_wall` 或 `song_request`。
|
||||
2. 为设置定义可序列化结构,提供安全默认值和 `sanitize`/校验逻辑。
|
||||
3. 实现 `ComponentDefinition`:
|
||||
- `settings_version` 从 `1` 开始。
|
||||
- `migrate_settings` 必须能把已保存的旧版本升级到当前版本。
|
||||
- `subscriptions` 只返回当前设置需要的 `LiveEventKind`。
|
||||
4. 实现无副作用的 `EventProjection`。返回 `None` 表示该事件无需发送浏览器。
|
||||
5. 若需要可靠业务动作,实现 `EventHandler`:
|
||||
- 即使没有 OBS 客户端也会执行。
|
||||
- 数据库操作必须包含 owner/source/component 条件。
|
||||
- 上游可能重试或出现组合事件,因此 handler 自己负责幂等。
|
||||
6. 在 `ComponentRegistry::with_builtin_components` 注册定义与投影,再注册 handler。
|
||||
7. 增加数据库创建/设置 API;不要把组件专属关系数据无限塞入 JSON settings。
|
||||
8. 在控制台增加设置编辑器,在 OBS 前端增加对应事件渲染器。
|
||||
9. 增加以下测试:设置边界、版本迁移、订阅、跨租户拒绝、handler 幂等、投影 wire shape 和 OBS 渲染。
|
||||
|
||||
## Projection 与 Handler 的边界
|
||||
|
||||
Projection 面向“现在打开的浏览器”。消息丢失或没有接收者都属于正常情况。它必须快速、确定、无副作用。
|
||||
|
||||
Handler 面向“业务事实”。例如点歌请求、礼物累计或审计写入必须在这里完成,而不是等待前端收到 WebSocket。一个 handler 失败会记录在
|
||||
`RouteReport`,但不会阻止其他 handler 或 OBS 投影。
|
||||
|
||||
## 设置版本规则
|
||||
|
||||
- 数据库同时保存 `settings` 与 `settings_version`。
|
||||
- 每次读取或路由前,通过 registry 迁移并校验设置。
|
||||
- 新字段应提供默认值,删除/改义字段必须增加版本并编写迁移。
|
||||
- 客户端输入只能作为待校验 JSON;后端返回的 sanitized 设置才是权威值。
|
||||
- UI slider 的范围不能代替后端范围检查。
|
||||
|
||||
## 租户与 token 规则
|
||||
|
||||
- 组件必须属于同一个 owner 与 source。
|
||||
- 路由和数据库查询都要重复检查这一关系。
|
||||
- 每个组件单独签发 access token,默认只有 `events:subscribe`。
|
||||
- 删除组件或轮换 token 时,关闭该组件 channel,使已有 socket 立即失效。
|
||||
- 组件 WebSocket 不得暴露其他组件列表或控制 API。
|
||||
|
||||
当前组件的具体行为见 [`danmaku-overlay.md`](danmaku-overlay.md)。
|
||||
@@ -0,0 +1,66 @@
|
||||
# `danmaku_overlay` 弹幕姬
|
||||
|
||||
弹幕姬把一个租户直播源的互动事件投影为透明 OBS 消息墙。它是被动展示组件:不记账、不回复弹幕,也不把 WebSocket 当作持久化业务通道。
|
||||
|
||||
## 订阅事件
|
||||
|
||||
组件根据设置动态订阅:
|
||||
|
||||
- 弹幕、进房、礼物与礼物连击、醒目留言、舰长、点赞、分享。
|
||||
- 关闭类别后,后端不为该组件投影对应事件,前端也会进行一次兼容性过滤。
|
||||
- 未归一化的 `live.unknown` 默认不进入弹幕姬。
|
||||
|
||||
## 设置
|
||||
|
||||
| 字段 | 范围/单位 | 行为 |
|
||||
| ------------------------ | ----------- | -------------------------- |
|
||||
| `fontScale` | 50–300% | 展开与收缩字号的统一比例 |
|
||||
| `maxVisible` | 1–12 | 同时保留的消息卡数量 |
|
||||
| `collapseAfterSeconds` | 2–120 秒 | 最新卡从展开态切换到紧凑态 |
|
||||
| `unfoldDurationMs` | 200–5000 ms | 横向卷轴展开动画时间 |
|
||||
| `motionIntensity` | 0–100% | 卡片、流光与焦点动画强度 |
|
||||
| `particleCount` | 0–12 | 每卡星花粒子数量 |
|
||||
| `particleSpeed` | 25–300% | 粒子动画速度 |
|
||||
| `lowPerformanceMode` | boolean | 关闭高成本动态效果 |
|
||||
| `highValueThreshold` | 千分之一元 | 高价值礼物起点 |
|
||||
| `featuredValueThreshold` | 千分之一元 | 焦点礼物起点 |
|
||||
| `show*` | boolean | 控制各事件类别订阅 |
|
||||
|
||||
后端的 `OverlaySettings::sanitize` 是最终边界。控制台 range input 只改善交互,不能取代服务端校验。
|
||||
|
||||
## 卡片生命周期
|
||||
|
||||
1. 新事件插入队首,以卷轴动画横向展开。
|
||||
2. 用户名与内容在展开态分行显示,长内容完整换行。
|
||||
3. 新事件到达或超时后,旧卡变成紧凑态;内容不会隐藏。
|
||||
4. 紧凑态缩小字号并尽量压缩布局,但仍允许换行避免截断。
|
||||
5. 超过 `maxVisible` 的最旧卡才会离开队列。
|
||||
|
||||
花纹由事件类型和事件 ID 的稳定 hash 选择。相邻卡会避开完全相同的款式;礼物连击更新沿用原卡片 key 和装饰,避免视觉跳动。
|
||||
|
||||
## 礼物展示
|
||||
|
||||
- `live.gift` 创建礼物卡;`live.gift.combo` 使用 `comboId` 更新同一张卡。
|
||||
- 元数据优先使用礼物目录中的静态图、GIF、币种和价格。
|
||||
- GIF 加载失败时降级为静态图片;静态图失败时隐藏图片但保留名称、数量和用户。
|
||||
- 普通、高价值和焦点礼物按 `totalPrice` 与两个阈值分级。
|
||||
- `priceCny` 只用于人类可读展示;整数 `totalPrice` 用于精确分级。
|
||||
|
||||
## 弹幕表情
|
||||
|
||||
文字和表情按 `segments` 顺序混排。表情 URL 来自消息本身或用户级表情目录补全;图片使用
|
||||
`no-referrer`,失败后显示原始表情文字。整条大表情可通过 `standalone` 使用更合适的尺寸。
|
||||
|
||||
## OBS 自适应
|
||||
|
||||
- 根背景完全透明,不存在 1920×1080 固定画布。
|
||||
- `ResizeObserver` 根据浏览器源实际宽高选择 `narrow`、`short` 或 `standard`。
|
||||
- 字号和间距使用 CSS custom properties 与 `clamp()`,OBS 自由缩放时不拉伸素材比例。
|
||||
- 建议从 `360×600`、`440×760`、`600×1080` 或 `720×320` 开始测试。
|
||||
- 低高度会减少视觉密度,但不会把仍在队列中的文字裁成省略号。
|
||||
|
||||
## 测试页面
|
||||
|
||||
控制台的事件测试直接构造 canonical
|
||||
`LiveEvent`,使用当前账户、source 和 component 走同一套订阅、handler、projection 与 EventHub。测试事件标记为
|
||||
`simulated=true`,不会发送到 Bilibili,也不会跨组件广播。
|
||||
Reference in New Issue
Block a user