fix: 修复预览播放器三个问题(标题不显示、无配音、片段切换黑屏) #1429

Closed
xiaoxia wants to merge 1 commits from fix/preview-player-v3 into develop
Owner

修复内容

1. 标题不显示(CSS 层级问题)

  • 根因.xx-preview-video::before 渐变光效覆盖在内容上方,遮挡 TitleOverlay
  • 修复:给 ::before 添加 z-index: 0,确保渐变层在内容之下

2. 没有配音音频

  • 根因:FrontendPreviewPlayer 只播放视频,没有音频逻辑
  • 修复
    • GeneratePage 中用 useQuery 获取 voice 素材,计算 voiceAudioUrl
    • 通过 PreviewVideoPanel → FrontendPreviewPlayer 传递
    • FrontendPreviewPlayer 中创建 Audio 对象,用 currentTime 同步播放

3. 片段切换不连贯(黑屏间隙)

  • 根因:切换片段时重新设置 video.src,浏览器需重新加载
  • 修复:在 useSegmentScheduler 的 tick 循环中,提前 2 秒预加载下一段素材,利用浏览器缓存减少加载时间

修改文件

  • apps/web/src/pages/generate/generate.css - CSS z-index 修复
  • apps/web/src/pages/generate/GeneratePage.tsx - 配音音频 URL 计算
  • apps/web/src/pages/generate/components/PreviewVideoPanel.tsx - 透传 voiceAudioUrl
  • apps/web/src/pages/generate/components/FrontendPreviewPlayer.tsx - 音频同步逻辑
  • apps/web/src/pages/generate/hooks/useSegmentScheduler.ts - 预加载优化

验证

  • TypeScript 编译通过
  • Prettier 格式化
  • 未修改 .gitea/workflows/ 目录
## 修复内容 ### 1. 标题不显示(CSS 层级问题) - **根因**:`.xx-preview-video::before` 渐变光效覆盖在内容上方,遮挡 TitleOverlay - **修复**:给 `::before` 添加 `z-index: 0`,确保渐变层在内容之下 ### 2. 没有配音音频 - **根因**:FrontendPreviewPlayer 只播放视频,没有音频逻辑 - **修复**: - GeneratePage 中用 `useQuery` 获取 voice 素材,计算 `voiceAudioUrl` - 通过 PreviewVideoPanel → FrontendPreviewPlayer 传递 - FrontendPreviewPlayer 中创建 Audio 对象,用 currentTime 同步播放 ### 3. 片段切换不连贯(黑屏间隙) - **根因**:切换片段时重新设置 video.src,浏览器需重新加载 - **修复**:在 `useSegmentScheduler` 的 tick 循环中,提前 2 秒预加载下一段素材,利用浏览器缓存减少加载时间 ## 修改文件 - `apps/web/src/pages/generate/generate.css` - CSS z-index 修复 - `apps/web/src/pages/generate/GeneratePage.tsx` - 配音音频 URL 计算 - `apps/web/src/pages/generate/components/PreviewVideoPanel.tsx` - 透传 voiceAudioUrl - `apps/web/src/pages/generate/components/FrontendPreviewPlayer.tsx` - 音频同步逻辑 - `apps/web/src/pages/generate/hooks/useSegmentScheduler.ts` - 预加载优化 ## 验证 - ✅ TypeScript 编译通过 - ✅ Prettier 格式化 - ✅ 未修改 .gitea/workflows/ 目录
xiaoxia added 1 commit 2026-08-18 21:26:40 +08:00
fix: 修复预览播放器三个问题
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m6s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 2m2s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m19s
AI Code Review / AI Code Review (pull_request) Failing after 2m23s
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m52s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 3m34s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m41s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Successful in 1m32s
CI/CD Pipeline / Frontend Lint (pull_request) Successful in 3m30s
CI/CD Pipeline / PR Build Web Image (pull_request) Successful in 4m9s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 10m59s
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 6s
ACR Cleanup / ACR Image Cleanup (pull_request_target) Waiting to run
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 50s
b0214beb39
1. 标题不显示:给 .xx-preview-video::before 添加 z-index: 0,确保渐变光效在内容层之下
2. 没有配音音频:添加 voiceAudioUrl prop 链路,在 FrontendPreviewPlayer 中创建 Audio 对象并同步视频播放
3. 片段切换不连贯:在 useSegmentScheduler 中提前 2 秒预加载下一段,减少黑屏间隙

- 所有修改通过 TypeScript 编译检查
- 代码已通过 Prettier 格式化

🚀 预览环境已部署

项目 详情
PR号 #1429
预览链接 https://pr-1429.preview.xiaoxiajianji.com
API环境 staging

💡 预览环境使用 staging API 数据,请勿在预览环境中操作重要数据。

🔄 每次提交新代码后预览环境会自动更新。

🗑️ PR 关闭或合并后,预览环境会自动清理。

