4.4 KiB
4.4 KiB
🐛 缺陷修复:视频生成与持久化回归 (Day 21)
概述
本日修复 Day 20 优化后引入的 3 个回归缺陷:Remotion 渲染崩溃容错、首页作品选择持久化、发布页作品选择持久化。
已完成修复
BUG-1: Remotion 渲染进程崩溃导致标题/字幕丢失
- 现象: 视频生成后没有标题和字幕,回退到纯 FFmpeg 合成。
- 根因: Remotion Node.js 进程在渲染完成(100%)后以 SIGABRT (code -6) 退出,Python 端将其视为失败。
- 修复:
remotion_service.py在进程非零退出时,先检查输出文件是否存在且大小合理(>1KB),若存在则视为成功。 - 文件:
backend/app/services/remotion_service.py
if process.returncode != 0:
output_file = Path(output_path)
if output_file.exists() and output_file.stat().st_size > 1024:
logger.warning(
f"Remotion process exited with code {process.returncode}, "
f"but output file exists ({output_file.stat().st_size} bytes). Treating as success."
)
return output_path
raise RuntimeError(...)
BUG-2: 首页历史作品选择刷新后不保持
- 现象: 用户选择某个历史作品后刷新页面,总是回到第一个视频。
- 根因:
fetchGeneratedVideos()在初始加载时无条件自动选中第一个视频,覆盖了useHomePersistence的恢复值。 - 修复:
fetchGeneratedVideos增加preferVideoId参数,仅在明确指定时才自动选中;新增"__latest__"哨兵值用于生成完成后选中最新。 - 文件:
frontend/src/features/home/model/useGeneratedVideos.ts,frontend/src/features/home/model/useHomeController.ts
// 任务完成 → 自动选中最新
useEffect(() => {
if (prevIsGenerating.current && !isGenerating) {
if (currentTask?.status === "completed") {
void fetchGeneratedVideos("__latest__");
} else {
void fetchGeneratedVideos();
}
}
prevIsGenerating.current = isGenerating;
}, [isGenerating, currentTask, fetchGeneratedVideos]);
BUG-3: 发布页作品选择刷新后不保持(根因:签名 URL 不稳定)
- 现象: 发布管理页选择视频后刷新,选择丢失(无任何视频被选中)。
- 根因: 后端
/api/videos/generated返回的path是 Supabase 签名 URL,每次请求都会变化。发布页用path作为选择标识存入 localStorage,刷新后新的path与保存值永远不匹配。首页不受影响是因为使用稳定的video.id。 - 修复: 发布页全面改用
id(稳定标识)替代path(签名 URL)进行选择、持久化和比较。 - 文件:
frontend/src/shared/types/publish.ts—PublishVideo新增id字段frontend/src/features/publish/model/usePublishController.ts—selectedVideo存储id,发布时根据id查找pathfrontend/src/features/publish/ui/PublishPage.tsx—key/onClick/选中比较改用v.idfrontend/src/features/home/model/useHomeController.ts— 预取缓存加入id字段
// 类型定义新增 id
export interface PublishVideo {
id: string; // 稳定标识符
name: string;
path: string; // 签名 URL(仅用于播放/发布)
}
// 发布时根据 id 查找 path
const video = videos.find(v => v.id === selectedVideo);
await api.post('/api/publish', { video_path: video.path, ... });
涉及文件汇总
| 文件 | 变更 |
|---|---|
backend/app/services/remotion_service.py |
Remotion 崩溃容错 |
frontend/src/features/home/model/useGeneratedVideos.ts |
首页视频选择不自动覆盖 |
frontend/src/features/home/model/useHomeController.ts |
任务完成监听 + 预取缓存加 id |
frontend/src/shared/types/publish.ts |
PublishVideo 新增 id 字段 |
frontend/src/features/publish/model/usePublishController.ts |
选择/持久化/发布改用 id |
frontend/src/features/publish/ui/PublishPage.tsx |
UI 选择比较改用 id |
关键教训
签名 URL 不可作为持久化标识。Supabase Storage 的签名 URL 包含时间戳和签名参数,每次请求都不同。任何需要跨请求/跨刷新保持的标识,必须使用后端返回的稳定
id字段。
重启要求
pm2 restart vigent2-backend # Remotion 容错
npm run build && pm2 restart vigent2-frontend # 前端持久化修复