app-template/docs/superpowers/specs/2026-09-26-dandanplay-capab...

8.1 KiB
Raw Blame History

对齐弹弹play能力(核心链路 + 协议/数据格式)— 设计规格

  • 日期:2026-09-26
  • 状态:设计已获用户批准,待规格审查 → writing-plans
  • 仓库:本产品仓(业务进入现有分层 + 新增 @app/danmaku)
  • 前置:2026-09-25-dandanplay-web-design.md(Web 版弹弹play 主体)已实现主链路

1. 目标与范围

在已有「挂载 → 找片 → 播放 → 弹幕 → 进度」之上,把弹幕能力与弹弹play 开放弹幕网络在体验与协议上对齐。

In scope

  1. 协议/数据兼容
    • 开放 API:/api/v2/match、/api/v2/comment/{episodeId}(含 withRelated)、AppId 签名
    • 数据格式:文件识别 hash(前 16MB MD5)、B 站/弹弹play 兼容弹幕 XML、匹配元数据
  2. 核心链路深对齐
    • 候选集匹配与手选(不盲取第一条)
    • 弹幕持久化与同目录自动关联(修 P1-3)
    • 关联弹幕与渲染体验(withRelated、prefs 服务端同步)
    • 弹幕过滤与屏蔽(关键词、类型)

Out of scope(YAGNI)

  • 远程访问协议(弹弹play 连帆幕)
  • protobuf 弹幕、多弹幕站聚合
  • BT/RSS、AI 字幕、投屏、Emby/Jellyfin 直连(见产品文档「还没有」)

验收口径:真实链路可跑通(文件 → 匹配候选 → 手选 → 拉弹幕 → 过滤 → 持久化,刷新/多设备可恢复)。无凭证时降级路径也要可用。

实现路径(用户选定):方案 B — 独立 @app/danmaku 协议包(非垂直增强、非先契约后功能)。

2. 架构与包边界

新增纯协议包 @app/danmaku:无 DB、无 tRPC;HTTP 仅用全局 fetch。

模块 职责
signature base64(sha256(AppId + Timestamp + Path + AppSecret))
hash 文件头 16MB MD5(流式,禁止整文件缓冲)
match POST /api/v2/match 入参/出参、hashAndFileName / fileNameOnly、候选排序纯函数
comment GET /api/v2/comment/{episodeId}、withRelated、comments 结构化
xml B 站/弹弹play 兼容 XML 解析与序列化(p 字段双向)
types EpisodeId、MatchCandidate、DanmakuComment 等纯类型
filter filterComments(关键词、类型、防重叠可选)

依赖方向(只新增向下边,禁止循环):

web ──► trpc ──► dao ──► db ──► models
 │        │
 │        ├──► types
 │        └──► danmaku(协议包)
 └──► danmaku(XML 解析复用)
  • trpc danmaku.service:鉴权、落库、缓存、绑定编排 + 调 @app/danmaku
  • web:danmaku-render.ts 格式解析改为引用 @app/danmaku 的 xml(单一解析实现)
  • 包位置:packages/danmaku,构建方式对齐 @app/types(vite + tsc dts)

3. 数据模型

Schema 源仍为 @app/models;查询进 @app/dao。

media_items 增列

字段 说明
dandanEpisodeId 开放网络 episodeId;空 = 未绑定
danmakuMatchSource auto | manual | none
danmakuMatchedAt 上次匹配时间

danmaku_prefs(用户级,新表)

userId · enabled · opacity · density · blockKeywords(JSON) · blockTypes(JSON) · updatedAt
唯一 (userId)。blockTypes:scroll / top / bottom。

danmaku_docs(正文持久化,新表,修 P1-3)

id · userId · mediaItemId · source: open-network|local-xml|related · xml · byteSize · createdAt
唯一 (userId, mediaItemId, source)(同源仅留最新)。userId 级隔离。

danmaku_cache(保留,全局共享)

未绑定时 matchKey = sha256(path:size);绑定后缓存键改为 episodeId(集身份比文件身份稳定)。

Zod(@app/types)

  • danmakuMatchSelectSchema(mediaItemId + episodeId)
  • danmakuImportSchema(替代仅 byteSize 的 importMeta,可含 fileName)
  • danmakuPrefsSchema(含 blockKeywords / blockTypes)
  • 输出:MatchCandidate[]、DanmakuFetchOutput(source 扩展 local-xml 等)

4. 协议/数据格式对齐