🚀 **预览环境已部署** | 项目 | 详情 | |------|------| | PR号 | #1429 | | 预览链接 | [https://pr-1429.preview.xiaoxiajianji.com](https://pr-1429.preview.xiaoxiajianji.com) | | API环境 | staging | > 💡 预览环境使用 staging API 数据,请勿在预览环境中操作重要数据。 > > 🔄 每次提交新代码后预览环境会自动更新。 > > 🗑️ PR 关闭或合并后,预览环境会自动清理。
Collaborator

【阻塞级判定】

  • 是否存在阻塞级问题:是
  • 阻塞级问题数量:3 个

📊 审查概览

  • 整体评价:需修改
  • 建议级问题数量:2 个

🔴 阻塞级问题(必须修复)

  1. [apps/web/src/pages/generate/hooks/useSegmentScheduler.ts: 240-248] 预加载视频元素未清理导致内存泄漏

    • 问题类型:数据损坏风险/内存泄漏
    • 问题描述:代码中创建了 preloadVideoRef.current (DOM 元素) 并赋值 src,但在组件卸载或 Hook 销毁时没有对应的清理逻辑。这会导致浏览器内存中残留未释放的 Video 元素和缓冲资源,长时间运行或频繁切换页面会导致内存占用飙升。
    • 修改建议:添加一个 useEffect 清理函数,在组件卸载时释放该 DOM 元素。
      useEffect(() => {
        return () => {
          if (preloadVideoRef.current) {
            preloadVideoRef.current.src = "";
            preloadVideoRef.current.load();
            preloadVideoRef.current = null;
          }
        };
      }, []);
      
  2. [apps/web/src/pages/generate/components/FrontendPreviewPlayer.tsx: 96-107] 播放状态同步 Effect 依赖项错误导致性能损耗

    • 问题类型:性能问题
    • 问题描述:useEffect 的依赖数组包含了 [isPlaying, currentTime]。在播放过程中,currentTime 会高频更新(通常每秒多次),导致该 Effect 在播放期间被高频触发。虽然内部通过 prevIsPlayingRef 进行了逻辑短路,但 Effect 本身的频繁调度会造成不必要的性能开销和 React 调度压力。
    • 修改建议:移除依赖项中的 currentTimehandleSeekTo 已经负责了 Seek 时的音频时间同步,该 Effect 仅需处理“播放/暂停”状态的切换即可。依赖项应改为 [isPlaying]
  3. [apps/web/src/pages/generate/components/FrontendPreviewPlayer.tsx: 81-95] 切换配音 URL 时播放状态未同步

    • 问题类型:逻辑bug
    • 问题描述:当 voiceAudioUrl 改变时,Effect 会更新 audio.src。在 HTML5 规范中,修改 src 属性会导致音频元素自动暂停(pause())。然而,此时 React 的 isPlaying 状态可能仍为 true,且 prevIsPlayingRef 保持为 true。这会导致视频继续播放,但音频处于暂停状态,出现音画不同步的 Bug。
    • 修改建议:在更新 src 后,如果当前处于播放状态(isPlaying 为 true),应显式调用 audio.play() 恢复播放,或者重置 prevIsPlayingRef.current = false 以触发下一个 Effect 重新开始播放逻辑。

