8.6 KiB
8.6 KiB
Web 版弹弹play(媒体中心)— 设计规格
- 日期:2026-09-25
- 状态:已获设计批准,待实现计划(writing-plans)
- 仓库:
app-template(按产品仓维护,业务进入现有分层)
1. 背景与调研结论
弹弹play 官方定位是本地视频 + 在线弹幕的全功能播放器(非音乐播放器),能力包括智能识别、媒体库、AI 字幕、远程访问(浏览器可连 PC 内嵌 API)、媒体库可挂 SMB/WebDAV/Emby 等。
本项目要做的是:独立 Web 应用(方案 A),提供类似的「挂载源 → 浏览 → 播放 + 弹幕 → 媒体库/进度」体验,不依赖本机运行的 PC 弹弹play。
| 能力 | 决策 |
|---|---|
| 范围 | A — 独立完整 Web 应用 |
| 播放器 | ArtPlayer |
| 弹幕 | 对接弹弹play 开放弹幕网络(服务端中继)+ 本地 XML 导入兜底 |
| 存储源 | 仅通用 WebDAV(OpenList 使用其 WebDAV 端点;不做 OpenList 原生 API) |
| 后端 | 挂载代理 + 弹幕中继 + 媒体库/进度 全做 |
| 刮削 | Bangumi:扫描自动匹配 + 手动搜索改绑(C) |
| UI | 全页面:播放 / 文件浏览 / 媒体库 / 挂载管理 / 弹幕设置 |
| 账号 | 多用户:注册登录;每人独立库与进度 |
| 架构方案 | A — 紧凑垂直切片 media(复制 user 切片模式) |
| 视觉 | shadcn/ui Dashboard 风格(侧栏 + 卡片 + 中性灰阶),不以模板深空工业 HUD 为产品主视觉 |
| 落点 | B — 产品化本仓:业务进入 app/web、packages/* |
调研来源(Browser Use 实读)
- https://www.dandanplay.com/ — 产品能力与远程访问/WebDAV 叙述
- https://doc.dandanplay.com/open/library-api.html — PC 远程访问 REST(本项目不对接;仅作产品对照)
- https://doc.dandanplay.com/function/media-library.html — 媒体库信息架构参考
- https://github.com/OpenListTeam/OpenList — AList fork;本项目只用 WebDAV 接入方式
说明:会话内 IAB 不可用,调研经
cua_repl+managed-chromium完成 SERP 与正文阅读。
2. 系统架构(方案 A)
浏览器 @app/web(React islands,shadcn dashboard)
├─ 登录 / 媒体库 / 文件浏览 / 播放(ArtPlayer+弹幕) / 挂载 / 弹幕设置
└─ 仅经 tRPC 与 /api/stream(Range)访问
│
▼
服务层 trpc + service + dao(@app/trpc · dao)
├─ mount.* WebDAV 列目录、凭据加密、测试连接
├─ stream Range 拉流代理
├─ danmaku.* 开放弹幕网络中继 + 缓存
├─ scrape.* Bangumi 搜索/绑定;扫描内自动刮削
├─ library.* 扫描入库、列表、海报
└─ playback.* 进度节流写入
│
┌─────┴──────┐
▼ ▼
Drizzle/Turso 外部:WebDAV · 弹弹play 开放弹幕网络 · Bangumi API
分层约束(沿用仓库 AGENTS)
- Schema 源:
@app/models;查询:@app/dao;连接:@app/db - 业务逻辑:
@app/trpcservice(调 dao);入参 Zod:@app/types - UI:
@app/ui+ design tokens;页面在@app/web - 产品化本仓:新增业务实体照
user垂直切片扩展(本产品期间业务代码进入现有分层,视为对「模板不掺业务」的产品化豁免)
播放主路径
- 登录 → 2. 配置 WebDAV 挂载 → 3. 浏览目录或扫描入库
- 打开视频 → stream 代理 → ArtPlayer
- 识别/拉弹幕(中继 +
danmaku_cache)→ 弹幕层 - 节流上报
playback_progress
首版不做
OpenList 原生 API · 本机弹弹play 远程 API 对接 · BT/RSS · 多刮削源 · NFO 优先 · 公网多租户硬化(SSO/套餐限流)
3. 数据模型
users(已有 auth)
沿用模板用户表与会话,不重复造账号。
mounts
| 字段 | 说明 |
|---|---|
| id | PK |
| userId | → users,级联隔离 |
| name | 展示名 |
| type | 固定 webdav(预留枚举) |
| baseUrl | WebDAV 根 URL(含 OpenList WebDAV 地址) |
| username | 可选 |
| secretEnc | 服务端加密密文;API 永不回传明文 |
| rootPath | 根路径前缀 |
| enabled | 启用 |
media_items
| 字段 | 说明 |
|---|---|
| id | PK |
| userId | 所属用户 |
| mountId | 可空(扫描所得) |
| path | 挂载内路径;userId+path 唯一 |
| rawName | 原始文件名 |
| title | 展示标题(可被刮削覆盖) |
| size / mime | 文件元数据 |
| bangumiId? | 刮削绑定 |
| epNumber? | 集数启发式 |
| scrapeStatus | pending | ok | failed | unmatched |
| scrapedAt? | 最近刮削时间 |
| posterUrl? | 海报(Bangumi CDN 或占位) |
| matchedHash? | 弹幕匹配指纹(预留) |
| scannedAt | 入库时间 |
playback_progress
id · userId · mediaItemId · positionMs · durationMs · updatedAt
唯一:(userId, mediaItemId)。
danmaku_cache(全局,不绑 user)
id · matchKey · payload/xml · source · expiresAt
bangumi_cache(可选,限流)
bangumiId · payload JSON · expiresAt
Zod(@app/types)
mountCreateSchema/mountUpdateSchemascanMountSchema·playbackReportSchemadanmakuQuerySchema·danmakuImportMetaSchemascrapeSearchSchema·scrapeBindSchema
4. 页面与交互
路由(shadcn dashboard 侧栏)
| 路径 | 页面 |
|---|---|
/login /register |
认证(登录前仅此可见) |
/library |
媒体库(默认登录后):海报卡、筛选全部/未匹配、继续播放、扫描入口 |
/browse |
文件浏览:选挂载 → 面包屑目录 → 行内播放/加入库 |
/watch |
播放:ArtPlayer + 弹幕层 + 同目录剧集(可选)+ 弹幕开关/导入 XML |
/mounts |
挂载管理:CRUD、测试连接、按挂载扫描 |
/danmaku |
弹幕设置:默认开关/透明度/密度;导入说明 |
主流程
- 注册/登录
- 挂载管理添加 WebDAV → 测试 → 保存
- 文件浏览点选播放,或「扫描」→ 刮削管线 → 媒体库
/watch:stream → 弹幕中继 → 进度保存- 媒体库「继续播放」带 progress 打开
/watch - 未匹配项手动 Bangumi 搜索绑定;详情可重新刮削
刮削管线(扫描)
- 列目录,视频入
media_items - 文件名启发式 → Bangumi 搜索
- 命中 → 写元数据/海报/
bangumiId - 低置信 →
unmatched,UI 手动搜绑 - 重复扫描按指纹/缓存,避免打爆 Bangumi;刮削失败不阻断入库
视觉
- shadcn 风格组件语义:侧栏 nav、卡片、primary 按钮、Sheet 挂载表单、Dialog 确认、Toast
- 可基于
@app/ui对齐 shadcn API,产品主题为中性暗色 dashboard(非工业信号黄主视觉) - 动效克制,尊重
prefers-reduced-motion
5. 错误处理
| 场景 | 策略 |
|---|---|
| WebDAV 401/超时 | 明确文案;浏览 skeleton + 重试;引导改凭据 |
| stream 失败 | 播放器错误 + Toast;不暴露栈 |
| 弹幕网络失败 | 降级无弹幕,可播;可仅本地 XML |
| Bangumi 失败 | scrapeStatus=failed,可重试;不回滚文件 |
| 进度失败 | 静默重试,不打断播放 |
| 权限 | 所有 library/mount/progress 查询强制 userId |
6. 测试与验证
- types:Zod 单测
- dao/service:进度 upsert、刮削绑定、路径规范化(mock HTTP)
- tRPC:跨用户越权
- web:主路径冒烟(登录→列表→播放页);无 CI 浏览器则手动清单
- 命令:
yarn typecheck·yarn lint·yarn build:web - 不做重型视觉回归
7. 实现范围(一个计划可覆盖)
In scope
- media 垂直切片全栈(mount/stream/danmaku/scrape/library/playback)
- 六个 UI 面(含登录沿用)
- ArtPlayer 集成与弹幕层(开放网络 + XML 导入)
- Bangumi 自动/手动刮削
- shadcn dashboard 信息架构与主题
Out of scope(本规格)
见 §2「首版不做」及 §1 调研中未选路径。
8. 风险与开放问题(实现前可再核)
- 弹弹play 开放弹幕网络 端点、鉴权与条款:实现时以官方文档/实测为准,service 单点适配
- Bangumi API 限流与字段:实现时核对官方 API 文档
- WebDAV 流:Range、HTTPS 混合内容、大文件内存——stream 用流式管道,禁止整文件缓冲
- 艺术墙纸/版权:用户自备片源与挂载凭据
9. 批准记录
| 节 | 结果 |
|---|---|
| 架构 + shadcn dashboard | OK |
| 数据模型 | OK |
| 页面与交互 + Bangumi 刮削 C | OK |
| 错误/测试/边界 | OK |
| 方案选型 | A |