# Tennis Training Hub - 变更日志 ## 2026.03.17-live-camera-media-asset-url (2026-03-17) ### 功能更新 - 修复同步观看预览地址重复拼接 `/media` 的问题;当前端收到 `/media/assets/...` 这类已完整的应用内媒体路径时,会直接使用原值,不再错误请求 `/media/media/assets/...` - 当前端收到完整的 `https://...` 外部媒体地址时,也会保持原样,避免把外链错误改写成站内 media 路径 - 其他仍是普通相对路径的媒体资源会继续自动补齐 `/media` 前缀,因此原有依赖相对路径的调用链不需要调整 - `/live-camera` 点击“同步观看”后,请求的缓存视频地址恢复为 `/media/assets/sessions/.../preview.webm`,不再因 `404 page not found` 导致无视频可播 ### 测试 - `pnpm vitest run client/src/lib/media.test.ts` - `pnpm check` - `pnpm build` - `playwright-skill` 线上 smoke:登录 `H1` 后访问 `https://te.hao.work/live-camera`,确认 viewer 实际请求 `https://te.hao.work/media/assets/sessions/.../preview.webm?...` 并返回 `200`,同时不存在 `/media/media/...` 双前缀请求 - `curl -I https://te.hao.work/` - `curl -I https://te.hao.work/assets/index-*.js` - `curl -I https://te.hao.work/assets/index-*.css` ### 线上 smoke - 部署前确认公开站点仍在旧资源 revision,尚未提供本次修复 - 部署完成后,`https://te.hao.work/` 已切到本次新构建,而不是继续提供部署前的旧资源 revision - `/live-camera` 的同步观看请求地址已恢复为 `/media/assets/sessions/.../preview.webm`,Playwright 真实浏览器验证拿到的 preview 请求状态为 `200` - 已确认不存在 `/media/media/assets/...` 双重前缀请求 ### 仓库版本 - `0af88b3` ## 2026.03.17-live-camera-pose-buffer-window (2026-03-17) ### 功能更新 - 修复 `/live-camera` 开始分析时报错 `Cannot destructure property 'Pose' ... as it is undefined` 的问题;MediaPipe Pose 动态加载现在兼容 `Pose`、`default.Pose` 和默认导出三种模块形态 - 多端同步观看的 relay 缓存窗口改为按会话配置,默认 `2` 分钟,可选最短 `10` 秒、最长 `5` 分钟;viewer 页面、徽标和设置卡都会同步显示当前缓存时长 - owner 端分析录制在继续保持“每 `60` 秒自动归档”之外,会额外每 `10` 秒上传一次 relay 分片,因此短缓存模式下其他端不需要等待整整 `60` 秒才看到平滑同步视频 - media 服务会按各自 relay 会话的缓存秒数裁剪 preview 分段;从磁盘恢复旧 relay 会话时也会自动归一化到合法范围,避免旧会话继续沿用固定 `60` 秒窗口 - 同步端渲染远端 `recentSegments` 时新增旧快照归一化;即使历史快照缺少 `keyFrames`、`issueSummary` 等数组字段,也会自动补默认值,不再触发 `Cannot read properties of undefined (reading 'length')` - 同步观看界面新增“已累积多少缓存、预计还需多久才能看到首段回放、距离目标缓存还差多少”的提示,观看端等待阶段会给出更明确的可观察时间说明 - 线上 smoke 已确认 `https://te.hao.work/` 正在提供本次新构建,而不是旧资源版本;当前公开站点资源 revision 为 `assets/index-CYpJPG0R.js`、`assets/index-BHHHsAWc.css`、`assets/pose-C93FSit6.js` ### 测试 - `cd media && go test ./...` - `pnpm vitest run client/src/lib/liveCamera.test.ts` - `pnpm check` - `pnpm build` - `pnpm exec playwright test tests/e2e/app.spec.ts` - `playwright-skill` 线上 smoke:登录 `H1` 后访问 `https://te.hao.work/live-camera`,完成校准、启用假摄像头并点击“开始分析”,确认页面进入分析中状态、默认显示“缓存 2 分钟”,且无控制台与页面级错误 - `curl -I https://te.hao.work/` - `curl -I https://te.hao.work/assets/index-CYpJPG0R.js` - `curl -I https://te.hao.work/assets/index-BHHHsAWc.css` - `curl -I https://te.hao.work/assets/pose-C93FSit6.js` ### 线上 smoke - `https://te.hao.work/` 已切换到本次新构建,而不是旧资源版本 - 当前公开站点前端资源 revision:`assets/index-CYpJPG0R.js`、`assets/index-BHHHsAWc.css`、`assets/pose-C93FSit6.js` - 已确认首页、主 JS、主 CSS 与 `pose` 模块均返回 `200`,且 MIME 分别为 `text/html`、`application/javascript`、`text/css`、`application/javascript` - 真实浏览器验证已通过:登录 `H1` 后进入 `/live-camera`,能够完成校准、启用摄像头并点击“开始分析”;页面会进入“分析进行中”状态,默认显示“缓存 2 分钟”,且未再出现 `Pose` 模块解构异常 ### 仓库版本 - `f3f7e19+pose-buffer-window` ## 2026.03.17-live-camera-relay-buffer (2026-03-17) ### 功能更新 - `/live-camera` 的同步观看改为播放 media 服务生成的滚动缓存视频,不再轮询 `live-frame.jpg` 单帧图片,因此观看端的画面会按最近 60 秒缓存视频平滑播放 - owner 端每个 60 秒的合成录像分段现在会额外上传到 `relay` 会话,worker 会在收到新分段后自动重建最近窗口的 `preview.webm` - `relay` 会话只保留最近 60 秒视频分段,旧分段会从会话元数据和磁盘同步清理,避免观看端继续读到旧一分钟之前的缓存 - media worker 会自动清理超过 30 分钟无活动的 relay 会话、分段目录和公开缓存文件,降低磁盘堆积风险 - viewer 页面文案、加载提示和按钮文案已同步更新为“缓存视频 / 缓存回放”语义;预览阶段跳过 mp4 转码,Chrome 直接使用 webm,降低处理时延 ### 测试 - `cd media && go test ./...` - `pnpm vitest run client/src/lib/liveCamera.test.ts` - `pnpm exec playwright test tests/e2e/app.spec.ts --grep "live camera page exposes camera startup controls|live camera starts analysis and produces scores|live camera switches into viewer mode when another device already owns analysis|live camera recovers mojibake viewer titles before rendering|live camera no longer opens viewer peer retries when server relay is active"` - `pnpm check` - `pnpm build` - 线上 smoke:部署后确认 `https://te.hao.work/` 已提供新构建而不是旧资源版本,`/live-camera` viewer 端进入“服务端缓存同步”路径,首页与资源文件返回正确 MIME ### 线上 smoke - 部署完成后已确认 `https://te.hao.work/` 提供的是本次新构建,而不是旧资源版本 - `https://te.hao.work/live-camera` 的 viewer 端会走“服务端缓存同步”路径,不再请求旧的 `live-frame.jpg` 单帧同步 - 首页、主 JS、主 CSS 与 `pose` 模块均返回 `200` 和正确 MIME,未再出现脚本/样式被回退成 `text/html` 的问题 ### 仓库版本 - `63dbfd2+relay-buffer` ## 2026.03.17-live-camera-preview-recovery (2026-03-17) ### 功能更新 - `/live-camera` 的 runtime 标题恢复逻辑新增更严格的乱码筛除与二次 UTF-8 解码兜底,`服...` 这类异常标题会优先恢复为正常中文;无法恢复时会自动回退到稳定默认标题,避免继续显示脏字符串 - 同步观看退出时会完整重置 viewer 轮询、连接标记和帧版本,不再把旧的 viewer 状态带回 owner 或空闲态,修复退出同步后仍黑屏、仍显示“等待同步画面”的问题 - 本地摄像头预览增加独立重绑流程和多次 watchdog 重试,即使浏览器首帧没有及时绑定 `srcObject` 或 `play()` 被短暂中断,也会继续自动恢复本地预览 - 视频区域是否显示画面改为按当前 runtime 角色分别判断,避免 viewer 旧连接状态误导 owner 模式,导致本地没有预览时仍错误隐藏占位提示 ### 测试 - `pnpm check` - `pnpm vitest run client/src/lib/liveCamera.test.ts` - `pnpm exec playwright test tests/e2e/app.spec.ts --grep "live camera"` - `pnpm build` - 线上 smoke:`curl -I https://te.hao.work/` - 线上 smoke:`curl -I https://te.hao.work/assets/index-BJ7rV3xe.js` - 线上 smoke:`curl -I https://te.hao.work/assets/index-tNGuStgv.css` - 线上 smoke:`curl -I https://te.hao.work/assets/pose-CZKsH31a.js` ### 线上 smoke - `https://te.hao.work/` 已切换到本次新构建 - 当前公开站点前端资源 revision:`assets/index-BJ7rV3xe.js`、`assets/index-tNGuStgv.css`、`assets/pose-CZKsH31a.js` - 已确认 `index`、`css` 与 `pose` 模块均返回 `200`,且 MIME 分别为 `application/javascript`、`text/css`、`application/javascript`,不再出现此前的模块脚本和样式被当成 `text/html` 返回的问题 ### 仓库版本 - `06b9701` ## 2026.03.16-live-camera-runtime-refresh (2026-03-16) ### 功能更新 - `/live-camera` 在打开拍摄引导、启用摄像头、开始分析前,都会先向服务端强制刷新 runtime 状态,避免旧的同步观看锁残留导致本机明明已释放却仍无法启动 - 新增 runtime 标题乱码恢复逻辑,可自动把 UTF-8 被误按 Latin-1 显示的标题恢复成正常中文,避免出现 `服...` 一类异常标题 - 摄像头启动链路改为以 `getUserMedia` 成功为准;即使本地预览 `