💡 改进建议(不阻塞合并)

  1. [apps/web/src/pages/generate/components/FrontendPreviewPlayer.tsx: 120-125] 冗余的暂停逻辑

    • 具体内容:代码中存在一个独立的 useEffect 用于在 !isPlaying 时暂停音频。实际上,上方的主同步 Effect(// 同步播放状态)中的 else if 分支已经处理了暂停逻辑。这个独立的 Effect 是冗余的,建议移除以保持代码简洁。
  2. [apps/web/src/pages/generate/components/FrontendPreviewPlayer.tsx: 101] 错误处理建议

    • 具体内容:audio.play().catch(() => {}) 吞掉了所有错误。建议在 catch 中添加 console.warn,以便在出现自动播放策略限制等问题时能进行调试。

良好实践

  • 使用 handleSeekTo 封装了 Seek 逻辑,统一处理视频和音频的时间跳转,思路清晰。
  • 使用 prevIsPlayingRef 来避免状态更新导致的死循环或重复触发,这是处理 Media Element 同步的正确做法。

🤖 由 AI 代码审查机器人自动生成 | 2026-08-18 13:29:22 | 模型:

### 【阻塞级判定】 - 是否存在阻塞级问题:是 - 阻塞级问题数量:3 个 ### 📊 审查概览 - 整体评价:需修改 - 建议级问题数量:2 个 ### 🔴 阻塞级问题(必须修复) 1. **[apps/web/src/pages/generate/hooks/useSegmentScheduler.ts: 240-248] 预加载视频元素未清理导致内存泄漏** - 问题类型:数据损坏风险/内存泄漏 - 问题描述:代码中创建了 `preloadVideoRef.current` (DOM 元素) 并赋值 `src`,但在组件卸载或 Hook 销毁时没有对应的清理逻辑。这会导致浏览器内存中残留未释放的 Video 元素和缓冲资源,长时间运行或频繁切换页面会导致内存占用飙升。 - 修改建议:添加一个 `useEffect` 清理函数,在组件卸载时释放该 DOM 元素。 ```javascript useEffect(() => { return () => { if (preloadVideoRef.current) { preloadVideoRef.current.src = ""; preloadVideoRef.current.load(); preloadVideoRef.current = null; } }; }, []); ``` 2. **[apps/web/src/pages/generate/components/FrontendPreviewPlayer.tsx: 96-107] 播放状态同步 Effect 依赖项错误导致性能损耗** - 问题类型:性能问题 - 问题描述:`useEffect` 的依赖数组包含了 `[isPlaying, currentTime]`。在播放过程中,`currentTime` 会高频更新(通常每秒多次),导致该 Effect 在播放期间被高频触发。虽然内部通过 `prevIsPlayingRef` 进行了逻辑短路,但 Effect 本身的频繁调度会造成不必要的性能开销和 React 调度压力。 - 修改建议:移除依赖项中的 `currentTime`。`handleSeekTo` 已经负责了 Seek 时的音频时间同步,该 Effect 仅需处理“播放/暂停”状态的切换即可。依赖项应改为 `[isPlaying]`。 3. **[apps/web/src/pages/generate/components/FrontendPreviewPlayer.tsx: 81-95] 切换配音 URL 时播放状态未同步** - 问题类型:逻辑bug - 问题描述:当 `voiceAudioUrl` 改变时,Effect 会更新 `audio.src`。在 HTML5 规范中,修改 `src` 属性会导致音频元素自动暂停(`pause()`)。然而,此时 React 的 `isPlaying` 状态可能仍为 `true`,且 `prevIsPlayingRef` 保持为 `true`。这会导致视频继续播放,但音频处于暂停状态,出现音画不同步的 Bug。 - 修改建议:在更新 `src` 后,如果当前处于播放状态(`isPlaying` 为 true),应显式调用 `audio.play()` 恢复播放,或者重置 `prevIsPlayingRef.current = false` 以触发下一个 Effect 重新开始播放逻辑。 ### 💡 改进建议(不阻塞合并) 1. **[apps/web/src/pages/generate/components/FrontendPreviewPlayer.tsx: 120-125] 冗余的暂停逻辑** - 具体内容:代码中存在一个独立的 `useEffect` 用于在 `!isPlaying` 时暂停音频。实际上,上方的主同步 Effect(`// 同步播放状态`)中的 `else if` 分支已经处理了暂停逻辑。这个独立的 Effect 是冗余的,建议移除以保持代码简洁。 2. **[apps/web/src/pages/generate/components/FrontendPreviewPlayer.tsx: 101] 错误处理建议** - 具体内容:`audio.play().catch(() => {})` 吞掉了所有错误。建议在 catch 中添加 `console.warn`,以便在出现自动播放策略限制等问题时能进行调试。 ### ✅ 良好实践 - 使用 `handleSeekTo` 封装了 Seek 逻辑,统一处理视频和音频的时间跳转,思路清晰。 - 使用 `prevIsPlayingRef` 来避免状态更新导致的死循环或重复触发,这是处理 Media Element 同步的正确做法。 --- <sub>🤖 由 AI 代码审查机器人自动生成 | 2026-08-18 13:29:22 | 模型: </sub> <!-- AI_CODE_REVIEW_AUTO_COMMENT -->
auto-approve-bot approved these changes 2026-08-18 21:40:31 +08:00
auto-approve-bot left a comment
Collaborator

CI全绿,自动审批通过。

CI全绿,自动审批通过。
auto-approve-bot approved these changes 2026-08-18 21:40:31 +08:00
auto-approve-bot left a comment
Collaborator

CI全绿,自动审批通过。

CI全绿,自动审批通过。
xiaoxia closed this pull request 2026-08-19 20:48:08 +08:00

🗑️ 预览环境已清理

PR #1429 已关闭或合并,对应的预览环境已被清理。

如有需要,可以重新打开 PR 来重新生成预览环境。

🗑️ **预览环境已清理** PR #1429 已关闭或合并,对应的预览环境已被清理。 > 如有需要,可以重新打开 PR 来重新生成预览环境。
Some checks are pending
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m6s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 2m2s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m19s
AI Code Review / AI Code Review (pull_request) Failing after 2m23s
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m52s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 3m34s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m41s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Successful in 1m32s
CI/CD Pipeline / Frontend Lint (pull_request) Successful in 3m30s
CI/CD Pipeline / PR Build Web Image (pull_request) Successful in 4m9s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 10m59s
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 6s
ACR Cleanup / ACR Image Cleanup (pull_request_target) Waiting to run
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 50s

Pull request closed

Sign in to join this conversation.