对齐点 规范
文件识别 前 16MB MD5 + 文件名;有 hash 用 hashAndFileName,否则 fileNameOnly
匹配 POST /api/v2/match → matches[];按置信/用户选择写入 dandanEpisodeId
弹幕 GET /api/v2/comment/{id}?withRelated=true
鉴权 X-AppId / X-Timestamp / X-Signature(现有算法保留 + 单测向量)
XML <d p="time,mode,size,color,timestamp,pool,uid,rowid">text</d>;round-trip 测试
降级 无凭证/失败 → 本地 XML 仍可用

环境变量沿用:OPEN_DANMAKU_APP_ID / OPEN_DANMAKU_APP_SECRET / OPEN_DANMAKU_API_BASE。

5. 页面与交互

路由不变;只增强 /watch、/danmaku 等组件。

候选集匹配与手选

  1. 打开 /watch:无 dandanEpisodeId → 自动 match → 高置信绑定(source=auto)→ 拉弹幕
  2. 未匹配/低置信 → 「重新匹配」→ 候选列表(标题、集数、类型、置信)→ 点选绑定(source=manual)→ 立即拉弹幕
  3. 已绑定可「更换匹配」;弹幕集绑定与 Bangumi 绑定相互独立

弹幕持久化与自动关联

  • 导入 XML → 服务端 danmaku_docs(source=local-xml)(≤20MB)→ 刷新/换端可恢复
  • 播放优先级:本地已导入 > 开放网络
  • 浏览/扫描发现同目录 同名.xml → 登记 local-xml(正文按需从 WebDAV 拉取)→ 播放页提示「发现同名弹幕」

关联弹幕与渲染体验

  • withRelated 并入;过滤面板可显示本集/关联计数
  • 继续用 artplayer-plugin-danmuku;danmaku_prefs 服务端同步(开关/透明度/密度),localStorage 仅作无网络回退
  • 密度 thinDanmaku 仍在客户端

弹幕过滤与屏蔽

  • 播放页过滤面板:关键词、类型(滚动/顶部/底部)、防重叠(插件已有)
  • 设置页:默认值 + 屏蔽词编辑 → danmaku_prefs
  • 过滤在 XML → comments 之后、喂播放器之前执行(filterComments 纯函数)

6. 错误处理

场景 策略
无开放网络凭证 明确提示「未配置弹幕网络」;本地 XML 全功能可用
match 401/签名失败 Toast 鉴权失败;不重试风暴
match 无候选/低置信 进手选候选面板,不静默
comment 失败 保留绑定;可重试;本地 XML 优先
XML 解析失败 导入报错拒绝;自动关联静默跳过
prefs 失败 回退 localStorage 会话级;不阻断播放
权限 docs / prefs / 绑定均强制 userId 隔离

7. 测试与验证

@app/danmaku 单测:签名向量、16MB MD5、XML round-trip、filterComments、候选排序;match/comment 用 fixture 锁字段名。

service 测:绑定持久化、导入落库、prefs upsert、缓存键(path:size → episodeId)切换。

真实链路清单(验收)

  1. 配置凭证 → 未绑定视频自动匹配 → 弹幕上屏
  2. 低置信 → 手选 → 绑定刷新仍有效
  3. 导入 XML → 刷新/换端登录仍在
  4. 同目录同名 XML 自动关联
  5. 关联弹幕计入;屏蔽词/类型即时生效且持久
  6. 断网/无凭证降级:可播、本地 XML 可用

命令:yarn typecheck · yarn lint · yarn test · yarn build:web

8. 风险与开放问题

  1. 凭证:当前 .env 的 OPEN_DANMAKU_APP_ID 为空。真实链路需提供 AppId/AppSecret,或先用 OPEN_DANMAKU_API_BASE 指向 mock 跑通再切官方。
  2. 开放 API 字段:实现时以 doc.dandanplay.com/open 实测为准;fixture 与适配器单点收口在 @app/danmaku。
  3. 同目录 XML 自动关联:避免扫描时全量拉 WebDAV 正文;按需拉取 + 缓存。
  4. 协议包勿膨胀:若未来要多端复用再抽;本规格不做远程访问协议。

9. 批准记录

节 结果
§1 架构与包边界 OK(方案 B)
§2 数据模型 + 协议/数据格式 OK
§3 页面与交互(四块) OK
§4 错误处理 + 测试验证 OK
验收口径 真实链路可跑通
范围 协议/数据兼容 + 核心四块全选