# 雪碧图 VTT 拖动预览 ## 目标 将进度条拖动预览主链路改为服务端雪碧图 + WebVTT 局部裁剪,原生取帧只作为降级: 1. `Episode` 与 `PlayTicket` 解析 `thumbnailsUrl`。 2. VTT 只拉取/解析一次,内存缓存 10 分钟。 3. cue 使用起止时间 + 相对 sprite 文件名 + `xywh`,按 position 二分选择。 4. sprite 图最多缓存 2 张 `ui.Image`,拖动帧只绘制 sourceRect。 5. 无 VTT、空轴或图片失败时回退现有 `PlaybackThumbnailService`,再回退封面。 ## 性能红线 - 拖动帧禁止网络请求与图片解码,只允许 cue 二分查找和 `RawImage.sourceRect` 绘制。 - VTT 每个 URL 只解析一次;sprite 解码不在 build/build paint 中执行。 - sprite ui.Image LRU 上限 2 张,页面 dispose 清空。 - 解码 sprite 最长边超过 2048px 时按比例缩小后常驻。 - 签名 `thumbnailsUrl` 不写入任何持久化缓存。 ## 实施 - 新增 `SpriteThumbnailAxisService`: - Dio 拉取 VTT,403 清缓存后重试一次; - 解析和选 cue 为纯函数,解析失败返回空轴; - 播放器就绪时预取当前 cue 及相邻 sprite; - LRU2 sprite 缓存和 10 分钟 VTT 缓存。 - `PlayerPage` 持有页面级服务,按当前选中集预取,dispose 时清空。 - `ScrubPreviewCard` 优先读取已缓存 sprite frame,显示 `RawImage` 裁剪; VTT 未就绪时暂显封面,轴为空/不可用后启动本地取帧,全部失败保留封面。 - 首页 feed 和全屏播放器都把 `thumbnailsUrl` 传到预览卡片。 - 不新增 pub 依赖、不改后端契约。 ## 测试 - VTT 解析:时间、xywh、多 sprite 文件。 - cue 选择:命中、越界最近邻。 - sprite LRU 最多 2 张。 - 回退状态判定。 - Widget:sprite 裁剪且不触发本地取帧;无 URL 回退本地;全部失败显示封面。 - 门禁:`dart analyze lib test`、`flutter test --no-pub`。 ## 风险 - 真实网络 VTT/sprite 可访问性和签名过期由 PM 真机验收。 - 本次不启动服务、不操作真机、不修改 Web/FruitServer。