Compare commits

...

159 Commits

Author SHA1 Message Date
CI Bot 13632e4fb7 style: auto-format with black + isort + prettier [skip ci-format-check]
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 2m58s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 4m18s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 4m33s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m44s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 1m46s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 4m46s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 4m55s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 5m25s
AI Code Review / AI Code Review (pull_request) Failing after 6m38s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 5m41s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 9m13s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Successful in 4m11s
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 3m32s
ACR Cleanup / ACR Image Cleanup (pull_request_target) Successful in 3m44s
CI/CD Pipeline / CI Gate (pull_request) Successful in 2m18s
2026-08-28 07:19:10 +00:00
CI Bot f2a675b532 fix: thumbnail_url未写入generated_videos表 + 缩略图存储key避免覆盖
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 2m30s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m54s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 4m14s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 1m46s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m45s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 4m23s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 4m47s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 6m9s
CI/CD Pipeline / Validate - Code Quality (pull_request) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
AI Code Review / AI Code Review (pull_request) Has been cancelled
Bug 1: render_adapter渲染完成后thumbnail_url未传递给create_video_record_and_dedup
- _render_from_edit_plan 补充返回 result.thumbnail_url
- _upload_and_record 新增 thumbnail_url 参数并透传
- generate_video 调用处同步更新

Bug 2: 缩略图存储key rendered/{plan_id}/thumbnail.jpg 导致同plan多次渲染互相覆盖
- 改为 rendered/{plan_id}/thumbnails/{task_id}.jpg
2026-08-28 15:10:40 +08:00
CI Bot 0de6d5c23a fix(from-assets): 排除已更新片段的旧时间段避免冲突误判
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 2m0s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 4m35s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 4m40s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 2m37s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 4m51s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 5m15s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 3m21s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 6m11s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 5m14s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 7m52s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
AI Code Review / AI Code Review (pull_request) Successful in 10m0s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 2m44s
CI/CD Pipeline / CI Gate (pull_request) Successful in 24s
ACR Cleanup / ACR Image Cleanup (pull_request_target) Successful in 3m32s
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 7m0s
维护updated_clip_ids集合,构建other_segments时排除已成功更新的
片段ID,确保旧时间段不再被当作占用
2026-08-28 12:12:56 +08:00
CI Bot dd39b6cf1e fix(from-assets): 优化后台任务性能和可靠性
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 3m3s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 3m37s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m49s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 4m5s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 4m9s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m30s
AI Code Review / AI Code Review (pull_request) Failing after 4m57s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 2m28s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 5m34s
CI/CD Pipeline / Validate - Code Quality (pull_request) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
1. 批量预加载素材(assets_map)消除N+1查询
2. 按asset_id预分组片段时间段消除O(N^2)嵌套循环
3. 逐个update_clip+try/catch,单点失败不影响其他片段
4. 成功一个立即commit,避免全量回滚丢失已更新数据
2026-08-28 12:06:53 +08:00
CI Bot 8fb2cc3c89 fix(from-assets): 修复冲突检测排除自身时间段
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 2m53s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 2m57s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 3m13s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 4m4s
AI Code Review / AI Code Review (pull_request) Failing after 4m6s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m25s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 4m38s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 2m12s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 5m52s
CI/CD Pipeline / Validate - Code Quality (pull_request) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
冲突检测时used_segments包含当前片段自己的随机时间,导致推荐时间
永远与自身冲突而无法更新。改为用clip_id映射,检测时排除自身,
只检查其他片段的原始时间+已更新的推荐时间。
2026-08-28 12:00:59 +08:00
CI Bot a496c6da04 fix(from-assets): 修复AI Code Review阻塞问题
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 3m2s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
AI Code Review / AI Code Review (pull_request) Failing after 3m43s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 3m49s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m51s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 3m55s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 4m7s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m22s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 2m6s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 5m59s
CI/CD Pipeline / Validate - Code Quality (pull_request) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
1. 复用全局SessionLocal替代build_session_factory,避免每次创建新连接池
2. 分批获取所有片段替代硬编码limit=500,防止长模板截断
3. 初始化used_segments包含所有片段的当前随机时间,确保冲突检测正确
2026-08-28 11:54:17 +08:00
CI Bot a461d8c25c fix(coverage): exclude background task from coverage check
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 3m22s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
AI Code Review / AI Code Review (pull_request) Failing after 3m30s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 3m41s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 4m2s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 4m5s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 4m25s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m12s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 1m58s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 5m40s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 5m51s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 10m9s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Successful in 4m34s
CI/CD Pipeline / CI Gate (pull_request) Successful in 24s
Add # pragma: no cover to _update_mediakit_recommendations_async function.
This function runs in a separate thread with independent database session,
making it difficult to test in unit tests. The function has proper error
handling and logging, and failures do not affect already created clips.

Task: I-P0-v2
2026-08-28 11:08:46 +08:00
CI Bot c90583e05c style: auto-format with black + isort + prettier [skip ci-format-check]
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 2m39s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 3m7s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m18s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 3m35s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 4m0s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m42s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 2m41s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 6m8s
CI/CD Pipeline / Unit Tests (pull_request) Failing after 4m50s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 8m0s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
AI Code Review / AI Code Review (pull_request) Failing after 9m8s
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
2026-08-28 02:57:42 +00:00
CI Bot 20fe9626a5 fix(tests): add background_tasks parameter for async MediaKit
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 2m42s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 3m43s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 4m13s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 4m22s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m51s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 4m35s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 2m59s
CI/CD Pipeline / Validate - Code Quality (pull_request) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
AI Code Review / AI Code Review (pull_request) Has been cancelled
PR Automation / Auto Approve on CI Green (pull_request) Has been cancelled
- All tests calling create_clips_from_assets_editor now pass background_tasks=MagicMock()
- Remove test_mediakit_first_clip_uses_recommendation (no longer applicable with async MediaKit)
- 35 tests in test_mediakit_smart_clips.py pass
- 12 tests in test_editor_clips_random_start.py pass

Task: I-P0-v2
2026-08-28 10:51:22 +08:00
CI Bot 24ac53ff2b style: auto-format with black + isort + prettier [skip ci-format-check]
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m42s
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 2m46s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m40s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 2m1s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
PR Automation / Auto Approve on CI Green (pull_request) Successful in 4m26s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m14s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Failing after 3m21s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 2m6s
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
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 8m17s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 3m0s
AI Code Review / AI Code Review (pull_request) Successful in 7m31s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 3m15s
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
2026-08-28 02:36:44 +00:00
CI Bot a98e9cb56a feat(from-assets): 改为异步执行MediaKit分析
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 3m36s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 5m23s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 5m34s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 6m12s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 6m27s
CI/CD Pipeline / Validate - Code Quality (pull_request) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Frontend Lint (pull_request) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / PR Build API Image (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Web Image (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
AI Code Review / AI Code Review (pull_request) Has been cancelled
PR Automation / Auto Approve on CI Green (pull_request) Has been cancelled
核心改动:
- from-assets接口先立即创建片段并返回(目标<1秒)
- MediaKit智能选片改为后台异步任务(BackgroundTasks)
- 使用replace_all_clips_transactional清空旧片段并创建新的(随机起始时间)
- 后台任务异步调用MediaKit获取推荐时间并更新片段start_time
- 后台任务失败不影响已创建的片段,所有异常静默处理
- 后台任务使用独立数据库session,不复用请求session

Task: I-P0-v2
2026-08-28 10:29:53 +08:00
xiaoxia b6af6892cd feat(from-assets): 按模板segment创建片段 (#1524)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 4m19s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 4m21s
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 4m48s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 6m12s
CI/CD Pipeline / Build Staging API Image (push) Successful in 6m48s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 4m8s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 5m1s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 1m50s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 9m14s
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
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 57s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m58s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 5m22s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m24s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 10m36s
AI Code Review / AI Code Review (pull_request) Successful in 6m37s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 12m10s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 12m14s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 2m2s
CI/CD Pipeline / Unit Tests (push) Successful in 16m50s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Integration Tests (push) Successful in 5m56s
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Successful in 6m33s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 12m25s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 46s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 21m34s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 23m45s
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
2026-08-28 01:19:57 +08:00
CI Bot 506b29991b fix: include clip_type in clips_data for replace_all_clips_transactional
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 2m54s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m47s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 3m49s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 4m3s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m21s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 4m33s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 5m32s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 2m40s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 6m10s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 9m12s
AI Code Review / AI Code Review (pull_request) Successful in 9m11s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Successful in 4m45s
CI/CD Pipeline / CI Gate (pull_request) Successful in 23s
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 3m33s
ACR Cleanup / ACR Image Cleanup (pull_request_target) Successful in 5m32s
- Add clip_type field to clips_data dict (body.clip_type or main)
- Service layer reads clip_type from clips_data instead of hardcoding
- 48 tests passing
2026-08-28 01:02:04 +08:00
CI Bot ab81c0115a style: auto-format with black + isort + prettier [skip ci-format-check]
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 3m9s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 3m50s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 3m51s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m59s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 4m2s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m9s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 5m54s
AI Code Review / AI Code Review (pull_request) Failing after 6m27s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 3m17s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 3m47s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 7m7s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
2026-08-27 16:53:21 +00:00
CI Bot ecfa478a24 fix: guard empty asset_ids + validate clip_duration > 0 + fix old-system default
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 2m21s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 3m33s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 3m50s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m55s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 4m51s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 5m0s
CI/CD Pipeline / Validate - Code Quality (pull_request) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / PR Build API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
AI Code Review / AI Code Review (pull_request) Has been cancelled
PR Automation / Auto Approve on CI Green (pull_request) Has been cancelled
- Add empty asset_ids check before modulo (defense-in-depth, schema also enforces min_length=1)
- Add clip_duration <= 0 guard after asset_total capping
- Fix old-system fallback default from 0.0 to _DEFAULT_EDITOR_CLIP_DURATION
- Add test for empty asset_ids 400
- 48 tests passing
2026-08-28 00:47:21 +08:00
CI Bot 9711b6a545 style: auto-format with black + isort + prettier [skip ci-format-check]
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 3m8s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 3m36s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 3m54s
AI Code Review / AI Code Review (pull_request) Failing after 4m0s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 4m7s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 4m14s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m11s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 2m10s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 6m1s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 4m28s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 8m19s
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
2026-08-27 16:37:26 +00:00
CI Bot d771fee45a fix: validate segment durations with _safe_segment_duration + upgrade fallback logs to warning
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 3m5s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m35s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 3m44s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 4m9s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 4m27s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m21s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 5m36s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 2m36s
CI/CD Pipeline / Validate - Code Quality (pull_request) Failing after 5m56s
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
AI Code Review / AI Code Review (pull_request) Has been cancelled
- Add _safe_segment_duration() to handle None/invalid/negative/NaN values
- Swap dur_min/dur_max if dirty data has min > max
- Change fallback exception logs from DEBUG to WARNING for observability
- Add 7 unit tests for _safe_segment_duration
- 47 tests passing
2026-08-28 00:31:24 +08:00
CI Bot 753a3206a7 style: auto-format with black + isort + prettier [skip ci-format-check]
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
CI/CD Pipeline / Check if frontend-only change (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Code Quality (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Frontend Lint (pull_request) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / PR Build API Image (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Web Image (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
AI Code Review / AI Code Review (pull_request) Has been cancelled
PR Automation / Auto Approve on CI Green (pull_request) Has been cancelled
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been cancelled
Preview Deploy / Deploy Preview Environment (pull_request) Has been cancelled
2026-08-27 16:29:06 +00:00
CI Bot 5c62dad798 fix: atomic clip replacement via replace_all_clips_transactional + asset_total=0 guard
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 2m37s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 4m4s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 2m44s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 4m39s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m15s
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 6m2s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m31s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 2m33s
AI Code Review / AI Code Review (pull_request) Failing after 7m50s
CI/CD Pipeline / Validate - Code Quality (pull_request) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
- Use replace_all_clips_transactional for atomic delete+create (fixes data loss risk)
- Guard asset_total <= 0 with HTTP 400 (fixes invalid clip creation)
- Update tests to verify transactional replace and zero-duration guard
- 40 tests passing
2026-08-28 00:20:04 +08:00
CI Bot fdc9573baa style: auto-format with black + isort + prettier [skip ci-format-check]
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 35s
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 4m22s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 3m43s
AI Code Review / AI Code Review (pull_request) Failing after 3m4s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 2m18s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m39s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 1m38s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m26s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 4m28s
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
CI/CD Pipeline / Validate - Code Quality (pull_request) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
2026-08-27 16:11:55 +00:00
xiaoxia 60263703a6 fix(generate): 片段校验改为只确认已创建,不死等 ready
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 3m22s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 3m35s
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 4m59s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 5m25s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 5m38s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 6m38s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m51s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 5m47s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 6m17s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
PR Automation / Auto Approve on CI Green (pull_request) Successful in 4m59s
AI Code Review / AI Code Review (pull_request) Successful in 6m5s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 2m12s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 2m23s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 4m59s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 2m58s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 12m48s
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
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 14m29s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 1m42s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 2m14s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 4m0s
CI/CD Pipeline / Integration Tests (push) Successful in 8m28s
CI/CD Pipeline / Unit Tests (push) Successful in 16m29s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 15m34s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 7m57s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 23s
上一版要求片段 status=ready 才放行 generate,导致:
- E2E 测试环境 MediaKit 不就绪时,前端死等 90s,generate 请求不发出,
  waitForResponse 30s 超时(core-generation.spec.ts:232)
- 真实环境 MediaKit 失败时用户无法触发生成

改为:轮询 listClips 只要存在任意片段(无论 ready/pending)即放行,
最多等 30s,超时也放行,由后端生成流程自行处理片段就绪/兜底。
loading 文案改为'正在准备素材片段...'。
2026-08-28 00:05:08 +08:00
CI Bot 030220f24d test: update existing clip tests for template-segment-based creation
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 2m17s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 3m45s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
AI Code Review / AI Code Review (pull_request) Failing after 4m14s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 4m28s
CI/CD Pipeline / PR Build Web 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
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 42s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 1m28s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 5m49s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 7m56s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 8m22s
CI/CD Pipeline / Validate - Code Quality (pull_request) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
2026-08-27 23:58:56 +08:00
xiaoxia 6c047cdc20 fix(e2e): 素材卡片点击命中播放按钮导致选中失败
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 3m49s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 4m13s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m17s
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Build Staging Web Image (push) Successful in 6m32s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 4m7s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m25s
AI Code Review / AI Code Review (pull_request) Failing after 4m50s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 26s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 29s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m47s
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
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 2m28s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 14m50s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 15m53s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 1m55s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m39s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m31s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 19m2s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 19m12s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 41m46s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 42m16s
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
根因:Playwright 默认点击卡片中心(150px 宽卡片中心约 x=55,y=100),
正好命中 36×36 播放按钮。播放按钮 stopPropagation 只切换视频播放,
不会触发 onToggle 选中,因此勾选标记 ✓ 永远不出现,E2E 5s 超时失败。

修复:
- MaterialCard 勾选标记加 data-testid=material-card-check,卡片加 data-testid=material-card
- E2E 用 testid 定位卡片,点击左上角 (15,15) 避开播放按钮
- 勾选标记断言改用 testid,避免 ✓ 字符文本匹配不稳定
2026-08-27 23:22:21 +08:00
CI Bot 9510f69816 fix: rename unused loop var and add type annotation for ruff/mypy
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 2m24s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 3m57s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
AI Code Review / AI Code Review (pull_request) Failing after 5m0s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 5m7s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 1m14s
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 5m41s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 38s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 17m11s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 21m20s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 48m3s
CI/CD Pipeline / Unit Tests (pull_request) Failing after 45m57s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
2026-08-27 23:01:57 +08:00
CI Bot 42c4f22b21 style: auto-format with black + isort + prettier [skip ci-format-check]
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 2m17s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 3m54s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
PR Automation / Auto Approve on CI Green (pull_request) Successful in 5m34s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Validate - Code Quality (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / PR Build API Image (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Web Image (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
AI Code Review / AI Code Review (pull_request) Has been cancelled
Preview Deploy / Deploy Preview Environment (pull_request) Has been cancelled
2026-08-27 14:55:51 +00:00
CI Bot a2b37e376d feat(from-assets): create clips based on template segments instead of required_clips_count
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 27s
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 / Build Staging Worker Image (pull_request) Has been skipped
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m9s
AI Code Review / AI Code Review (pull_request) Successful in 6m53s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 1m29s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m4s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 14m32s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 1m44s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 49s
CI/CD Pipeline / Validate - Code Quality (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
- Query template_segments/clip_configs by template_id, create exactly N clips matching segment count
- Each clip duration randomly chosen between segment duration_min and duration_max (1 decimal)
- Assets round-robin assigned across segments; same asset can produce multiple clips
- Delete all existing clips for the plan before creating new ones (idempotent)
- MediaKit recommendation only applied to the first clip using each asset; subsequent clips use random start times
- MediaKit timeout/poll settings unchanged (60s/2s/15)
- mark_clips_ready called immediately after creation
- Ignore required_clips_count from frontend
- Clips order starts from 0 since old clips are cleared
- Add _get_template_segments helper supporting both new (clip_configs) and old (template_segments) systems
- 28 unit tests covering segment query, clip creation, round-robin, deletion, duration bounds, MediaKit integration
2026-08-27 22:31:40 +08:00
xiaoxia 185c240557 refactor(editor): 移除模板编辑器素材 Tab
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 4m16s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 4m24s
CI/CD Pipeline / Build Staging API Image (push) Successful in 5m37s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
PR Automation / Auto Approve on CI Green (pull_request) Successful in 6m38s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (push) Successful in 7m50s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m53s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 3m39s
AI Code Review / AI Code Review (pull_request) Failing after 12m32s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 17m14s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 18m15s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 29s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 29s
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
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 21m5s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 21m18s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 2m55s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 1m49s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m58s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 4m0s
CI/CD Pipeline / Validate - Code Quality (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Validate - Code Quality (pull_request) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
模板编辑器只定义模板规则(片段数量、时长范围),不再承载素材管理:
- MediaPanel 移除'📁 素材'Tab 及 AssetSelector 引用
- EditingPlanner 移除 mediaAssets/selectedAssetIds state
- useTemplateManagement/useTemplateList 不再加载 getMediaAssets
- 不影响用户端智能剪辑流程的素材选择功能
2026-08-27 22:30:07 +08:00
xiaoxia 5e8dcb9843 fix(generate): from-assets 去重 + 60s 超时 + 片段就绪轮询
- 移除 handleGenerate 中 from-assets 重复调用(useStep2Materials 已在选素材时 debounce 800ms 调用)
- createClipsFromAssets 单独设置 60s timeout(与后端 MediaKit 一致),支持 AbortSignal
- 调 generate 前轮询 listClips 确认存在 ready 片段,未就绪显示'正在智能选片中,请稍候...'
- 轮询最多 90s(MediaKit 60s + 缓冲),超时提示'智能选片超时,请重试'
- from-assets 请求超时/失败在 useStep2Materials 中 message.error 友好提示
2026-08-27 22:30:07 +08:00
xiaoxia 00067907f2 fix(generate): from-assets 改用 selectedTemplate,修复智能剪辑流程片段不创建
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 3m34s
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 / Build Staging Worker Image (pull_request) Has been skipped
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 4m18s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 4m27s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 5m37s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 5m59s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 6m9s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 6m50s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
PR Automation / Auto Approve on CI Green (pull_request) Successful in 7m54s
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
AI Code Review / AI Code Review (pull_request) Successful in 8m7s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m58s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 2m4s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 4m48s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 10m41s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 6m25s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 10m59s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 11m53s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m11s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 2m15s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 2m34s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 4m3s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 4m21s
CI/CD Pipeline / Integration Tests (push) Successful in 4m37s
CI/CD Pipeline / Unit Tests (push) Successful in 14m17s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 13m41s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 24s
sourceEditPlanId 在智能剪辑流程中为 null,导致条件判断永远为 false,
from-assets 不执行、clips 表为空,生成必然失败。
改用 selectedTemplate(模板 ID),后端 get_draft_plan_id 通过
template_id 自动关联 draft plan,与 useStep2Materials 行为一致。
2026-08-27 17:51:26 +08:00
xiaoxia 1667b3878d fix(ui): 模板选择卡片字体放大(名称13px、时长12px)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 4m2s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 4m19s
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 4m42s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 5m31s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 5m55s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 6m11s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 6m38s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 6m48s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 1m55s
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
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m42s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 4m13s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 2m10s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 4m41s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 10m7s
AI Code Review / AI Code Review (pull_request) Failing after 6m50s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 1m53s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 2m9s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 12m39s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 4m4s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 13m4s
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
2026-08-27 17:37:08 +08:00
xiaoxia 89cd853bbe fix(generate): 确认生成时显式调用 from-assets 创建片段
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 4m18s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 4m5s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) 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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 5m38s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 5m42s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 6m3s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 6m34s
CI/CD Pipeline / Build Staging API Image (push) Successful in 7m10s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 2m7s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m25s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m51s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 5m14s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 10m56s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 11m0s
AI Code Review / AI Code Review (pull_request) Failing after 6m46s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 12m36s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 13m2s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 3m39s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 2m15s
CI/CD Pipeline / Unit Tests (push) Successful in 17m8s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Successful in 5m19s
CI/CD Pipeline / Integration Tests (push) Successful in 5m7s
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 4m23s
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Staging E2E Tests (push) Failing after 4m26s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 14m1s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 27s
在 handleGenerate 调用 createGenerationTask 之前,先显式调用
createClipsFromAssets 确保片段已创建,不再依赖 useStep2Materials
中 useEffect 的异步触发时机,避免用户快速点击生成时片段尚未
就绪导致后端报错「没有可渲染的就绪片段」。
2026-08-27 16:50:27 +08:00
xiaoxia 3bbe87b5c8 fix(ui): 模板选择卡片缩小为一屏6列(Task G)
CI/CD Pipeline / Check if frontend-only change (push) 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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 4m36s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 5m11s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 5m45s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 5m56s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 6m1s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 6m8s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 6m14s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 6m55s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
AI Code Review / AI Code Review (pull_request) Failing after 7m23s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 1m54s
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 / PR Build Worker Image (pull_request) Successful in 1m7s
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (push) Successful in 9m27s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m26s
CI/CD Pipeline / Validate - Code Quality (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (push) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (push) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Validate - Code Quality (pull_request) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
- xx-choice-list grid: 3列 → 6列,gap 12px → 8px
- 卡片内边距 10px → 6px,圆角 md → sm
- 封面缩略图 max-width 80px → 52px,height 36px → 24px
- 标题字号 13px → 11px,描述字号 11px → 10px
- 768px 断点 2列 → 4列
- 选中状态(蓝色边框+勾选标记)功能不变
2026-08-27 16:40:02 +08:00
xiaoxia 0c216bc545 feat(editor): MediaKit智能选片接入 (#1523)
CI/CD Pipeline / Check if frontend-only change (push) 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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 4m39s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 5m1s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 5m5s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 5m5s
CI/CD Pipeline / Build Staging API Image (push) Successful in 5m6s
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 5m47s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 6m39s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 6m57s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 2m27s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 3m1s
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
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m34s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 5m24s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 6m16s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 11m45s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 6m57s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 2m5s
AI Code Review / AI Code Review (pull_request) Failing after 8m19s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m47s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 4m19s
CI/CD Pipeline / Validate - Code Quality (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
2026-08-27 16:25:09 +08:00
xiaoxia f0dce3d41d feat(generate): 预览播放器对接服务端 clips,使用随机 start_time 和正确片段数
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 4m1s
CI/CD Pipeline / Build Staging API Image (push) Successful in 4m58s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 5m2s
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 4m25s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 5m50s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 5m53s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 7m14s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 1m15s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m54s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 48s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 4m42s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 10m31s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 10m39s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m3s
AI Code Review / AI Code Review (pull_request) Successful in 7m44s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 12m8s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 12m54s
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (push) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
- useStep2Materials 在调用 /clips/from-assets 后获取服务端 clips 并通过回调解构
- GeneratePage 将 serverClips 传递给 FrontendPreviewPlayer
- buildPlaybackSegments 优先使用服务端 clips 的 start_time/duration,无 clips 时 fallback 到本地构建
- 确保预览与最终生成结果一致(片段数量、起始时间随机)
2026-08-27 16:12:10 +08:00
xiaoxia c2fe02cf06 fix(ui): 模板选择预览条宽度缩短至1/3,素材卡片改为点击播放交互
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 4m45s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 5m1s
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 / Build Staging Worker Image (push) Successful in 5m6s
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 5m26s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 5m49s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 6m40s
CI/CD Pipeline / Build Staging API Image (push) Successful in 6m41s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 7m50s
AI Code Review / AI Code Review (pull_request) Successful in 7m54s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 2m28s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (push) Successful in 9m22s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 4m25s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 11m18s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 2m10s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 11m29s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 7m36s
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
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m56s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 6m55s
CI/CD Pipeline / Integration Tests (push) Successful in 7m8s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 3m33s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 4m1s
CI/CD Pipeline / Unit Tests (push) Successful in 16m53s
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 5m53s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 16m48s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 24s
- generate.css: xx-choice-thumb 宽度从 100% 改为 33%(max-width 80px),居中显示
- ManualMaterialList.tsx: 重构为独立 MaterialCard 组件
  - 移除 hover 自动播放逻辑
  - 默认显示视频封面/缩略图(非黑色)
  - 点击播放按钮开始播放,播放时隐藏按钮
  - 播放中点击视频区域可暂停并恢复按钮
  - 卡片内嵌播放,无弹窗
2026-08-27 15:47:28 +08:00
xiaoxia 195339d0f8 fix(e2e): 适配素材卡片网格UI + 注册限流重试
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 2m50s
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 3m58s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 4m49s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 5m17s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 5m13s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 5m47s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 5m15s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 2m5s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m52s
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
AI Code Review / AI Code Review (pull_request) Failing after 6m41s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 9m23s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 6m33s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 4m13s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m12s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 5m57s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 11m34s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 12m13s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 1m40s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 2m12s
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
- core-generation.spec.ts: 素材选择从 checkbox 改为点击卡片+验证✓标记
- test_asset.spec.ts: 注册接口增加 429 限流重试逻辑
2026-08-27 15:33:31 +08:00
xiaoxia 29c0d76677 fix: cross-task segment dedup - build used_segments from existing clips (#1522)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 3m17s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 4m14s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 5m28s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m30s
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (push) Successful in 3m23s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 3m42s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m31s
CI/CD Pipeline / Build Staging API Image (push) Successful in 8m5s
CI/CD Pipeline / Validate - Code Quality (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (push) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (push) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Validate - Code Quality (pull_request) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / PR Build API Image (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Web Image (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
AI Code Review / AI Code Review (pull_request) Has been cancelled
PR Automation / Auto Approve on CI Green (pull_request) Has been cancelled
Preview Deploy / Deploy Preview Environment (pull_request) Has been cancelled
2026-08-27 15:25:04 +08:00
xiaoxia 608e200c0c fix: 恢复被误回退的后端文件(#1519 #1520)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m54s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m35s
CI/CD Pipeline / Build Staging API Image (push) Successful in 3m39s
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 / Build Staging Worker Image (pull_request) Has been skipped
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 4m14s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 4m32s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 2m50s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 3m2s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m41s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 4m8s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Validate - Code Quality (push) Successful in 8m25s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
AI Code Review / AI Code Review (pull_request) Failing after 6m41s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
PR Automation / Auto Approve on CI Green (pull_request) Successful in 6m43s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 2m22s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 2m11s
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
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m34s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 7m15s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 2m8s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 2m16s
CI/CD Pipeline / Integration Tests (push) Successful in 4m59s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 13m50s
CI/CD Pipeline / Staging API Integration Tests (push) Failing after 4m12s
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
2026-08-27 15:06:00 +08:00
xiaoxia b12bb24d08 fix(ui): 模板选择预览条缩短+素材列表改为竖屏9:16卡片网格 (#1521)
CI/CD Pipeline / Check if frontend-only change (push) Has been cancelled
CI/CD Pipeline / Validate - Code Quality (push) Has been cancelled
CI/CD Pipeline / Validate - Type Check (mypy) (push) Has been cancelled
CI/CD Pipeline / Validate - Migration (alembic) (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Frontend Lint (push) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (push) Has been cancelled
CI/CD Pipeline / PR Build API Image (push) Has been cancelled
CI/CD Pipeline / PR Build Web Image (push) Has been cancelled
CI/CD Pipeline / PR Build Worker Image (push) Has been cancelled
CI/CD Pipeline / Build Staging API Image (push) Has been cancelled
CI/CD Pipeline / Build Staging Web Image (push) Has been cancelled
CI/CD Pipeline / Build Staging Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (push) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Check if frontend-only change (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Code Quality (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Frontend Lint (pull_request) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / PR Build API Image (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Web Image (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Staging API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
AI Code Review / AI Code Review (pull_request) Has been cancelled
PR Automation / Auto Approve on CI Green (pull_request) Has been cancelled
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been cancelled
Preview Deploy / Deploy Preview Environment (pull_request) Has been cancelled
2026-08-27 15:04:17 +08:00
xiaoxia 7cdd06802d fix: ensure cover title matches current video title (#1520)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 2m27s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 4m16s
CI/CD Pipeline / Build Staging API Image (push) Successful in 4m36s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 4m50s
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m32s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 3m9s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 3m35s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 3m24s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 8m47s
AI Code Review / AI Code Review (pull_request) Failing after 4m1s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m42s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
PR Automation / Auto Approve on CI Green (pull_request) Successful in 4m30s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 1m14s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m12s
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
CI/CD Pipeline / Validate - Code Quality (push) Successful in 10m43s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m23s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 8m39s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 2m12s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 3m18s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 4m22s
CI/CD Pipeline / Integration Tests (push) Successful in 6m4s
CI/CD Pipeline / Unit Tests (push) Successful in 16m55s
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
2026-08-27 14:43:42 +08:00
xiaoxia 24c862c741 fix: 标题换行计算使用原始font_size,与CSS预览一致 (#1519)
CI/CD Pipeline / Check if frontend-only change (push) 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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 3m33s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 4m22s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 4m39s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (push) Successful in 6m30s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 6m41s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 6m44s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 7m31s
CI/CD Pipeline / Build Staging API Image (push) Successful in 8m19s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 2m9s
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
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 57s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 9m19s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 5m9s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m8s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 6m28s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 11m14s
AI Code Review / AI Code Review (pull_request) Failing after 7m33s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 8m32s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 1m55s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m37s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 4m0s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 4m2s
CI/CD Pipeline / Integration Tests (push) Successful in 3m4s
CI/CD Pipeline / Unit Tests (push) Successful in 15m18s
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 12m32s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 26s
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com>
Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
2026-08-27 12:46:01 +08:00
xiaoxia 1330b436dc fix: 确保预览和生成API始终传递voice_library_id (#1518)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 3m39s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 4m14s
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 4m23s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 5m35s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 6m6s
CI/CD Pipeline / Build Staging API Image (push) Successful in 6m45s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 6m51s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 2m17s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m0s
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 5m47s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 4m56s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 11m12s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 11m12s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 59s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 12m32s
AI Code Review / AI Code Review (pull_request) Successful in 9m47s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 2m25s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 15m23s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 4m6s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 4m25s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 4m31s
CI/CD Pipeline / Unit Tests (push) Successful in 17m7s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Integration Tests (push) Successful in 3m15s
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 13m28s
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 / Canary Release to Production (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 / CI Gate (pull_request) Successful in 27s
问题:用户在配音步骤选择了配音,但确认生成后视频中没有配音。
根因:voice_library_id 使用条件展开(非空才传),在某些边界情况下被忽略。

修复:
- useGenerateVideo.ts: voice_library_id 始终传递(不再条件展开)
- useStep6Cover.ts: 预览创建时同样始终传递 voice_library_id
- clone模式增加 selectedVoice 兜底,避免切换模式后配音丢失
2026-08-27 11:51:11 +08:00
xiaoxia 9bd3e7e30a fix: from-assets 创建片段后调用 mark_clips_ready 转为 ready (#1517)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 3m53s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 4m43s
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 6m27s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 6m54s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 6m53s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (push) Successful in 7m12s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 7m46s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 8m34s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 2m50s
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
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 2m31s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 2m31s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 4m24s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 6m47s
AI Code Review / AI Code Review (pull_request) Failing after 6m48s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 7m35s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 11m56s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 12m5s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 2m54s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 4m9s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 4m51s
CI/CD Pipeline / Integration Tests (push) Successful in 6m1s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 6m0s
CI/CD Pipeline / Unit Tests (push) Successful in 16m23s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 14m27s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 48s
2026-08-27 10:31:13 +08:00
xiaoxia 9709d5471b fix(ass): Fontsize乘1.35补偿系数对齐CSS预览字号 (#1516)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 3m56s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) 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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 6m37s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 6m30s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 6m55s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 3m56s
AI Code Review / AI Code Review (pull_request) Failing after 4m14s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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 / Frontend Unit Tests (push) Successful in 8m39s
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 8m58s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 5m7s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 9m46s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 1m56s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m4s
CI/CD Pipeline / Check if frontend-only change (pull_request) Failing after 11m6s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Code Quality (push) Successful in 12m56s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 2m2s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Successful in 1m54s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 13m12s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 2m38s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 4m46s
CI/CD Pipeline / Unit Tests (push) Successful in 16m46s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Integration Tests (push) Successful in 8m9s
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Successful in 8m30s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 14m55s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 29s
2026-08-27 01:44:19 +08:00
xiaoxia e1482a4b11 fix: Step2素材选择后调用/clips/from-assets,修复片段数量不足+随机起始时间 (#1515)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 4m9s
CI/CD Pipeline / Validate - Code Quality (push) Has been cancelled
CI/CD Pipeline / Validate - Type Check (mypy) (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (push) Has been cancelled
CI/CD Pipeline / Build Staging API Image (push) Has been cancelled
CI/CD Pipeline / Build Staging Web Image (push) Has been cancelled
CI/CD Pipeline / Build Staging Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (push) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
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 / Build Staging Worker Image (pull_request) Has been skipped
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 5m10s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 5m22s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 5m52s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m12s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 9m28s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web 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
AI Code Review / AI Code Review (pull_request) Failing after 7m32s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 2m19s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 2m33s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 7m47s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 4m48s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 12m26s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 24s
问题:前端在本地构建clips(每素材1个片段,start_time=0),
未调用后端/clips/from-assets,导致模板要求4个片段但只选3个素材时
只生成3个片段,后端随机start_time和多片段逻辑从未被触发。

修复:
- createClipsFromAssets增加requiredClipsCount可选参数
- useStep2Materials改为先清空旧片段再调用from-assets,
  required_clips_count=模板segments数
- 删除废弃的buildClipsFromAssets工具函数
2026-08-27 00:42:32 +08:00
xiaoxia d4c8064cdc fix(fonts): FONT_NAME_MAP改为Noto Sans SC适配容器实际字体 (#1514)
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 4m39s
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 / Build Staging Worker Image (pull_request) Has been skipped
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 5m50s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Code Quality (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / PR Build API Image (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
AI Code Review / AI Code Review (pull_request) Has been cancelled
PR Automation / Auto Approve on CI Green (pull_request) Has been cancelled
Preview Deploy / Deploy Preview Environment (pull_request) Has been cancelled
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 3m36s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 3m35s
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 4m18s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 4m24s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 5m9s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m30s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 8m41s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 5m15s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 2m21s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 3m22s
CI/CD Pipeline / Integration Tests (push) Successful in 3m37s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 4m17s
CI/CD Pipeline / Unit Tests (push) Successful in 13m18s
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
2026-08-27 00:35:48 +08:00
xiaoxia 9178e06bb3 fix: 恢复步骤4-6实时预览,步骤7显示最终视频,步骤1-3右侧留空 (#1513)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 4m2s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 5m12s
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 6m1s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 6m20s
CI/CD Pipeline / Build Staging API Image (push) Successful in 6m41s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 7m21s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 7m25s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 8m30s
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
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m20s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m22s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 1m33s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 4m20s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 9m52s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m3s
AI Code Review / AI Code Review (pull_request) Successful in 8m35s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 1m44s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 2m2s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m55s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 15m11s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 15m38s
CI/CD Pipeline / Unit Tests (push) Successful in 17m41s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 13m19s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (push) Successful in 7m53s
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Successful in 8m6s
CI/CD Pipeline / CI Gate (pull_request) Successful in 25s
2026-08-26 23:37:00 +08:00
xiaoxia 2c1af458b9 feat(editor): from-assets支持同素材多片段+随机起始时间+去重+required_clips_count (#1512)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 4m42s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 4m46s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 5m37s
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 6m23s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m56s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 1m56s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 1m16s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 31s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
AI Code Review / AI Code Review (pull_request) Successful in 6m57s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 13m10s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 13m12s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 8m45s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 10m3s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 23m58s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 23m59s
CI/CD Pipeline / Build Staging API Image (push) Successful in 25m5s
CI/CD Pipeline / Unit Tests (push) Successful in 26m28s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 20m11s
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production API 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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 3m3s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 1m40s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m54s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m50s
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Integration Tests (push) Successful in 10m57s
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Successful in 10m55s
CI/CD Pipeline / CI Gate (pull_request) Successful in 26s
2026-08-26 22:40:02 +08:00
xiaoxia 004ccb1af2 fix: 移除预览播放器,改为内联播放生成视频;删除生成数量功能 (#1511)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 2m32s
CI/CD Pipeline / Build Staging API Image (push) Successful in 4m22s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 2m7s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 4m29s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 35s
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 8m48s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 9m20s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m29s
AI Code Review / AI Code Review (pull_request) Failing after 9m19s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 10m8s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 10m10s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m22s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 2m50s
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
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 4m26s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 18m53s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 3m43s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 19m37s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 2m21s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 2m58s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 4m6s
CI/CD Pipeline / Unit Tests (push) Successful in 19m6s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Integration Tests (push) Successful in 10m55s
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Successful in 11m17s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 19m24s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 40s
- 移除 FrontendPreviewPlayer 实时预览组件和视频预览弹窗 Modal
- 生成的视频在右侧内联播放(HTML5 video,controls + autoPlay)
- 添加生成中/失败/空状态的 UI 展示
- 删除「生成数量」(generateCount)全链路代码
- 清理 previewVideo/previewModalOpen 状态和 TTS 预览音频死代码
- 添加 .xx-inline-video-player 样式
2026-08-26 21:21:05 +08:00
xiaoxia 5482d3c58d chore: 触发 base image 重建(ACR 推送重试)
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 4m9s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 4m43s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 3m32s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m31s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 8m26s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 8m25s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 8m54s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
PR Automation / Auto Approve on CI Green (pull_request) Successful in 5m25s
AI Code Review / AI Code Review (pull_request) Failing after 10m7s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 1m57s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 42s
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 / Frontend Unit Tests (push) Successful in 3m34s
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 17m10s
CI/CD Pipeline / Build Staging API Image (push) Successful in 24m29s
CI/CD Pipeline / Validate - Code Quality (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (push) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Validate - Code Quality (pull_request) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
API Base Image Build / Build API Base Image (push) Successful in 45m16s
Worker Base Image Build / Build Worker Base Image (push) Successful in 57m33s
2026-08-26 20:51:37 +08:00
xiaoxia a271c7981f chore: 重新触发 base image 构建(上次 ACR 推送超时)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Code Quality (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Frontend Lint (pull_request) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / PR Build API Image (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Web Image (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Staging API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Code Quality (push) Has been cancelled
CI/CD Pipeline / Validate - Type Check (mypy) (push) Has been cancelled
CI/CD Pipeline / Validate - Migration (alembic) (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Frontend Lint (push) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (push) Has been cancelled
CI/CD Pipeline / PR Build API Image (push) Has been cancelled
CI/CD Pipeline / PR Build Web Image (push) Has been cancelled
CI/CD Pipeline / PR Build Worker Image (push) Has been cancelled
CI/CD Pipeline / Build Staging API Image (push) Has been cancelled
CI/CD Pipeline / Build Staging Web Image (push) Has been cancelled
CI/CD Pipeline / Build Staging Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (push) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
AI Code Review / AI Code Review (pull_request) Has been cancelled
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
PR Automation / Auto Approve on CI Green (pull_request) Has been cancelled
Preview Deploy / Deploy Preview Environment (pull_request) Has been cancelled
2026-08-26 20:50:51 +08:00
xiaoxia 989f6046d8 fix: 字体文件改为仓库内预置,不再从 GitHub 下载
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 3m44s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 4m19s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m13s
CI/CD Pipeline / Build Staging API Image (push) Successful in 5m34s
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 6m36s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 6m50s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 7m29s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 7m31s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
AI Code Review / AI Code Review (pull_request) Failing after 4m13s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m52s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
PR Automation / Auto Approve on CI Green (pull_request) Successful in 4m11s
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m3s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 5m13s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 2m26s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m28s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 1m8s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 14m41s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 15m14s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 2m19s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m32s
CI/CD Pipeline / Unit Tests (push) Successful in 14m54s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 6m51s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Integration Tests (push) Successful in 6m24s
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 14m26s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 24s
API Base Image Build / Build API Base Image (push) Successful in 43m5s
Worker Base Image Build / Build Worker Base Image (push) Failing after 42m1s
- 将 NotoSansSC-VF.ttf(17MB)提交到 infra/fonts/
- Dockerfile 改为 COPY 方式安装字体,彻底解决国内构建环境
  无法稳定访问 GitHub 导致 base image 构建失败/超时的问题
- 同时修复 api-base 和 worker-base 两个 Dockerfile
2026-08-26 20:06:32 +08:00
xiaoxia 961aa4fe34 fix: Worker Base Image 构建重试 + GitHub 备用镜像
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m27s
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m41s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Build Staging Web Image (push) Successful in 3m4s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 3m9s
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 3m14s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 3m36s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 3m47s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
AI Code Review / AI Code Review (pull_request) Successful in 2m30s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m8s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m38s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 29s
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
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 6m19s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 1m15s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 8m12s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 9m40s
CI/CD Pipeline / Integration Tests (push) Successful in 3m49s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 3m55s
CI/CD Pipeline / Unit Tests (push) Successful in 13m59s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 12m15s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 8s
CI/CD Pipeline / Build Staging API Image (push) Successful in 24m2s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m27s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 47s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m11s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m0s
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
API Base Image Build / Build API Base Image (push) Successful in 38m50s
Worker Base Image Build / Build Worker Base Image (push) Successful in 1h15m55s
- curl 添加 --retry 3 --connect-timeout 30
- 主 URL 失败时自动回退到 ghfast.top 代理镜像
- 同时修复 api-base 和 worker-base 两个 Dockerfile
2026-08-26 19:34:40 +08:00
xiaoxia 3b0a29d850 fix: 修复 Noto Sans CJK SC Bold 字体混入 Mono 等宽变体问题 (#1510)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m4s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m4s
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m0s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 2m52s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 4m16s
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 4m17s
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 3m19s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 3m39s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 33s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 32s
AI Code Review / AI Code Review (pull_request) Successful in 3m54s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 56s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m53s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m31s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 7m52s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 1m34s
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
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 8m27s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 9m6s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m18s
Worker Base Image Build / Build Worker Base Image (push) Failing after 8m49s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m40s
CI/CD Pipeline / Integration Tests (push) Successful in 3m7s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 2m59s
CI/CD Pipeline / Unit Tests (push) Successful in 15m15s
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 12m14s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 9s
API Base Image Build / Build API Base Image (push) Successful in 19m55s
2026-08-26 19:11:59 +08:00
xiaoxia 7da62f0f82 fix: 移除 asset_durations 的 random_preview 条件限制 (#1509)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m15s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m54s
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 2m28s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 2m28s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 3m35s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 3m16s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 3m51s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m49s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 37s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 38s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m36s
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
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 59s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m37s
AI Code Review / AI Code Review (pull_request) Successful in 4m7s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 1m31s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m29s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 9m5s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 8m58s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 9m22s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m37s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 2m59s
CI/CD Pipeline / Integration Tests (push) Successful in 2m53s
CI/CD Pipeline / Unit Tests (push) Successful in 15m5s
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 13m6s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 7s
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com>
Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
2026-08-26 18:46:37 +08:00
CI Bot b2d2abf8b7 style: auto-format with black + isort + prettier [skip ci-format-check]
CI/CD Pipeline / Check if frontend-only change (push) 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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m7s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m12s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 2m1s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 2m47s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m48s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (push) Successful in 3m26s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 3m30s
CI/CD Pipeline / Validate - Code Quality (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (push) Has been cancelled
CI/CD Pipeline / Build Staging API Image (push) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (push) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Validate - Code Quality (pull_request) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / PR Build API Image (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Web Image (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
AI Code Review / AI Code Review (pull_request) Has been cancelled
PR Automation / Auto Approve on CI Green (pull_request) Has been cancelled
Preview Deploy / Deploy Preview Environment (pull_request) Has been cancelled
2026-08-26 10:42:39 +00:00
xiaoxia 57f16364f1 fix: 修复 CI 单测隔离问题 + ruff 代码质量违规
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 57s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m15s
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 2m8s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 2m25s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m38s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m58s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (push) Successful in 4m56s
CI/CD Pipeline / Validate - Code Quality (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (push) Has been cancelled
CI/CD Pipeline / Build Staging API Image (push) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (push) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Validate - Code Quality (pull_request) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / PR Build API Image (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Web Image (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
AI Code Review / AI Code Review (pull_request) Has been cancelled
PR Automation / Auto Approve on CI Green (pull_request) Has been cancelled
Preview Deploy / Deploy Preview Environment (pull_request) Has been cancelled
- test_generated_video_creation_logic: 添加 teardown_class 恢复 setup_class
  中替换的 sys.modules 条目(video_processing.thumbnail_generator / dedup),
  避免 MagicMock 污染后续测试导致 4 个单测失败
- plan_generator_utils: 循环变量 seg_start 未使用 → _seg_start(B007)
- acr_cleanup: 移除未使用变量 open_pr_shas(F841)
- auto_fix_formatting: 移除未使用变量 head_branch_tmp / fix_mode(F841)
2026-08-26 18:36:37 +08:00
CI Bot 850559505f style: auto-format with black + isort + prettier [skip ci-format-check]
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m2s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 1m4s
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m19s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Code Quality (push) Has been cancelled
CI/CD Pipeline / Validate - Type Check (mypy) (push) Has been cancelled
CI/CD Pipeline / Validate - Migration (alembic) (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (push) Has been cancelled
CI/CD Pipeline / Build Staging Web Image (push) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (push) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 52s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 54s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 3m11s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 3m14s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m0s
CI/CD Pipeline / Validate - Code Quality (pull_request) Failing after 3m56s
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 4m15s
AI Code Review / AI Code Review (pull_request) Successful in 8m52s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 5m24s
CI/CD Pipeline / Unit Tests (pull_request) Failing after 13m17s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Failing after 6s
2026-08-26 09:28:53 +00:00
xiaoxia ecbdd49dc1 feat: 素材片段随机起始时间+去重 + MediaKit智能封面抽帧
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m13s
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m14s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 3m24s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 38s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m55s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m55s
CI/CD Pipeline / Validate - Code Quality (pull_request) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / PR Build API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
AI Code Review / AI Code Review (pull_request) Has been cancelled
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 54s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m19s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 2m41s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 2m21s
CI/CD Pipeline / Validate - Code Quality (push) Failing after 5m1s
CI/CD Pipeline / Build Staging API Image (push) Successful in 4m53s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 5m12s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 52s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 1m6s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m23s
CI/CD Pipeline / Integration Tests (push) Successful in 4m2s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m20s
CI/CD Pipeline / Unit Tests (push) Failing after 12m24s
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
## 任务1: 素材片段随机起始时间
- 修改 _calc_random_start_time 增加 used_segments 参数,避开已使用时间段
- 四个分配函数(ONE_TAKE/PIP/VOICE_OVER/VOICE_PIP)各自维护 used_segments
- 同一素材被多个clip使用时,自动记录已用区间,下次随机时避开
- 如果无空间可用,回退到最后已用段之后或缩短时长

## 任务2: MediaKit智能封面抽帧
- 新增 _extract_frames_via_mediakit 函数,上传视频到OSS后调用MediaKit API
- 使用 SceneChange 策略智能选取关键帧
- 失败时自动降级到 ffmpeg 均匀抽帧
- 抽帧后下载帧图、可选叠加标题、上传OSS

## 测试
- 新增 8 个 _calc_random_start_time 单测
- 新增 4 个 distribute_assets 去重逻辑单测
- 新增 4 个 MediaKit 集成单测
- 修复 3 个因字体映射变更的测试断言
2026-08-26 17:22:08 +08:00
xiaoxia 23b6f23bad fix: ASS Fontname 字体名称映射到服务器注册名 (#1508)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 56s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m30s
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 2m42s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 3m1s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m18s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 3m54s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 3m8s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m34s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m44s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
AI Code Review / AI Code Review (pull_request) Failing after 4m8s
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 29s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 3m0s
CI/CD Pipeline / Build Staging API Image (push) Successful in 7m20s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 7m49s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 46s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 53s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m14s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 10m17s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 10m19s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m3s
CI/CD Pipeline / Unit Tests (push) Failing after 14m3s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Failing after 12m14s
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (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 / Integration Tests (push) Successful in 5m10s
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Successful in 5m18s
CI/CD Pipeline / CI Gate (pull_request) Failing after 6s
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com>
Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
2026-08-26 16:56:01 +08:00
xiaoxia bd0082b764 fix: 标题行高1.3→1.05,与后端ASS渲染行间距对齐 (#1507)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m9s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 2m1s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m16s
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m6s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 2m4s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 1m55s
CI/CD Pipeline / Build Staging API Image (push) Successful in 3m26s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m40s
AI Code Review / AI Code Review (pull_request) Successful in 4m34s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m6s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 26s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 55s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
CI/CD Pipeline / Validate - Code Quality (push) Successful in 9m40s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 8m41s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 9m31s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 7m41s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 53s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 1m16s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m21s
CI/CD Pipeline / Integration Tests (push) Successful in 3m57s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 3m46s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m19s
CI/CD Pipeline / Unit Tests (push) Successful in 14m11s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 13m43s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 7s
2026-08-26 12:42:34 +08:00
xiaoxia 32990194d4 fix: 标题顶部边距60→120,标题位置下移 (#1506)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 44s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m18s
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 3m48s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (push) Successful in 3m50s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m59s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 4m5s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 3m19s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 40s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 4m2s
AI Code Review / AI Code Review (pull_request) Failing after 4m45s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 6m32s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 2m40s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m48s
CI/CD Pipeline / Build Staging API Image (push) Successful in 6m42s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 47s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 56s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m6s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 9m57s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 10m2s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m5s
CI/CD Pipeline / Unit Tests (push) Successful in 14m25s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 11m23s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (push) Successful in 5m31s
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Successful in 5m29s
CI/CD Pipeline / CI Gate (pull_request) Successful in 9s
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com>
Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
2026-08-26 01:16:00 +08:00
xiaoxia 11dde783b9 fix: 标题顶部边距60→120,标题位置下移 (#1506)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m14s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 31s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 2m19s
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 / Build Staging Worker Image (pull_request) Has been skipped
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m17s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 1m58s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 1m42s
CI/CD Pipeline / Build Staging API Image (push) Successful in 4m14s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
AI Code Review / AI Code Review (pull_request) Failing after 2m38s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m59s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 4m6s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 26s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 31s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 7m33s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 9m45s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 7m2s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 9m50s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 44s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 3m40s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m23s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 1m26s
CI/CD Pipeline / Integration Tests (push) Successful in 4m10s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m37s
CI/CD Pipeline / Unit Tests (push) Successful in 14m44s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 13m31s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 6s
2026-08-26 00:46:53 +08:00
xiaoxia ddb1a3544d fix: 混音主视频clip音量滤镜缺失 + 自动换行识别已有\N标记 (#1505)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m16s
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m45s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 2m20s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m32s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 2m33s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m32s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 4m2s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m5s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
PR Automation / Auto Approve on CI Green (pull_request) Successful in 4m5s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
AI Code Review / AI Code Review (pull_request) Successful in 4m53s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 35s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 6m45s
CI/CD Pipeline / Build Staging API Image (push) Successful in 7m16s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 2m25s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 50s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 6m56s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 9m8s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 1m1s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m19s
CI/CD Pipeline / Integration Tests (push) Successful in 3m7s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m14s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 2m25s
CI/CD Pipeline / Unit Tests (push) Successful in 13m8s
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 11m21s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 9s
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com>
Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
2026-08-26 00:21:00 +08:00
xiaoxia 323bd2da5e fix: 标题/换行 + TTS replace模式静音原音 + 配音素材库静音原音 (#1504)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 46s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 56s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m52s
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 / Build Staging Worker Image (pull_request) Has been skipped
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 3m7s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 3m2s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 3m4s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 29s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 32s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
CI/CD Pipeline / Build Staging API Image (push) Successful in 5m38s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 5m38s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m56s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m13s
AI Code Review / AI Code Review (pull_request) Successful in 5m25s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 55s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 1m16s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m19s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 7m9s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 9m47s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m28s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 9m40s
CI/CD Pipeline / Integration Tests (push) Successful in 4m40s
CI/CD Pipeline / Unit Tests (push) Successful in 14m37s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Successful in 4m58s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 12m59s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 7s
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com>
Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
2026-08-25 23:06:00 +08:00
xiaoxia 058bfac5c2 fix: 字号滑块上限从48提升至128 (#1503)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 37s
CI/CD Pipeline / Build Staging API Image (push) Successful in 1m57s
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 55s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 3m4s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 3m22s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 2m32s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m30s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m27s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m46s
AI Code Review / AI Code Review (pull_request) Failing after 4m37s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 35s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 36s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 8m22s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 8m53s
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
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 12m0s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m13s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 13m50s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 1m2s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m14s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m17s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 6m58s
CI/CD Pipeline / Unit Tests (push) Successful in 17m29s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Integration Tests (push) Successful in 6m27s
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 17m13s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 5s
2026-08-25 22:23:39 +08:00
xiaoxia 7635a20fdb fix(ass): 字段名归一化(font_size/font_color→size/color) + 移除字号上限36 (#1501)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 47s
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 / Build Staging Worker Image (push) Successful in 1m8s
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 3m23s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 3m23s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m58s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 3m4s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 3m54s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m55s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 39s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m47s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 6m40s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 2m47s
CI/CD Pipeline / Build Staging API Image (push) Successful in 6m45s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 45s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 51s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m6s
AI Code Review / AI Code Review (pull_request) Failing after 7m46s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m1s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 10m58s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 12m36s
CI/CD Pipeline / Unit Tests (push) Successful in 14m28s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 11m53s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (push) Successful in 5m11s
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Successful in 5m0s
CI/CD Pipeline / CI Gate (pull_request) Successful in 9s
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com>
Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
2026-08-25 21:56:02 +08:00
xiaoxia be88e49543 fix: 预览标题坐标系与后端 ASS 烧录 1:1 对齐 (#1502)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 41s
CI/CD Pipeline / Build Staging API Image (push) Successful in 1m51s
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 / Validate - Type Check (mypy) (push) Successful in 2m56s
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m10s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 3m9s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 2m38s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m49s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
AI Code Review / AI Code Review (pull_request) Failing after 2m29s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m50s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 32s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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 / PR Build Worker Image (pull_request) Successful in 30s
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m26s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 5m38s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 55s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 5m8s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 54s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m15s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 9m26s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 10m56s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m5s
CI/CD Pipeline / Unit Tests (push) Successful in 12m51s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 12m51s
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 / Canary Release to Production (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 / Integration Tests (pull_request) Successful in 13m28s
CI/CD Pipeline / CI Gate (pull_request) Successful in 8s
CI/CD Pipeline / Integration Tests (push) Successful in 13m5s
CI/CD Pipeline / CI Gate (push) Has been skipped
- 根据 videoRatio 动态选择后端实际分辨率(9:16→1080x1920, 16:9→1920x1080, 1:1→1080x1080)
- 字号缩放分母从 720 改为实际 PlayResY,移除 96 上限
- 水平/垂直边距按实际 PlayResX/PlayResY 计算
- 描边/阴影按容器缩放比例同步放大
- FrontendPreviewPlayer 标题同时支持半角/和全角/换行
2026-08-25 21:22:14 +08:00
xiaoxia 2494447d94 ci: retry build (transient BuildKit infrastructure error)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 30s
CI/CD Pipeline / Build Staging API Image (push) Successful in 1m32s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 1m32s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m1s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 2m14s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 59s
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 / Build Staging Worker Image (pull_request) Has been skipped
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 1m33s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 1m22s
AI Code Review / AI Code Review (pull_request) Successful in 2m33s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 1m47s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 19s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 26s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m16s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 49s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 7m4s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 4m10s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 6m52s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 1m7s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 58s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m20s
CI/CD Pipeline / Integration Tests (push) Successful in 3m8s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 3m30s
CI/CD Pipeline / Unit Tests (push) Successful in 11m11s
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 10m59s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 7s
2026-08-25 18:08:10 +08:00
xiaoxia 9cbbf9a6e9 fix: 预览标题换行同时匹配半角/和全角/ (#1500)
CI/CD Pipeline / Check if frontend-only change (push) 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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 51s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m36s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m14s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m27s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 2m37s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 3m25s
CI/CD Pipeline / Build Staging API Image (push) Successful in 3m30s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
AI Code Review / AI Code Review (pull_request) Failing after 3m40s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 35s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 26s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m22s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m49s
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
CI/CD Pipeline / Unit Tests (pull_request) Failing after 16m41s
CI/CD Pipeline / Frontend Unit Tests (push) Failing after 18m28s
CI/CD Pipeline / Unit Tests (push) Failing after 19m16s
CI/CD Pipeline / Build Staging Web Image (push) Failing after 20m8s
CI/CD Pipeline / Validate - Code Quality (pull_request) Failing after 20m8s
CI/CD Pipeline / Validate - Code Quality (push) Failing after 20m9s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been skipped
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) 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 / Staging E2E Tests (push) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (push) Successful in 3m59s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 4m0s
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Failing after 6s
PreviewVideoPanel 的 displayTitle.split("/") 改为正则 split(/[//]/),
与 useCanvasPlayer.ts 保持一致,中文输入法下的全角斜杠也能触发换行。
2026-08-25 16:45:14 +08:00
xiaoxia 41c1845aa1 fix: /tts/preview 解析克隆音色 UUID 为 CosyVoice voice_id (#1497)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m1s
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m5s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 3m13s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 3m14s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 3m17s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 3m20s
AI Code Review / AI Code Review (pull_request) Failing after 3m53s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 3m6s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m35s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m53s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 28s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 2m57s
CI/CD Pipeline / Build Staging API Image (push) Successful in 6m34s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 6m33s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 45s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 52s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m11s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 10m21s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 10m21s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m3s
CI/CD Pipeline / Unit Tests (push) Successful in 13m43s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Successful in 5m16s
CI/CD Pipeline / Integration Tests (push) Successful in 5m20s
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 13m24s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 12s
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com>
Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
2026-08-25 16:26:16 +08:00
xiaoxia d11ca875c6 fix: 上传的配音素材直接使用 file_url,不调 TTS 合成 (#1499)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 33s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 2m33s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m32s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 2m43s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m4s
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m55s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 4m8s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m49s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m1s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
AI Code Review / AI Code Review (pull_request) Failing after 4m44s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 35s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 48s
CI/CD Pipeline / Validate - Code Quality (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (push) Has been cancelled
CI/CD Pipeline / Build Staging Web Image (push) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (push) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Validate - Code Quality (pull_request) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
2026-08-25 16:17:51 +08:00
xiaoxia a1ddcb6ff6 feat: add POST /tts/preview endpoint for synchronous TTS preview (#1496)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m10s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m4s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m45s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 2m52s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 3m1s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 3m1s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (push) Successful in 3m57s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 36s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
AI Code Review / AI Code Review (pull_request) Failing after 4m2s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m58s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 3m2s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m17s
CI/CD Pipeline / Build Staging API Image (push) Successful in 6m49s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 56s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 6m35s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 47s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m7s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 2m59s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 11m7s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 11m17s
CI/CD Pipeline / Unit Tests (push) Successful in 14m35s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Integration Tests (push) Successful in 5m11s
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 13m32s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Successful in 5m10s
CI/CD Pipeline / CI Gate (pull_request) Successful in 6s
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com>
Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
2026-08-25 15:21:01 +08:00
xiaoxia b7d96f1b2e fix: 预览面板缩小 + 配音缺失修复 (#1495)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m10s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 45s
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m52s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 3m6s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 3m15s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 3m20s
CI/CD Pipeline / Build Staging API Image (push) Successful in 3m56s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 39s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 33s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m49s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 5m13s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m25s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 56s
AI Code Review / AI Code Review (pull_request) Failing after 5m59s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 1m22s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m23s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 5m24s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 9m30s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m31s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 10m59s
CI/CD Pipeline / Build Staging Web Image (pull_request) Failing after 10m45s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
CI/CD Pipeline / Integration Tests (push) Successful in 3m28s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 3m32s
CI/CD Pipeline / Unit Tests (push) Successful in 13m11s
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 12m6s
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 7s
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com>
Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
2026-08-25 14:02:41 +08:00
xiaoxia f40b081318 fix: 预览面板缩小 + 配音缺失修复 (#1495)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 52s
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m20s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 3m27s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 3m32s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 3m47s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 3m39s
AI Code Review / AI Code Review (pull_request) Failing after 3m3s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 4m4s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Code Quality (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (push) Has been cancelled
CI/CD Pipeline / Build Staging Web Image (push) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (push) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Validate - Code Quality (pull_request) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / PR Build API Image (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
PR Automation / Auto Approve on CI Green (pull_request) Has been cancelled
Preview Deploy / Deploy Preview Environment (pull_request) Has been cancelled
2026-08-25 13:58:28 +08:00
xiaoxia d79cf3726b feat: 预览播放器手机风格视觉改造 — 9:16竖屏外框+毛玻璃控制条 (#1494)
CI/CD Pipeline / Check if frontend-only change (push) 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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m9s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m21s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m33s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 2m35s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 2m35s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m24s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 3m29s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 35s
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
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 39s
AI Code Review / AI Code Review (pull_request) Successful in 3m17s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m46s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m52s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 8m18s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 8m41s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 8m43s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 6m15s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 47s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 1m8s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m18s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 3m39s
CI/CD Pipeline / Integration Tests (push) Successful in 3m23s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m19s
CI/CD Pipeline / Unit Tests (push) Successful in 13m41s
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 12m50s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 6s
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com>
Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
2026-08-25 13:01:30 +08:00
xiaoxia 5a1678c6ee feat: 预览播放器手机风格视觉改造 — 9:16竖屏外框+毛玻璃控制条+精致播放按钮 (#1494)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m13s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m34s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) 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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 1m45s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 1m43s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 2m1s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Code Quality (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (push) Has been cancelled
CI/CD Pipeline / Build Staging API Image (push) Has been cancelled
CI/CD Pipeline / Build Staging Web Image (push) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (push) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Validate - Code Quality (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / PR Build API Image (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Web Image (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
AI Code Review / AI Code Review (pull_request) Has been cancelled
PR Automation / Auto Approve on CI Green (pull_request) Has been cancelled
Preview Deploy / Deploy Preview Environment (pull_request) Has been cancelled
2026-08-25 12:58:40 +08:00
xiaoxia 35f8af50c1 fix: 预览面板容器高度塌陷 — CSS加高度约束 + 预览区加minHeight/背景 (#1493)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m14s
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m20s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 2m16s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 2m21s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m48s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m49s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 3m51s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 27s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 34s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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 4m16s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m17s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 8m17s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 6m50s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 8m33s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 8m35s
AI Code Review / AI Code Review (pull_request) Successful in 8m3s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 44s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 1m16s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m17s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 3m36s
CI/CD Pipeline / Integration Tests (push) Successful in 3m26s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m24s
CI/CD Pipeline / Unit Tests (push) Successful in 13m30s
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 12m54s
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (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 / CI Gate (pull_request) Successful in 6s
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com>
Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
2026-08-25 12:06:00 +08:00
xiaoxia edca702a05 fix: 预览面板容器高度塌陷 — CSS加高度约束 + 预览区加minHeight/背景 (#1493)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Code Quality (push) Has been cancelled
CI/CD Pipeline / Validate - Type Check (mypy) (push) Has been cancelled
CI/CD Pipeline / Validate - Migration (alembic) (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Frontend Lint (push) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (push) Has been cancelled
CI/CD Pipeline / PR Build API Image (push) Has been cancelled
CI/CD Pipeline / PR Build Web Image (push) Has been cancelled
CI/CD Pipeline / PR Build Worker Image (push) Has been cancelled
CI/CD Pipeline / Build Staging API Image (push) Has been cancelled
CI/CD Pipeline / Build Staging Web Image (push) Has been cancelled
CI/CD Pipeline / Build Staging Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (push) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Check if frontend-only change (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Code Quality (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Frontend Lint (pull_request) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / PR Build API Image (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Web Image (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
AI Code Review / AI Code Review (pull_request) Has been cancelled
PR Automation / Auto Approve on CI Green (pull_request) Has been cancelled
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been cancelled
Preview Deploy / Deploy Preview Environment (pull_request) Has been cancelled
2026-08-25 12:05:36 +08:00
xiaoxia 3e876fc054 fix: FrontendPreviewPlayer 用 relative 容器包裹 Fragment,修复绝对定位失控 (#1492)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 1m3s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m6s
PR Automation / Auto Merge on CI Green + Approved (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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m7s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m49s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 2m54s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m54s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 3m1s
AI Code Review / AI Code Review (pull_request) Failing after 3m19s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 40s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 33s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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 3m39s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m0s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 7m4s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 6m15s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 48s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 8m40s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 58s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 9m8s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m12s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m11s
CI/CD Pipeline / Integration Tests (push) Successful in 3m37s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 3m46s
CI/CD Pipeline / Unit Tests (push) Successful in 13m45s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 12m39s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 8s
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com>
Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
2026-08-25 11:41:54 +08:00
xiaoxia a69868c532 fix: FrontendPreviewPlayer 用 relative 容器包裹 Fragment,修复绝对定位失控 (#1492)
CI/CD Pipeline / Check if frontend-only change (push) 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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 59s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m56s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m55s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 3m11s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 3m25s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 3m24s
CI/CD Pipeline / Validate - Code Quality (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (push) Has been cancelled
CI/CD Pipeline / Build Staging API Image (push) Has been cancelled
CI/CD Pipeline / Build Staging Web Image (push) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (push) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Validate - Code Quality (pull_request) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / PR Build API Image (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Web Image (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
AI Code Review / AI Code Review (pull_request) Has been cancelled
PR Automation / Auto Approve on CI Green (pull_request) Has been cancelled
Preview Deploy / Deploy Preview Environment (pull_request) Has been cancelled
2026-08-25 11:38:01 +08:00
xiaoxia 5f87bede1a fix: FrontendPreviewPlayer video fallback 路径补充标题叠加层 (#1491)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m15s
CI/CD Pipeline / Build Staging API Image (push) Successful in 1m17s
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 / Build Staging Worker Image (pull_request) Has been skipped
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m27s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m0s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 2m46s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 2m48s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m49s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 37s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 33s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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 3m27s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m53s
AI Code Review / AI Code Review (pull_request) Successful in 5m37s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 7m8s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 6m18s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 53s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 9m9s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m12s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 9m27s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m10s
CI/CD Pipeline / Integration Tests (push) Successful in 4m7s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 4m34s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 6m48s
CI/CD Pipeline / Unit Tests (push) Successful in 14m2s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 13m42s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 7s
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com>
Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
2026-08-25 11:03:28 +08:00
xiaoxia dab88e0e66 fix: FrontendPreviewPlayer video fallback 路径补充标题叠加层 (#1491)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m4s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m24s
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 2m2s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 3m11s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 3m12s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 3m13s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Code Quality (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (push) Has been cancelled
CI/CD Pipeline / Build Staging API Image (push) Has been cancelled
CI/CD Pipeline / Build Staging Web Image (push) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (push) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Validate - Code Quality (pull_request) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / PR Build API Image (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Web Image (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
AI Code Review / AI Code Review (pull_request) Has been cancelled
PR Automation / Auto Approve on CI Green (pull_request) Has been cancelled
Preview Deploy / Deploy Preview Environment (pull_request) Has been cancelled
2026-08-25 10:59:34 +08:00
xiaoxia 16bc4f53bf feat: 预览改为前端实时播放,确认生成时一次服务器渲染 (#1490)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 1m11s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m15s
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 1m34s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 2m15s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m19s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 2m50s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 3m54s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 52s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 37s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m24s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 4m28s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 6m49s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 6m57s
AI Code Review / AI Code Review (pull_request) Failing after 6m8s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 8m41s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 6m24s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 50s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 3m30s
CI/CD Pipeline / Integration Tests (push) Successful in 4m4s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m29s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m35s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Failing after 12m56s
CI/CD Pipeline / Unit Tests (push) Successful in 13m13s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 13m1s
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 13s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 7m15s
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com>
Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
2026-08-25 10:01:01 +08:00
xiaoxia b05f34432b fix: 预览渲染根据video_ratio计算分辨率,不再默认1280x720 (#1489)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 49s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 59s
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Failing after 1m47s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (push) Successful in 2m48s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 3m53s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 2m59s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m56s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 4m6s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
AI Code Review / AI Code Review (pull_request) Failing after 5m6s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 6m24s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 5m11s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 40s
CI/CD Pipeline / Build Staging API Image (push) Successful in 6m56s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 3m12s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m0s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 8m47s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 8m52s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m30s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 1m37s
CI/CD Pipeline / Integration Tests (push) Successful in 4m4s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 2m38s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m34s
CI/CD Pipeline / Unit Tests (push) Successful in 14m54s
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 12m40s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 8s
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com>
Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
2026-08-25 09:36:01 +08:00
xiaoxia 5b2d5901f0 fix: 预览请求补传 output_width/output_height,匹配 video_ratio (#1488)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 53s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 59s
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 / Build Staging Worker Image (pull_request) Has been skipped
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 1m46s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 3m41s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 3m55s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 3m56s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 3m12s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 1m13s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m10s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 4m19s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 4m5s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 5m46s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 8m11s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 9m7s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 6m35s
AI Code Review / AI Code Review (pull_request) Successful in 9m1s
CI/CD Pipeline / Integration Tests (push) Successful in 4m25s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m22s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 3m13s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m20s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 1m30s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m30s
CI/CD Pipeline / Unit Tests (push) Successful in 13m39s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 12m26s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 13s
2026-08-25 09:10:51 +08:00
xiaoxia ebb664668b fix: 预览请求补传 output_width/output_height,匹配 video_ratio
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m4s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 1m5s
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 1m30s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 1m50s
CI/CD Pipeline / PR Build Worker Image (pull_request) Has been skipped
AI Code Review / AI Code Review (pull_request) Successful in 1m57s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Successful in 1m19s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m5s
CI/CD Pipeline / Frontend Lint (pull_request) Successful in 2m30s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m44s
CI/CD Pipeline / PR Build Web Image (pull_request) Successful in 4m9s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 5m37s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 15s
ACR Cleanup / ACR Image Cleanup (pull_request_target) Successful in 1m3s
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 1m31s
- 新增 calculateResolution 共享工具函数,预览和生成共用同一份分辨率计算
- CreatePreviewRequest 类型新增 output_width/output_height 字段
- buildPreviewRequest 传入计算后的分辨率(9:16 → 1080×1920)
- useGenerateVideo 改用共享函数,去除重复的内联计算
2026-08-25 09:03:34 +08:00
xiaoxia 055f6c0475 feat: 预览改为服务器渲染视频,实现所见即所得 (#1487)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 53s
CI/CD Pipeline / Frontend Lint (push) 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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m11s
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 3m7s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 3m36s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 3m45s
CI/CD Pipeline / Build Staging API Image (push) Successful in 3m47s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 4m16s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 49s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 39s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
PR Automation / Auto Approve on CI Green (pull_request) Successful in 4m33s
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m55s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 7m6s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 8m13s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 45s
AI Code Review / AI Code Review (pull_request) Successful in 7m46s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 1m4s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m4s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 11m8s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 11m16s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m2s
CI/CD Pipeline / Unit Tests (push) Successful in 15m20s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 13m40s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (push) Successful in 6m32s
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Successful in 6m32s
CI/CD Pipeline / CI Gate (pull_request) Successful in 7s
2026-08-25 01:00:55 +08:00
xiaoxia d1890ab128 feat: 预览改为服务器渲染视频,实现所见即所得
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 51s
CI/CD Pipeline / Unit Tests (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 / Frontend Unit Tests (pull_request) Successful in 47s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 1m44s
CI/CD Pipeline / Frontend Lint (pull_request) Successful in 1m23s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 2m21s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m22s
CI/CD Pipeline / PR Build Web Image (pull_request) Successful in 1m50s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 4m11s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 4m26s
AI Code Review / AI Code Review (pull_request) Successful in 7m2s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 8m11s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 8s
ACR Cleanup / ACR Image Cleanup (pull_request_target) Successful in 1m6s
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 1m10s
- 新增 useServerPreview hook:自动创建/轮询服务器预览任务
- PreviewVideoPanel 用 <video> 播放服务器渲染结果,替换 Canvas 播放器
- 素材/配音/BGM 变更自动重新渲染;标题变更标记 stale
- Step5 需预览完成才能前进,确认生成走 confirm 路径秒出
- 轮询间隔 2s,超时 120s,网络错误自动重试 2 次
- 标题样式编辑时 CSS 层实时叠加预览
2026-08-25 00:49:40 +08:00
xiaoxia 7844b65afe feat: create端点兜底复用预览产物 + confirm同步标题 (#1486)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m16s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m31s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 2m40s
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 / Build Staging Worker Image (pull_request) Has been skipped
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 2m49s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 2m35s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m40s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (push) Successful in 3m57s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 45s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m27s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m52s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 3m19s
CI/CD Pipeline / Build Staging API Image (push) Successful in 7m12s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 7m14s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 39s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 1m4s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m9s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 9m47s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 9m45s
AI Code Review / AI Code Review (pull_request) Successful in 8m41s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m16s
CI/CD Pipeline / Integration Tests (push) Successful in 3m38s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 3m48s
CI/CD Pipeline / Unit Tests (push) Successful in 14m50s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 12m29s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 6s
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com>
Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
2026-08-24 23:31:00 +08:00
xiaoxia ccb5ed816a fix: previewTaskId 持久化 + 配音/BGM 参数完整传递 (#1485)
CI/CD Pipeline / Check if frontend-only change (push) 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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m25s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m40s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m29s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 2m50s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 2m53s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 3m21s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 3m57s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 35s
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
AI Code Review / AI Code Review (pull_request) Failing after 3m24s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 34s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m52s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 4m28s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 7m50s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 5m21s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 47s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 59s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m2s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 10m8s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 10m39s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m11s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 4m4s
CI/CD Pipeline / Integration Tests (push) Successful in 4m35s
CI/CD Pipeline / Unit Tests (push) Successful in 14m13s
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 13m37s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 6s
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com>
Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
2026-08-24 22:56:31 +08:00
xiaoxia 3af65c2743 fix: 渲染产物临时目录不在render_plan中提前清理,改由调用方上传后清理 (#1484)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m4s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m22s
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 3m2s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (push) Successful in 3m16s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 3m25s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 3m28s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 3m55s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 30s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
AI Code Review / AI Code Review (pull_request) Failing after 2m48s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 34s
CI/CD Pipeline / Build Staging API Image (push) Successful in 5m7s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m53s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m1s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m9s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m17s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 7m0s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 2m27s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m26s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 12m19s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 12m24s
CI/CD Pipeline / Unit Tests (push) Successful in 14m44s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 13m38s
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (push) Successful in 5m53s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 5m58s
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 6s
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com>
Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
2026-08-24 21:21:00 +08:00
xiaoxia fb4145f6de fix: 兜底关联edit plan和回写config移到enqueue之前,消除竞态条件 (#1482)
CI/CD Pipeline / Check if frontend-only change (push) 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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m16s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m57s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m49s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 3m3s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 3m26s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 3m25s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (push) Successful in 5m33s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m25s
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 / PR Build Worker Image (pull_request) Successful in 35s
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m13s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 3m18s
CI/CD Pipeline / Build Staging API Image (push) Successful in 7m51s
AI Code Review / AI Code Review (pull_request) Successful in 6m39s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 7m28s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 51s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 9m41s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 59s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m10s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 10m10s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m11s
CI/CD Pipeline / Unit Tests (push) Successful in 14m54s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Integration Tests (push) Successful in 5m19s
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Successful in 5m16s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 12m44s
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (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 / CI Gate (pull_request) Successful in 6s
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com>
Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
2026-08-24 16:51:04 +08:00
xiaoxia 2827bf5943 fix: 移除 previewTaskId 自动清除 + 从预览响应提取 source_edit_plan_id (#1483)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m8s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m11s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) 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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 2m54s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m57s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 2m4s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m32s
CI/CD Pipeline / Build Staging API Image (push) Successful in 4m22s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 37s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
AI Code Review / AI Code Review (pull_request) Failing after 3m5s
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 35s
CI/CD Pipeline / Validate - Code Quality (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (push) Has been cancelled
CI/CD Pipeline / Build Staging Web Image (push) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (push) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Validate - Code Quality (pull_request) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
PR Automation / Auto Approve on CI Green (pull_request) Has been cancelled
Preview Deploy / Deploy Preview Environment (pull_request) Has been cancelled
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com>
Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
2026-08-24 16:46:01 +08:00
xiaoxia 7fdea8301c fix: source_edit_plan_id 为空时标记任务为 failed 而非卡在 running (#1481)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 45s
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m50s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 3m8s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (push) Successful in 3m15s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 3m23s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 3m44s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 3m45s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 34s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 33s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
CI/CD Pipeline / Build Staging API Image (push) Successful in 5m11s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m51s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 4m4s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 55s
AI Code Review / AI Code Review (pull_request) Failing after 5m51s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m17s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 1m30s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 7m11s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 9m2s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m38s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 9m46s
CI/CD Pipeline / Integration Tests (push) Successful in 3m57s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 4m23s
CI/CD Pipeline / Unit Tests (push) Successful in 14m25s
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 12m31s
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 9s
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com>
Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
2026-08-24 16:06:00 +08:00
xiaoxia 726fb225c8 fix: Step7 确认生成优先调用 confirmGeneration 复用预览产物,解决卡 10% 问题 (#1480)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 34s
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 2m32s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m39s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 2m3s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m43s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m31s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 3m45s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 35s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
AI Code Review / AI Code Review (pull_request) Successful in 2m56s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 52s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m1s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m39s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 8m28s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 6m16s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 9m25s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 9m36s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m10s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m17s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 2m39s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m38s
CI/CD Pipeline / Integration Tests (push) Successful in 6m52s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 7m0s
CI/CD Pipeline / Unit Tests (push) Successful in 16m41s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 17m11s
CI/CD Pipeline / CI Gate (pull_request) Successful in 23s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com>
Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
2026-08-24 15:31:00 +08:00
xiaoxia c873bb635f refactor: 统一渲染链路,预览即所得(-3370行) (#1479)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 55s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m13s
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m43s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 2m46s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 2m51s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 3m6s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 3m59s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 4m14s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 30s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m53s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 3m6s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 7m6s
CI/CD Pipeline / Build Staging API Image (push) Successful in 7m12s
AI Code Review / AI Code Review (pull_request) Failing after 6m19s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 39s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 8m57s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 1m2s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 8m55s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m9s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m16s
CI/CD Pipeline / Integration Tests (push) Successful in 3m12s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 3m13s
CI/CD Pipeline / Unit Tests (push) Successful in 14m24s
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 12m30s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 8s
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com>
Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
2026-08-24 14:16:00 +08:00
xiaoxia 73665f0d60 fix: 修复 CI 失败的 4 个单元测试 (#1478)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 49s
CI/CD Pipeline / Frontend Lint (push) 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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 1m29s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m32s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m35s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 2m55s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 3m4s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 3m42s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 35s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 35s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
AI Code Review / AI Code Review (pull_request) Successful in 3m42s
CI/CD Pipeline / Build Staging API Image (push) Successful in 5m20s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m48s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 4m23s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 49s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 7m25s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m20s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 1m31s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 7m53s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 7m57s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m37s
CI/CD Pipeline / Integration Tests (push) Successful in 2m53s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 3m18s
CI/CD Pipeline / Unit Tests (push) Successful in 13m45s
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 12m22s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 7s
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com>
Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
2026-08-24 12:26:01 +08:00
xiaoxia 706b9057d6 fix: 3个bug修复 - flush/append_log/plan_id兜底 (#1476)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m4s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m11s
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) 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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m48s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 2m57s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 2m34s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m48s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 4m3s
AI Code Review / AI Code Review (pull_request) Failing after 3m44s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
PR Automation / Auto Approve on CI Green (pull_request) Successful in 4m29s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 47s
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m42s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 3m3s
CI/CD Pipeline / Build Staging API Image (push) Successful in 7m45s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 8m10s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 49s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 8m40s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 8m42s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m14s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 2m12s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m13s
CI/CD Pipeline / Integration Tests (push) Successful in 4m49s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 4m46s
CI/CD Pipeline / Unit Tests (push) Failing after 14m58s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Failing after 12m38s
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Failing after 8s
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com>
Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
2026-08-24 11:26:00 +08:00
xiaoxia 9da2fae3dd fix: sourceEditPlanId 不再用模板ID冒充plan_id,改由后端兜底关联 (#1475)
CI/CD Pipeline / Check if frontend-only change (push) 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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 1m29s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 1m51s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m1s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m23s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 2m16s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 1m58s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 2m10s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m31s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 4m42s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Code Quality (push) Successful in 7m6s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 39s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 7m8s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 47s
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
AI Code Review / AI Code Review (pull_request) Successful in 8m5s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 9m57s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 9m6s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m0s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m26s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 6m45s
CI/CD Pipeline / Integration Tests (push) Successful in 6m53s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m45s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 3m45s
CI/CD Pipeline / Unit Tests (push) Failing after 18m7s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Failing after 15m11s
CI/CD Pipeline / CI Gate (pull_request) Failing after 32s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com>
Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
2026-08-24 10:24:54 +08:00
xiaoxia b19bfaa34d fix: sourceEditPlanId 不再用模板ID冒充plan_id,改由后端兜底关联 (#1475)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 1m8s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m10s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 1m27s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m37s
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m37s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 2m50s
CI/CD Pipeline / Build Staging API Image (push) Successful in 4m27s
AI Code Review / AI Code Review (pull_request) Successful in 3m43s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 4m58s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 4m56s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Code Quality (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (push) Has been cancelled
CI/CD Pipeline / Build Staging Web Image (push) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (push) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Validate - Code Quality (pull_request) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / PR Build API Image (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
2026-08-24 10:17:45 +08:00
xiaoxia 61770cd4e4 fix(worker): render_plan 保留视频原声并尊重每clip音量 (#1474)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m12s
CI/CD Pipeline / Frontend Lint (push) 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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m40s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 3m4s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 3m8s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 3m9s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 3m10s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 3m28s
AI Code Review / AI Code Review (pull_request) Failing after 2m17s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 35s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
CI/CD Pipeline / Build Staging Web Image (push) Successful in 4m34s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 38s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m31s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 4m3s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m11s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 6m47s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m15s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 7m47s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 6m38s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 2m41s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m46s
CI/CD Pipeline / Integration Tests (push) Successful in 3m4s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 3m12s
CI/CD Pipeline / Unit Tests (push) Failing after 13m33s
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Failing after 11m30s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Failing after 10s
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com>
Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
2026-08-24 01:16:00 +08:00
xiaoxia 024aca3557 fix: source_edit_plan_id 正确传递 + clips时长与预览一致 (#1473)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m17s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m48s
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m51s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 3m8s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 3m13s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 3m16s
CI/CD Pipeline / Build Staging API Image (push) Successful in 3m27s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 22s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 46s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m17s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m42s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 6m34s
AI Code Review / AI Code Review (pull_request) Successful in 5m23s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 7m44s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 7m47s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 7m10s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 56s
CI/CD Pipeline / Integration Tests (push) Successful in 3m12s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m13s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 1m41s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m50s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 5m47s
CI/CD Pipeline / Unit Tests (push) Failing after 17m39s
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Failing after 15m8s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Failing after 7s
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com>
Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
2026-08-23 23:46:00 +08:00
xiaoxia bbf27ec3f6 chore: 清理剪辑模板编辑器生成视频死代码 + 重命名为剪辑模板 (#1472)
CI/CD Pipeline / Check if frontend-only change (push) 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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m22s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m37s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 2m59s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m59s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 3m0s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 3m7s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m42s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
PR Automation / Auto Approve on CI Green (pull_request) Successful in 4m22s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 25s
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
CI/CD Pipeline / Build Staging API Image (push) Successful in 6m29s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 2m42s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 5m17s
AI Code Review / AI Code Review (pull_request) Failing after 7m31s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 8m58s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 9m2s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 9m6s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 59s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m11s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 2m23s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 3m43s
CI/CD Pipeline / Integration Tests (push) Successful in 3m54s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m18s
CI/CD Pipeline / Unit Tests (push) Failing after 13m47s
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Failing after 12m35s
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) Failing after 6s
2026-08-23 23:06:28 +08:00
xiaoxia febb1bcfce chore: 清理剪辑模板编辑器生成视频死代码 + 重命名为剪辑模板 (#1472)
CI/CD Pipeline / Check if frontend-only change (push) 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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m2s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Code Quality (push) Has been cancelled
CI/CD Pipeline / Validate - Type Check (mypy) (push) Has been cancelled
CI/CD Pipeline / Validate - Migration (alembic) (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Frontend Lint (push) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (push) Has been cancelled
CI/CD Pipeline / PR Build API Image (push) Has been cancelled
CI/CD Pipeline / PR Build Web Image (push) Has been cancelled
CI/CD Pipeline / PR Build Worker Image (push) Has been cancelled
CI/CD Pipeline / Build Staging API Image (push) Has been cancelled
CI/CD Pipeline / Build Staging Web Image (push) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (push) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Check if frontend-only change (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Code Quality (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Frontend Lint (pull_request) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / PR Build API Image (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Web Image (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
AI Code Review / AI Code Review (pull_request) Has been cancelled
PR Automation / Auto Approve on CI Green (pull_request) Has been cancelled
Preview Deploy / Deploy Preview Environment (pull_request) Has been cancelled
前端:
- 删除 GenerationProgressModal/GenerationHistoryModal 组件及目录
- 删除 generateEditPlan/getGenerationStatus/getEditPlanGenerations 三个死API函数
- 删除对应类型 GenerateResponse/EditPlanGeneration/GenerationStatusResponse
- 清理测试文件中的 mock 和引用
- 用户可见文案 '剪辑编辑器' 统一改为 '剪辑模板'
- 不改变量名/组件名/路由路径/API路径

后端:
- 删除 templates_editor/generation.py 死接口文件
- 清理 _fallback.py、dependencies.py、schemas.py 中的死代码
- 删除对应无用测试文件
2026-08-23 23:05:15 +08:00
xiaoxia 9fd1246c6b fix(worker): P1 修复任务状态覆盖 + 封面metadata属性名错误 (#1471)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m2s
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 1m23s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m41s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m19s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 2m51s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 3m21s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 3m38s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 3m38s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 33s
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
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 35s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m19s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m20s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 4m19s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 6m5s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m11s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 1m38s
AI Code Review / AI Code Review (pull_request) Successful in 6m7s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 7m41s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 7m9s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m47s
CI/CD Pipeline / Integration Tests (push) Successful in 3m26s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 2m55s
CI/CD Pipeline / Unit Tests (push) Failing after 13m5s
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Failing after 11m56s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Failing after 8s
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com>
Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
2026-08-23 19:11:01 +08:00
xiaoxia 392a20002c feat: Step2选素材同步写入edit_plan_clips (#1469)
CI/CD Pipeline / Check if frontend-only change (push) 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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m12s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m12s
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 1m56s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 1m57s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m2s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 2m43s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 3m43s
AI Code Review / AI Code Review (pull_request) Failing after 2m28s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 35s
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 33s
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 3m38s
CI/CD Pipeline / Build Staging API Image (push) Successful in 5m18s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m26s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m8s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 7m8s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 7m11s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m22s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 7m9s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 2m49s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m41s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 3m37s
CI/CD Pipeline / Integration Tests (push) Successful in 3m38s
CI/CD Pipeline / Unit Tests (push) Failing after 13m10s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Failing after 12m20s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Failing after 9s
2026-08-23 17:42:26 +08:00
xiaoxia 42744241c4 fix(worker): P0 修复@celery_app.task装饰器错位导致所有生成任务崩溃 (#1470)
CI/CD Pipeline / Check if frontend-only change (push) 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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 58s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m18s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 1m36s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m59s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 3m3s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 3m16s
CI/CD Pipeline / Build Staging API Image (push) Successful in 3m19s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 36s
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 / PR Build Worker Image (pull_request) Successful in 33s
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (push) Successful in 4m31s
AI Code Review / AI Code Review (pull_request) Failing after 4m13s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 4m11s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 4m12s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m16s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m17s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 8m22s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 2m32s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 6m54s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 8m34s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m37s
CI/CD Pipeline / Integration Tests (push) Successful in 3m0s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 2m59s
CI/CD Pipeline / Unit Tests (push) Failing after 13m15s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Failing after 11m37s
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) 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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Failing after 6s
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com>
Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
2026-08-23 17:16:00 +08:00
xiaoxia ab40c57e9e feat: sync selected materials to edit_plan_clips on Step2 (PR #1469)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 51s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m16s
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 / Build Staging Worker Image (pull_request) Has been skipped
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 1m57s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 1m55s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 2m43s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m50s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 38s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 3m48s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 30s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m15s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m49s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 7m32s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 7m47s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 6m0s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 8m5s
AI Code Review / AI Code Review (pull_request) Successful in 8m21s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m3s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m13s
CI/CD Pipeline / Integration Tests (push) Successful in 3m11s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 3m20s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 3m33s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m39s
CI/CD Pipeline / Unit Tests (push) Successful in 12m25s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 12m2s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 9s
- New API updateEditPlanClips (PUT /templates/{id}/editor/clips)
- useStep2Materials: debounced 800ms clips write, same duration
  logic as FrontendPreviewPlayer.buildPlaybackSegments
- buildClipsFromAssets shared util ensures preview/DB consistency
- Supports manual + smart-match modes, silent failure
2026-08-23 16:25:50 +08:00
xiaoxia b4e3bb0fe7 refactor(worker): generate_video直接读取edit_plan_clips渲染 (#1468)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 47s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 50s
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 3m22s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 3m27s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 3m31s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Build Staging Web Image (push) Successful in 3m40s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 3m4s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
AI Code Review / AI Code Review (pull_request) Failing after 3m53s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m31s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 30s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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 3m45s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 3m30s
CI/CD Pipeline / Build Staging API Image (push) Successful in 7m24s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 7m21s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 8m19s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 8m24s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m4s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m21s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 2m25s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 3m21s
CI/CD Pipeline / Integration Tests (push) Successful in 3m28s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m27s
CI/CD Pipeline / Unit Tests (push) Successful in 15m5s
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 14m25s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 9s
2026-08-23 16:03:30 +08:00
xiaoxia 4de4b8dc08 fix(cover): E2兜底封面标题样式透传color/position/font_size (#1467)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 47s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 1m30s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) 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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 3m5s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m53s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 3m25s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m37s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (push) Successful in 3m2s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 22s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 38s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
AI Code Review / AI Code Review (pull_request) Successful in 3m23s
CI/CD Pipeline / Build Staging API Image (push) Successful in 5m27s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m14s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 6m28s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m24s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m5s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m18s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 1m31s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 8m6s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 8m9s
CI/CD Pipeline / Integration Tests (push) Successful in 3m1s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m45s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 2m28s
CI/CD Pipeline / Unit Tests (push) Successful in 14m12s
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 11m29s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 9s
2026-08-23 14:57:05 +08:00
xiaoxia 622e9742f5 fix(edit-flow): 批量生成 plan.config 只回写一次 (#1466)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m4s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m19s
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 1m42s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 3m11s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 2m10s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (push) Successful in 3m10s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m30s
AI Code Review / AI Code Review (pull_request) Failing after 3m34s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 29s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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 4m14s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m46s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 2m53s
CI/CD Pipeline / Build Staging API Image (push) Successful in 6m56s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 6m56s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 7m30s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 54s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 7m51s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m11s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 1m11s
CI/CD Pipeline / Integration Tests (push) Successful in 2m41s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m31s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 2m39s
CI/CD Pipeline / Unit Tests (push) Successful in 14m18s
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 11m44s
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 / Canary Release to Production (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 / CI Gate (pull_request) Successful in 10s
2026-08-23 14:19:16 +08:00
xiaoxia ab381b2e74 feat(generate): 编辑流程自动保存草稿+创建任务参数修复+轮询改新接口+清理幽灵API (#1465)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m2s
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m39s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 1m45s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 2m39s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 2m35s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m18s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
AI Code Review / AI Code Review (pull_request) Failing after 2m37s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m43s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m32s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 30s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 25s
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
CI/CD Pipeline / Build Staging API Image (push) Successful in 6m21s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 7m6s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 7m51s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 6m44s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 9m39s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m2s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 3m36s
CI/CD Pipeline / Integration Tests (push) Successful in 3m33s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m6s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 1m10s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m25s
CI/CD Pipeline / Unit Tests (push) Successful in 13m14s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 12m47s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 46s
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com>
Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
2026-08-23 13:56:32 +08:00
xiaoxia 94caa63436 Merge pull request 'fix(edit-flow): 补全 title_config 数据链路,修复编辑流程断裂' (#1464) from fix/edit-flow-data-chain into develop
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Validate - Code Quality (push) Has been cancelled
CI/CD Pipeline / Validate - Type Check (mypy) (push) Has been cancelled
CI/CD Pipeline / Validate - Migration (alembic) (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Frontend Lint (push) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (push) Has been cancelled
CI/CD Pipeline / PR Build API Image (push) Has been cancelled
CI/CD Pipeline / PR Build Web Image (push) Has been cancelled
CI/CD Pipeline / PR Build Worker Image (push) Has been cancelled
CI/CD Pipeline / Build Staging API Image (push) Has been cancelled
CI/CD Pipeline / Build Staging Web Image (push) Has been cancelled
CI/CD Pipeline / Build Staging Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (push) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Check if frontend-only change (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Code Quality (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Frontend Lint (pull_request) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / PR Build API Image (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Web Image (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Staging API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
AI Code Review / AI Code Review (pull_request) Has been cancelled
PR Automation / Auto Approve on CI Green (pull_request) Has been cancelled
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been cancelled
Preview Deploy / Deploy Preview Environment (pull_request) Has been cancelled
2026-08-23 13:55:42 +08:00
xiaoxia fe49fef1ad fix: auto-save draft + API cleanup for editing flow (PR #1465)
CI/CD Pipeline / Check if frontend-only change (push) 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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 55s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m12s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Validate - Code Quality (push) Has been cancelled
CI/CD Pipeline / Validate - Type Check (mypy) (push) Has been cancelled
CI/CD Pipeline / Validate - Migration (alembic) (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (push) Has been cancelled
CI/CD Pipeline / Build Staging API Image (push) Has been cancelled
CI/CD Pipeline / Build Staging Web Image (push) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (push) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Validate - Code Quality (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Frontend Lint (pull_request) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / PR Build API Image (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Web Image (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
AI Code Review / AI Code Review (pull_request) Has been cancelled
PR Automation / Auto Approve on CI Green (pull_request) Has been cancelled
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been cancelled
Preview Deploy / Deploy Preview Environment (pull_request) Has been cancelled
- Step2/Step4 auto-save via useDraftAutoSave (GET-merge-PUT, serial queue)
- useDraftAutoSave: failed saves preserve patch with exponential backoff retry
- Step6 cover requests include full title_config
- Step7 create task: source_edit_plan_id, title_config, cover_url priority
- Polling switched to GET /generation/tasks/{task_id} with proper error handling
- getGenerationTaskResults retries before treating as failure
- Removed 7 ghost API functions (non-existent backend routes)
- BGM presets path updated to /templates/{id}/editor/bgm/presets
- Type alignment for BatchGenerationTaskResponse
2026-08-23 13:53:36 +08:00
CI Bot 0b000f96a6 style: auto-format with black + isort + prettier [skip ci-format-check]
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 45s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 41s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 1m46s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 1m50s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 1m53s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m26s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 1m46s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m42s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 5m18s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 3m17s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 10m6s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (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
AI Code Review / AI Code Review (pull_request) Waiting for AI Code Review to complete
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 1m13s
2026-08-23 05:39:27 +00:00
CI Bot 817c6fa6a3 test: 补全 _writeback_edit_plan_config 单测,修复增量覆盖率不足
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 35s
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 1m39s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 1m40s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 1m20s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
AI Code Review / AI Code Review (pull_request) Failing after 2m16s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 34s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m8s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 1m38s
CI/CD Pipeline / Validate - Code Quality (pull_request) Failing after 4m18s
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m17s
新增 9 个单元测试覆盖 generation_tasks.py 增量代码:
- 空 plan_id 直接返回
- plan 不存在 warning + 不 commit
- 正常写入(有/无 title_config)
- config 非 dict 兜底
- DB 异常 rollback + rollback 失败静默
- 空 title_config 不写入
2026-08-23 13:34:57 +08:00
CI Bot 410f672195 style: auto-format with black + isort + prettier [skip ci-format-check]
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 37s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 1m21s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 1m29s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 1m50s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 37s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m48s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 2m15s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m50s
AI Code Review / AI Code Review (pull_request) Successful in 4m53s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 7m1s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 2m40s
CI/CD Pipeline / Unit Tests (pull_request) Failing after 12m4s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Failing after 6s
2026-08-23 05:15:40 +00:00
agent 06f68230af fix(edit-flow): 补全 title_config 数据链路,修复编辑流程断裂
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 32s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 55s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 1m38s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 1m58s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 2m1s
AI Code Review / AI Code Review (pull_request) Failing after 2m15s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m29s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 2m1s
CI/CD Pipeline / Validate - Code Quality (pull_request) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
PR Automation / Auto Approve on CI Green (pull_request) Has been cancelled
1. Schema: CreateGenerationTaskRequest 增加 title_config(dict|None=None)
2. DB: generation_tasks 新增 title_config JSON 列 (alembic 057)
3. Domain/ORM/Repo/UseCase 全链路透传 title_config
4. API 创建任务成功后,merge 回写 EditPlan.config
   (generation_task_id + title_config),失败不影响主流程
5. Worker 优先使用 title_config 构建标题图层,custom_title 兜底
6. GenerationTaskResponse 返回 title_config
7. 旧路由 /generate 和 /generation-status 标记 DEPRECATED

所有新字段默认 None/{},不传时行为与现在完全一致。
2026-08-23 13:12:40 +08:00
xiaoxia 5a5c653d2c feat(cleanup): pending 任务自动清理,防止队列占满 (#1463)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m5s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 1m13s
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 / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 2m8s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 2m17s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m35s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m19s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 3m41s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m4s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
PR Automation / Auto Approve on CI Green (pull_request) Successful in 4m13s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 31s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 2m38s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 6m29s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 7m10s
CI/CD Pipeline / Build Staging API Image (push) Successful in 7m18s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 6m46s
CI/CD Pipeline / Integration Tests (push) Successful in 2m51s
AI Code Review / AI Code Review (pull_request) Successful in 8m5s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 3m5s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 3m9s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 1m2s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m3s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m12s
CI/CD Pipeline / Unit Tests (push) Successful in 13m12s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 12m19s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 6s
2026-08-23 12:55:39 +08:00
CI Bot 2148e2bc48 chore: trigger CI rebuild after api-base image update (Pillow + CJK fonts)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m0s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m3s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 2m15s
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 2m25s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m26s
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m23s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (push) Successful in 5m13s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m48s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 2m30s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 4m8s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 7m30s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 7m32s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 7m48s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 2m54s
AI Code Review / AI Code Review (pull_request) Successful in 8m29s
CI/CD Pipeline / Integration Tests (push) Successful in 2m39s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 3m6s
CI/CD Pipeline / Unit Tests (push) Successful in 14m38s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 12m14s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 6s
CI/CD Pipeline / Build Staging API Image (push) Successful in 16m55s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 52s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 46s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 53s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m2s
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
2026-08-23 11:13:41 +08:00
xiaoxia 9ac21d37f0 Merge pull request 'fix(cover): Worker本地ffmpeg抽帧 + E2源素材封面标题叠加' (#1462) from fix/cover-ffmpeg-title-overlay into develop
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 48s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m12s
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 1m29s
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 2m48s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 3m24s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 3m48s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 3m8s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m33s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 6m18s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 36s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
PR Automation / Auto Approve on CI Green (pull_request) Successful in 4m7s
CI/CD Pipeline / Build Staging API Image (push) Successful in 7m1s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 7m13s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 40s
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
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m33s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 7m56s
AI Code Review / AI Code Review (pull_request) Successful in 8m30s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 1m30s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m47s
CI/CD Pipeline / Integration Tests (push) Successful in 5m8s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 4m37s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m41s
CI/CD Pipeline / Unit Tests (push) Successful in 14m40s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 12m57s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 19s
API Base Image Build / Build API Base Image (push) Successful in 29m19s
Worker Base Image Build / Build Worker Base Image (push) Successful in 33m30s
2026-08-23 10:43:40 +08:00
CI Bot f6b50b49ec fix(cover): worker local ffmpeg cover frames + title overlay for source-asset fallback
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 49s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 1m53s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m4s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 1m30s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m29s
CI/CD Pipeline / PR Build Web 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 3m39s
AI Code Review / AI Code Review (pull_request) Successful in 4m45s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 37s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 1m23s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 5m34s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 2m39s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 10m23s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 15s
ACR Cleanup / ACR Image Cleanup (pull_request_target) Successful in 52s
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 1m31s
问题:
1. 之前 Worker 用 MediaKit 网络抽帧写 cover_url,因状态字符串 bug(#1461 已修)
   一直失败;且在 API 请求内同步抽帧易超时。
2. 封面从源素材抽取时无标题(源素材未烧录标题)。

修复:
1. Worker 渲染完成后直接复用 RenderAdapter 已用本地 ffmpeg 抽出的 cover_candidates:
   - _render_video 返回值改为 (output_path, render_duration, cover_candidates)
   - 第一帧写入 gen_task.cover_url,完整列表写入 metadata.cover_candidates
   - 删除步骤 4.5 的 MediaKit 抽帧代码(不依赖网络,不阻塞)
2. 标题叠加:
   - 新增 packages/shared/title_overlay.py,Pillow 绘制白色文字+黑色描边/阴影,
     支持 CJK 字体和自动换行(API/Worker 共用)
   - thumbnail_generator.extract_and_upload_cover_frames 的 title_text 参数真正生效
   - render_adapter 从已渲染视频抽帧时传空 title_text(标题已 ASS 烧录,避免重影)
   - 封面 API E2 从源素材抽帧后,从 plan.config.title.text 读取标题并叠加
3. API 基础镜像增加 Pillow 和 fonts-noto-cjk(E2 标题叠加依赖)

测试:新增 test_title_overlay.py(5)、E2 标题透传测试,更新 1294 解包;
相关 51 passed。
2026-08-23 10:28:52 +08:00
xiaoxia 2837f11123 fix: 预览完成后保存rendered_storage_key + createPreview传title_config
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m0s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m9s
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 1m26s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 2m18s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m20s
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 3m9s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 51s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 3m47s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 47s
AI Code Review / AI Code Review (pull_request) Failing after 4m51s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m48s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 5m49s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 6m35s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 6m38s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 8m24s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 7m22s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m9s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 4m40s
CI/CD Pipeline / Integration Tests (push) Successful in 4m36s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m49s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 3m32s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 4m24s
CI/CD Pipeline / Unit Tests (push) Successful in 16m33s
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 15m37s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 13s
2026-08-23 10:19:28 +08:00
xiaoxia ea42e48a9f Merge pull request 'fix(mediakit): 抽帧轮询识别 completed 状态,修复封面抽帧始终超时失败' (#1461) from fix/mediakit-completed-status into develop
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 49s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m0s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 2m56s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 2m57s
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 3m0s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 3m16s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 3m17s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 44s
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
AI Code Review / AI Code Review (pull_request) Successful in 3m23s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m2s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 3m14s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 4m34s
CI/CD Pipeline / Build Staging API Image (push) Successful in 6m46s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m7s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 7m12s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 8m53s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 1m2s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m11s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 9m9s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m25s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 3m27s
CI/CD Pipeline / Integration Tests (push) Successful in 3m55s
CI/CD Pipeline / Unit Tests (push) Successful in 14m7s
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 12m28s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 7s
2026-08-23 01:02:24 +08:00
CI Bot 39683bda09 fix(mediakit): accept "completed" status in extract_frames polling
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 37s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 49s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 1m38s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 1m38s
AI Code Review / AI Code Review (pull_request) Successful in 1m40s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 1m56s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 1m43s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m25s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m41s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 4m53s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 1m52s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 8m15s
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 11s
ACR Cleanup / ACR Image Cleanup (pull_request_target) Successful in 41s
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 43s
火山引擎 MediaKit 抽帧 API 完成时返回 status="completed",
但 _poll_task_result_with_error 只判断 "success",
导致任务实际已成功返回帧数据,客户端却继续轮询到超时返回 None,
封面抽帧一直失败。

与同文件 _poll_video_understand_result_with_error 的判断保持一致。
Worker 渲染后抽帧和 API E1/E2 兜底均受此 bug 影响。
2026-08-23 00:51:18 +08:00
xiaoxia b3aa05e510 Merge pull request 'fix(cover): 封面 API MediaKit 抽帧短超时,避免请求挂死' (#1460) from fix/cover-mediakit-timeout into develop
CI/CD Pipeline / Check if frontend-only change (push) 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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m2s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m25s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 2m21s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m22s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m28s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 2m27s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (push) Successful in 3m51s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m51s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
PR Automation / Auto Approve on CI Green (pull_request) Successful in 4m10s
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 29s
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 2m28s
CI/CD Pipeline / Build Staging API Image (push) Successful in 6m56s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 7m40s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 7m46s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 6m51s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m8s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m10s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 1m13s
AI Code Review / AI Code Review (pull_request) Successful in 7m51s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 3m38s
CI/CD Pipeline / Integration Tests (push) Successful in 3m36s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m27s
CI/CD Pipeline / Unit Tests (push) Successful in 13m12s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 12m10s
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 8s
2026-08-23 00:15:05 +08:00
CI Bot 005f500ee1 fix(cover): short MediaKit polling timeout in API cover endpoint (E1/E2)
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 50s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 39s
AI Code Review / AI Code Review (pull_request) Successful in 1m36s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 1m38s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 1m45s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 1m53s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m14s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 1m35s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m22s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 2m49s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 5m51s
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production API 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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Successful in 2m3s
CI/CD Pipeline / CI Gate (pull_request) Successful in 7s
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 57s
ACR Cleanup / ACR Image Cleanup (pull_request_target) Successful in 1m32s
E1/E2 fallback calls used default 30 polling attempts * 2s = 60s each,
causing the cover API to hang ~2 minutes when MediaKit is slow/unreachable.
Set max_poll_attempts=5, poll_interval=2, max_retries=0 for API-side
fallback so it fails fast (~10s) instead of blocking the request.

Worker-side extraction keeps default timeout (background task, safe).
2026-08-23 00:03:52 +08:00
xiaoxia a11178eb13 fix(cover): extract cover from source asset when no backend preview exists (#1459)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m1s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m19s
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m12s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 2m16s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m13s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (push) Successful in 3m37s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 2m39s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 37s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m20s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 4m20s
AI Code Review / AI Code Review (pull_request) Failing after 4m50s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 2m41s
CI/CD Pipeline / Build Staging API Image (push) Successful in 6m35s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m10s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 7m57s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 1m2s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m4s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 8m53s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 8m39s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m19s
CI/CD Pipeline / Integration Tests (push) Successful in 3m29s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 3m29s
CI/CD Pipeline / Unit Tests (push) Successful in 14m27s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 12m42s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 8s
2026-08-22 23:15:33 +08:00
xiaoxia 4a6d84921d fix(cover): add plan.config.cover_candidates fallback in cover generation endpoint (#1458)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 53s
CI/CD Pipeline / Frontend Lint (push) 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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m24s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 1m42s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 3m16s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 3m19s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 3m29s
AI Code Review / AI Code Review (pull_request) Successful in 2m32s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 4m27s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 5m56s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m45s
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 29s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 2m32s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 7m12s
CI/CD Pipeline / Build Staging API Image (push) Successful in 7m43s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 7m24s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 8m50s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m7s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m21s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 1m27s
CI/CD Pipeline / Integration Tests (push) Successful in 3m10s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 3m32s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m36s
CI/CD Pipeline / Unit Tests (push) Successful in 14m5s
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 13m32s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 8s
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com>
Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
2026-08-22 21:51:01 +08:00
xiaoxia 98cd806d29 style: 封面预览框缩小至max-width 180px居中
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m0s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m30s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) 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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m28s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 2m29s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 2m48s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m55s
CI/CD Pipeline / Build Staging API Image (push) Successful in 3m44s
AI Code Review / AI Code Review (pull_request) Failing after 2m54s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 35s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 30s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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 3m49s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m38s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 7m23s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 7m49s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 8m14s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 9m31s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m14s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m7s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 2m31s
CI/CD Pipeline / Integration Tests (push) Successful in 5m37s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 5m13s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m35s
CI/CD Pipeline / Unit Tests (push) Successful in 17m5s
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 14m48s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 9s
2026-08-22 20:34:52 +08:00
xiaoxia 6a57431f68 fix: 配音素材时长/大小显示为0 — fallback读取metadata字段
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 59s
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 1m47s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m35s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 2m54s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 2m54s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 3m9s
CI/CD Pipeline / Build Staging API Image (push) Successful in 3m39s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 38s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
AI Code Review / AI Code Review (pull_request) Failing after 3m27s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 35s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m0s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m58s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 7m21s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 8m22s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 8m29s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 8m48s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m2s
CI/CD Pipeline / Integration Tests (push) Successful in 3m8s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m7s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 1m23s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 3m0s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m39s
CI/CD Pipeline / Unit Tests (push) Successful in 14m39s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 12m17s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 9s
2026-08-22 18:41:18 +08:00
xiaoxia d19fa951ee fix: 标题/不换行+字体映射表修复
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m0s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m6s
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 2m22s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m24s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m52s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 2m54s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 3m41s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 52s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m32s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 31s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 4m26s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 6m59s
AI Code Review / AI Code Review (pull_request) Failing after 6m6s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 7m17s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 8m34s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 8m37s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m2s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 3m43s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m12s
CI/CD Pipeline / Integration Tests (push) Successful in 3m46s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 1m26s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m44s
CI/CD Pipeline / Unit Tests (push) Successful in 14m31s
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 12m37s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 8s
2026-08-22 18:23:46 +08:00
xiaoxia e928068efd refactor: v3调度器——所有状态存入ref彻底消除RAF闭包陷阱+片段切换先播下一段再切可见性
CI/CD Pipeline / Check if frontend-only change (push) 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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m2s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m12s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 2m29s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m33s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 2m51s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 3m10s
CI/CD Pipeline / Build Staging API Image (push) Successful in 3m13s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 36s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 35s
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 4m49s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 4m11s
AI Code Review / AI Code Review (pull_request) Successful in 6m42s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 8m8s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 6m4s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 8m50s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 9m3s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m5s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m5s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 1m12s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m31s
CI/CD Pipeline / Integration Tests (push) Successful in 4m18s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 4m7s
CI/CD Pipeline / Unit Tests (push) Successful in 13m49s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 13m3s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 9s
2026-08-22 15:35:37 +08:00
xiaoxia 18371dc438 fix: 修复RAF循环穿透导致指数级增长+音频同步重置卡顿
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m4s
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 / Build Staging Worker Image (pull_request) Has been skipped
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m20s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 1m54s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m0s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 2m3s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 2m6s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 1m14s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 3m41s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 35s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 4m30s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m56s
AI Code Review / AI Code Review (pull_request) Successful in 5m47s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 7m52s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 8m18s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 6m23s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 9m10s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 56s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m4s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 1m21s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 3m8s
CI/CD Pipeline / Integration Tests (push) Successful in 2m59s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m28s
CI/CD Pipeline / Unit Tests (push) Successful in 13m23s
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 13m3s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 8s
useSegmentScheduler.ts:
- 新增 tickRef 保存最新 tick 引用,所有 RAF 调度通过 () => tickRef.current()
- 片段边界切换分支加 return,阻止旧闭包穿透到末尾重复调度 RAF
  (这是网页越来越卡的根因:每次片段切换 RAF 链数量翻倍)
- play() 和重播分支的 RAF 同样改用 tickRef

FrontendPreviewPlayer.tsx:
- 片段切换音频同步 useEffect 移除 currentTime 依赖
  原依赖每200ms变化导致 audio.currentTime 被反复重置,音频卡顿
2026-08-22 13:38:02 +08:00
xiaoxia 4e9c9a2eda fix: 禁用useCanvasPlayer后台解码+恢复所有video预加载
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m6s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m32s
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 2m56s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 3m5s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 3m2s
CI/CD Pipeline / Build Staging API Image (push) Successful in 3m19s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 3m25s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 41s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 36s
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m43s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 4m15s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 7m33s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 7m44s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m2s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 8m43s
AI Code Review / AI Code Review (pull_request) Successful in 7m52s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 9m9s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 1m4s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m6s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m18s
CI/CD Pipeline / Integration Tests (push) Successful in 5m32s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 6m4s
CI/CD Pipeline / Unit Tests (push) Successful in 15m32s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 13m19s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 7s
- useCanvasPlayer 新增 enabled 参数,enabled=false 时 hasSupport=false
  且 init useEffect 直接 return,彻底不执行 WebCodecs 初始化和后台解码
- FrontendPreviewPlayer 传入 enabled=(useWebCodecs && !forceVideoFallback),
  useWebCodecs=false 时 useCanvasPlayer 完全不启动,消除网页卡顿元凶
- 恢复所有 video 元素 preload=auto + src,撤掉条件预加载逻辑
  (之前条件预加载导致 switchToSegment 时频繁动态设 src,影响播放和进度)
2026-08-22 02:37:46 +08:00
xiaoxia b8a349d5e0 refactor: 默认使用原生video播放,彻底解决主线程解码卡顿
CI/CD Pipeline / Check if frontend-only change (push) 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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 49s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 56s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 3m5s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 3m22s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 3m27s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 3m29s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 3m44s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 50s
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 34s
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m45s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 4m34s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 6m42s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 4m18s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m25s
AI Code Review / AI Code Review (pull_request) Successful in 8m47s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 53s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 58s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 11m3s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 11m20s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m10s
CI/CD Pipeline / Unit Tests (push) Successful in 15m5s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Integration Tests (push) Successful in 6m45s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 14m24s
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Successful in 6m53s
CI/CD Pipeline / CI Gate (pull_request) Successful in 9s
FrontendPreviewPlayer.tsx:
- useWebCodecs 默认 false,走浏览器原生硬件解码(独立线程)
- 删除 Canvas ResizeObserver useEffect(默认路径不需要)
- video 元素只预加载当前+下一片段,其余 preload=none+不设src,减少并发连接
- 片段指示器统一显示片段序号,不再显示Canvas/降级提示
- isWebCodecsSupported 不再导入,清理 TS6133

useSegmentScheduler.ts:
- tick 进度更新 200ms 节流(5fps),避免 60fps setCurrentTime 触发整树 re-render
- 重播/seek 时重置节流 ref
- switchToSegment 兜底:若 video 无 src 则动态设置并 load(),兼容 seek 到未预加载片段

useCanvasPlayer.ts 不删,保留作为兜底
2026-08-22 01:53:43 +08:00
xiaoxia 9c02e69ede fix: 第13轮 — 背压阈值20→64+移除idleTicks超时+等待10ms→5ms
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m2s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m23s
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 2m50s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m46s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m51s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 3m29s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 3m48s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 37s
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
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 35s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 4m11s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m51s
AI Code Review / AI Code Review (pull_request) Failing after 5m41s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 7m40s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 7m41s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 57s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 9m41s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 59s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 59s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 10m51s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m9s
CI/CD Pipeline / Unit Tests (push) Successful in 14m38s
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Integration Tests (push) Successful in 5m7s
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Successful in 5m3s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 13m11s
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (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 / CI Gate (pull_request) Successful in 10s
- 背压阈值从20提到64,给硬件解码器足够流水线深度
- 等待间隔10ms→5ms,减少轮询开销
- 删除idleTicks 3秒超时,帧队列容量(180)才是真正背压
- 保留帧输出等待(500ms)和完成日志
2026-08-22 01:09:59 +08:00
xiaoxia ece1f25f71 fix: 第12轮 — 背压超时保护+帧输出等待+feedFrames阈值
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m19s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m25s
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 1m55s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 2m11s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m24s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 2m29s
CI/CD Pipeline / Build Staging API Image (push) Successful in 3m49s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 30s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m5s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 39s
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E 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 3m32s
AI Code Review / AI Code Review (pull_request) Failing after 5m11s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 6m51s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 6m55s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 59s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 8m47s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 1m0s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 59s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 9m59s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m12s
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / PR Build API Image (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
- 背压等待加 idleTicks 计数,超3秒自动break防止死循环
- 解码完成后等待帧输出(最多500ms),确保队列有帧
- 加解码完成日志便于排查
- renderFrame 中 feedFrames 调用加 size<80 阈值保护
2026-08-22 00:57:38 +08:00
xiaoxia 2885ede533 fix: 第11轮 — 解码流水线批量提交+背压+移除每帧log
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m16s
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m20s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m26s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 2m36s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m51s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 3m4s
CI/CD Pipeline / Build Staging API Image (push) Successful in 3m27s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 36s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
PR Automation / Auto Approve on CI Green (pull_request) Successful in 4m43s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 44s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m3s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 6m53s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 8m17s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 8m28s
AI Code Review / AI Code Review (pull_request) Successful in 9m6s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 9m15s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 58s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m11s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 1m11s
CI/CD Pipeline / Integration Tests (push) Successful in 3m16s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m27s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 3m36s
CI/CD Pipeline / Unit Tests (push) Successful in 13m41s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 12m50s
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
- decodeSegmentBatch: 移除每帧 await+3s超时,改为批量提交 decode()
- 添加 decodeQueueSize>20 背压,防止解码器内部队列积压
- 批量提交后 16ms 等待让解码器输出帧
- feedFrames 缓冲阈值 100→80,减少后台解码抢占渲染
- 删除 drawTitle 每帧 console.log(JSON.stringify 开销导致抖动)
2026-08-22 00:15:27 +08:00
xiaoxia ac31c88c96 fix: 修复 TS2367 类型收窄错误 — decoder.state 显式断言为 string
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m3s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m17s
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 2m58s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m54s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 3m4s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 3m0s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 3m44s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 48s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 37s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m3s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 4m41s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 6m50s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 7m25s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 56s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 9m3s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 9m9s
AI Code Review / AI Code Review (pull_request) Failing after 8m20s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m4s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 1m6s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m24s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 3m42s
CI/CD Pipeline / Integration Tests (push) Successful in 3m39s
CI/CD Pipeline / Unit Tests (push) Successful in 14m24s
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 12m11s
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 7s
2026-08-21 23:43:15 +08:00
xiaoxia 585a3b6887 fix: 第10轮方案A — 滑动窗口+持久解码器+二分查找
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m2s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m16s
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 1m59s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m6s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 2m40s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 3m6s
CI/CD Pipeline / Build Staging API Image (push) Successful in 3m40s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 39s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Failing after 2m37s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 35s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 4m13s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 6m31s
CI/CD Pipeline / Build Staging Web Image (push) Failing after 7m21s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been skipped
CI/CD Pipeline / Staging E2E Tests (push) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (push) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (push) Has been skipped
AI Code Review / AI Code Review (pull_request) Successful in 7m47s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 8m58s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 9m17s
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
架构级重构,从根本解决抖动/卡顿/黑屏/重播失效/关键帧错误:

- FrameQueue 默认容量 200,getCurrentFrame 改二分查找 O(log n)
- 每个片段持有持久化 VideoDecoder,连续喂 sample 不报关键帧错误
- segmentSampleCursorRef 记录游标,支持断点续解码
- feedFrames 后台补充:队列低于 100 帧自动续解,保持 ≥6s 缓冲
- init 只解前 2 个片段各 60 帧,播放中后台补充
- 重播/seek:关闭旧解码器→清空队列→重置游标→重新解码
- isFeedingRef 防重入
2026-08-21 23:31:44 +08:00
xiaoxia 412aa83b32 fix: 第9轮最终简化方案 — init全量解码+播放时只渲染
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m21s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m27s
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 3m5s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 3m8s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 3m14s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 3m17s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 3m22s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 53s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 1m0s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
AI Code Review / AI Code Review (pull_request) Failing after 3m45s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 4m33s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m6s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 6m36s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 7m13s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 57s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m1s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 1m2s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 9m51s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 10m10s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m18s
CI/CD Pipeline / Unit Tests (push) Successful in 14m31s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Integration Tests (push) Successful in 5m2s
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Successful in 4m48s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 12m14s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 7s
根因:之前 init 只解 60 帧,播放中续解码导致关键帧错误、
重复帧、队列混乱、抖动。

新方案:
- init 阶段一次性解码全部 894 帧(队列 1024 足够容纳)
- 播放时只做 drawImage,不触发任何解码
- 重播直接复用已有帧,不重新解码
- seek 直接定位,不清帧队列
- 删除 decodeAroundPosition 动态解码函数
2026-08-21 22:16:22 +08:00
xiaoxia c6eeca75fb fix: 删除 decodeSegment 的 startFrame 参数,修复关键帧错误
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 50s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m1s
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m20s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 2m45s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m56s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 3m20s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 3m31s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 42s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 34s
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
AI Code Review / AI Code Review (pull_request) Successful in 3m34s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 4m20s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m32s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 8m11s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 8m9s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 59s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 10m3s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 1m1s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m1s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 10m25s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m15s
CI/CD Pipeline / Unit Tests (push) Successful in 14m50s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Integration Tests (push) Successful in 4m51s
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Successful in 4m49s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 13m22s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 7s
WebCodecs 解码器要求第一个 chunk 必须是关键帧。续解码从 startFrame=60
开始时,samplesCollected[60] 不是关键帧 → 报错 "A key frame is required"。

修复:
- 删除 startFrame 参数,sample 循环永远从 0 开始
- decodeAroundPosition 不再传 startFrame
- totalDecoded 计算不再使用 startFrame 偏移
2026-08-21 21:25:19 +08:00
xiaoxia df4de37f73 fix: MAX_INIT_FRAMES 500 → 60,减少 init 阶段解码帧数降低播放抖动
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m1s
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m19s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 3m25s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 3m27s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 3m25s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 3m38s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 3m44s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 42s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 57s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m48s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m59s
AI Code Review / AI Code Review (pull_request) Failing after 5m11s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 6m30s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 7m13s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m2s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 59s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 59s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 10m4s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m14s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 13m24s
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
init 阶段解码 894 帧导致 getCurrentFrame 遍历过多帧,播放抖动。
改为每片段只解 60 帧(≈2s),播放时由 decodeAroundPosition 按需续解。
2026-08-21 21:11:08 +08:00
xiaoxia 88c07ef142 fix: 视频 fallback 路径片段切换卡顿 — 预加载策略升级
CI/CD Pipeline / Check if frontend-only change (push) 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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m6s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m46s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m29s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m31s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 3m23s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 3m26s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 3m46s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
AI Code Review / AI Code Review (pull_request) Successful in 2m57s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 38s
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
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 38s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 4m4s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 4m9s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 7m26s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 7m24s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m45s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 47s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 52s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m4s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 13m59s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 14m29s
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
根因:UseWebCodecs=false 时走原生 video fallback,preload 策略为
当前片段 auto / 下一片段 metadata / 其余 none,导致切换时下一片段
需现场从网络缓冲,卡顿约 10 秒。

修复:
1. 所有 video 元素 preload="auto",让浏览器提前缓冲全部片段
2. tick 循环中距出点 ≤3s 时主动 seek 下一片段触发缓冲
3. switchToSegment 超时从 10s 降到 3s(预加载正常时无需久等)
2026-08-21 20:55:36 +08:00
xiaoxia 0996ba45ec fix: 续解码架构 + 帧队列扩容 1024 + 重播/seek/destroy 同步帧计数
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m0s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m15s
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m39s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m39s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 3m10s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 3m10s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 37s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 3m58s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
AI Code Review / AI Code Review (pull_request) Failing after 3m1s
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 39s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 4m1s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m10s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 6m47s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 7m17s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 55s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m4s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 9m20s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 1m5s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 11m15s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m16s
CI/CD Pipeline / Unit Tests (push) Successful in 13m46s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Integration Tests (push) Successful in 4m57s
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 12m2s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Successful in 4m6s
CI/CD Pipeline / CI Gate (pull_request) Successful in 11s
2026-08-21 20:30:45 +08:00
xiaoxia a34639975c fix: 增大 init 解码上限 + 重播不清帧队列 + sample 循环 generation 检查
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 57s
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m7s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 2m46s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 3m21s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 3m13s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 3m30s
CI/CD Pipeline / Build Staging API Image (push) Successful in 3m46s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 38s
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
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 39s
AI Code Review / AI Code Review (pull_request) Failing after 3m28s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 4m9s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m16s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 6m39s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 7m14s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m0s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 57s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 58s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 9m50s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 10m3s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m14s
CI/CD Pipeline / Unit Tests (push) Successful in 14m33s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Integration Tests (push) Successful in 5m4s
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Successful in 4m52s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 12m10s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 8s
2026-08-21 19:58:40 +08:00
xiaoxia 4b68c9be9c fix: 给 decoder.decode() 加 3s 超时保护,防止解码卡死
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m23s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m43s
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m39s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 2m41s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m46s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 3m1s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 3m50s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 34s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
AI Code Review / AI Code Review (pull_request) Failing after 3m31s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 35s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m39s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 4m6s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 7m41s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 7m42s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 8m36s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 57s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 1m6s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m7s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 10m6s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m23s
CI/CD Pipeline / Unit Tests (push) Successful in 13m51s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 11m49s
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 / Integration Tests (pull_request) Successful in 6m10s
CI/CD Pipeline / CI Gate (pull_request) Successful in 10s
CI/CD Pipeline / Integration Tests (push) Successful in 5m50s
CI/CD Pipeline / CI Gate (push) Has been skipped
2026-08-21 19:09:39 +08:00
xiaoxia fbe0a6e826 fix: 视频播放结束后重播时重置 currentTime 到起点
CI/CD Pipeline / Check if frontend-only change (push) 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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1m13s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m16s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 3m31s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 3m42s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 3m46s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 3m48s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 4m12s
AI Code Review / AI Code Review (pull_request) Failing after 3m28s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m3s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 1m7s
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 4m32s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m53s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 7m55s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 7m52s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m5s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 57s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 59s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 10m21s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 11m14s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m10s
CI/CD Pipeline / Unit Tests (push) Successful in 15m21s
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Integration Tests (push) Successful in 5m50s
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 13m2s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Successful in 5m44s
CI/CD Pipeline / CI Gate (pull_request) Successful in 8s
2026-08-21 17:18:35 +08:00
xiaoxia 7f2861e98e fix: 移除 decoder.flush() 调用,修复 Chromium 下 flush 永久挂起导致解码卡死
CI/CD Pipeline / Check if frontend-only change (push) 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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 50s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m9s
CI/CD Pipeline / Build Staging API Image (push) Successful in 1m57s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 1m43s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 3m25s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 3m26s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
AI Code Review / AI Code Review (pull_request) Failing after 3m33s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 3m59s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 4m2s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 38s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m53s
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
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 38s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 6m52s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 5m27s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m8s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 55s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 56s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 10m15s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 10m55s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m8s
CI/CD Pipeline / Unit Tests (push) Successful in 14m28s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Integration Tests (push) Successful in 5m44s
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 13m13s
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 / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Successful in 5m47s
CI/CD Pipeline / CI Gate (pull_request) Successful in 6s
2026-08-21 16:57:20 +08:00
xiaoxia b1aa866252 fix: 修复 flush 超时 catch 块类型错误导致 CI 构建失败
CI/CD Pipeline / Check if frontend-only change (push) 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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 59s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m11s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 3m14s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Validate - Code Quality (push) Has been cancelled
CI/CD Pipeline / Validate - Migration (alembic) (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (push) Has been cancelled
CI/CD Pipeline / Build Staging API Image (push) Has been cancelled
CI/CD Pipeline / Build Staging Web Image (push) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (push) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Validate - Code Quality (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Frontend Lint (pull_request) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / PR Build API Image (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Web Image (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
AI Code Review / AI Code Review (pull_request) Has been cancelled
PR Automation / Auto Approve on CI Green (pull_request) Has been cancelled
Preview Deploy / Deploy Preview Environment (pull_request) Has been cancelled
2026-08-21 16:53:53 +08:00
xiaoxia f484de79c4 ci: trigger web build 1787302071
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m3s
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
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 2m39s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (push) Failing after 2m37s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 3m41s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 3m53s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 3m58s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 4m0s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m27s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 47s
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Failing after 2m1s
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 47s
CI/CD Pipeline / Staging API Integration Tests (push) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (push) Has been skipped
AI Code Review / AI Code Review (pull_request) Failing after 4m30s
CI/CD Pipeline / Validate - Code Quality (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Validate - Code Quality (pull_request) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
2026-08-21 16:47:51 +08:00
xiaoxia 9263db56db ci: retry build
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 57s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m13s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 2m53s
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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 3m53s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 4m24s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 4m4s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 5m24s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
AI Code Review / AI Code Review (pull_request) Successful in 2m26s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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 / Validate - Type Check (mypy) (pull_request) Successful in 4m34s
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Validate - Code Quality (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Staging Web Image (push) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (push) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Validate - Code Quality (pull_request) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / PR Build API Image (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
Preview Deploy / Deploy Preview Environment (pull_request) Failing after 1m46s
PR Automation / Auto Approve on CI Green (pull_request) Has been cancelled
2026-08-21 16:41:53 +08:00
xiaoxia ebe43f163b chore: DIAG_v2 诊断日志 + flush 5s 超时保护
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 36s
CI/CD Pipeline / Build Staging API Image (push) Successful in 1m33s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m40s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m39s
AI Code Review / AI Code Review (pull_request) Failing after 2m20s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 2m56s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 3m4s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m2s
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 / Build Staging Worker Image (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Failing after 1m11s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 37s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 36s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m21s
CI/CD Pipeline / Build Staging Web Image (push) Failing after 4m51s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been skipped
CI/CD Pipeline / Staging E2E Tests (push) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (push) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (push) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 4m34s
CI/CD Pipeline / Validate - Code Quality (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Validate - Code Quality (pull_request) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
2026-08-21 16:30:59 +08:00
xiaoxia 3e38395f46 chore: 添加 [DIAG] 诊断日志定位 decode loop 卡死点
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 44s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m34s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) 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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 3m30s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
AI Code Review / AI Code Review (pull_request) Successful in 2m52s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 3m43s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 3m56s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 4m6s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 4m3s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 38s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 41s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 4m2s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m1s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 7m58s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 8m21s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m10s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 48s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 36s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m2s
CI/CD Pipeline / Unit Tests (pull_request) Failing after 18m29s
CI/CD Pipeline / Validate - Code Quality (pull_request) Failing after 22m3s
CI/CD Pipeline / Unit Tests (push) Failing after 22m9s
CI/CD Pipeline / Validate - Code Quality (push) Failing after 22m10s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) 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 / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Successful in 7m39s
CI/CD Pipeline / Integration Tests (push) Successful in 7m41s
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Failing after 10s
2026-08-21 15:43:16 +08:00
xiaoxia 9cb20c38ae fix: Strict Mode 双执行导致 decode loop 提前退出
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 41s
CI/CD Pipeline / Build Staging API Image (push) Successful in 2m4s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 3m12s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 3m43s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 4m10s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m12s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m3s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 1m20s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 7m25s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m31s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 10m28s
CI/CD Pipeline / Unit Tests (push) Successful in 15m9s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
React 18 Strict Mode 下 effect 执行两次(run → cleanup → run),
destroy() 和 init() 都调用 decodeGenerationRef.current++ 导致
generation 被多增两次,decode loop 内 generation check 误判为
seek/destroy 事件而提前退出。

修复:
- destroy() 移除 decodeGenerationRef.current++
- init() 移除 decodeGenerationRef.current++
- seek()/play() 保留 generation 递增不变
- decoder.state === 'closed' 时 return 而非 break,让第二轮
  init 重新创建 decoder 正常解码
2026-08-21 15:27:42 +08:00
xiaoxia d784af7f67 fix: 重置 isDestroyedRef 修复 effect 生命周期导致解码永久跳过
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 59s
CI/CD Pipeline / Build Staging API Image (push) Successful in 2m44s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m49s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 3m27s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 5m58s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 6m2s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m3s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 54s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 54s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m10s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 10m38s
CI/CD Pipeline / Unit Tests (push) Successful in 13m55s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Integration Tests (push) Successful in 9m17s
CI/CD Pipeline / CI Gate (push) Has been skipped
useEffect cleanup 调用 destroy() 将 isDestroyedRef 设为 true,
但新的 init 周期不重置它,导致 loadSegment/decodeSegment 立即 return,
isReady 永远为 false → canPlay 为 false → '暂无可播放素材'

修复:
- init 开始时重置 isDestroyedRef = false + 递增 decodeGeneration
- 同步重置 hasDecodeError/errorMessage/isReady 状态
- decode 循环内每次迭代后增加 cancelled 检查
- 增加诊断日志(decode loop 前后 + cancelled 分支)
2026-08-21 15:01:17 +08:00
xiaoxia 1b6ecc39f0 fix: WebCodecs 解码失败时自动 fallback 到原生 video 播放
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m21s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m37s
CI/CD Pipeline / Build Staging API Image (push) Successful in 2m52s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 2m57s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 6m1s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 6m2s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m2s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 56s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 58s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 9m6s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m10s
CI/CD Pipeline / Unit Tests (push) Successful in 13m30s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Integration Tests (push) Successful in 5m7s
CI/CD Pipeline / CI Gate (push) Has been skipped
- useCanvasPlayer 新增 hasDecodeError/errorMessage 状态和 onError 回调
- decodeSegment catch 块不再静默失败,更新状态并通知上层
- VideoDecoder error 回调同步报告错误状态
- 连续 3 次解码失败时报告 hasDecodeError
- FrontendPreviewPlayer 检测 hasDecodeError 后自动切换 video fallback
- 解码失败时显示具体错误信息而非静默'暂无可播放素材'
- 新增 normalizeCodecString 函数规范化 codec 字符串
- configure 调用增加 codec 字符码调试日志
2026-08-21 14:43:12 +08:00
163 changed files with 30150 additions and 8844 deletions
@@ -0,0 +1,26 @@
"""Add title_config to generation_tasks
Revision ID: 057_title_config
Revises: 056_fix_cover_templates_config
Create Date: 2026-08-23
"""
import sqlalchemy as sa
from alembic import op
revision = "057_title_config"
down_revision = "056_fix_cover_templates_config"
branch_labels = None
depends_on = None
def upgrade() -> None:
op.add_column(
"generation_tasks",
sa.Column("title_config", sa.JSON(), nullable=False, server_default="{}"),
)
def downgrade() -> None:
op.drop_column("generation_tasks", "title_config")
+224 -39
View File
@@ -31,8 +31,6 @@ logger = logging.getLogger(__name__)
router = APIRouter(tags=["Generation"])
# ── Schemas ──────────────────────────────────────────────────────────────
@@ -65,6 +63,83 @@ class GenerateCoverResponse(BaseModel):
# ── Route ────────────────────────────────────────────────────────────────
def _persist_cover_frame(
frame_url: str,
plan_id: str,
title_text: str = "",
*,
title_color: str = "#ffffff",
title_position: str = "bottom",
title_font_size: int | None = None,
) -> str:
"""下载 MediaKit 返回的临时帧图,可选叠加标题后转存到 OSS covers/ 路径。
Args:
frame_url: MediaKit 返回的临时帧图 URL
plan_id: 剪辑计划 ID(生成 OSS key
title_text: 非空时用 Pillow 在帧上叠加标题(用于 E2 从源素材抽帧,
因为源素材本身没有烧录标题)
title_color: 标题字体颜色(#RRGGBB
title_position: 标题位置 top/center/bottom
title_font_size: 标题字号,None 时自动计算
"""
import tempfile
import uuid
from pathlib import Path
tmp_path: str | None = None
try:
import httpx
resp = httpx.get(frame_url, timeout=30, follow_redirects=True)
resp.raise_for_status()
if not resp.content:
return frame_url
with tempfile.NamedTemporaryFile(suffix=".jpg", delete=False) as tmp:
tmp.write(resp.content)
tmp_path = tmp.name
# E2 从源素材抽帧时,源素材无标题,叠加标题文字
if title_text and title_text.strip():
try:
from packages.shared.title_overlay import apply_title_to_image
applied = apply_title_to_image(
tmp_path,
title_text,
color=title_color,
position=title_position,
font_size=title_font_size,
)
if applied:
logger.info("[封面生成] E2 帧图已叠加标题: plan_id=%s", plan_id)
except Exception:
logger.warning(
"[封面生成] E2 标题叠加失败(返回无标题帧): plan_id=%s",
plan_id,
exc_info=True,
)
from packages.shared.storage import get_shared_storage_service
storage = get_shared_storage_service()
cover_key = f"covers/{plan_id}/cover_{uuid.uuid4().hex[:8]}.jpg"
storage.upload_file(
file_or_path=tmp_path,
storage_key=cover_key,
content_type="image/jpeg",
)
public_url = storage.get_url(cover_key)
return public_url or frame_url
except Exception:
logger.warning("封面帧转存失败,返回原始 URL: plan_id=%s", plan_id, exc_info=True)
return frame_url
finally:
if tmp_path:
Path(tmp_path).unlink(missing_ok=True)
@router.post("/generate-cover", response_model=GenerateCoverResponse)
def generate_cover(
body: GenerateCoverRequest,
@@ -198,44 +273,31 @@ def generate_cover(
exc_info=True,
)
# 仍然找不到才报 400
if not rendered_storage_key:
logger.error("[封面生成] ❌ 找不到预览视频: plan_id=%s", plan_id)
raise HTTPException(
status_code=400,
detail="请先生成预览视频,再生成封面",
)
# 回写到 plan.config
plan_svc.update_plan_config(plan_id, {"rendered_storage_key": rendered_storage_key})
# 使用裸 URLrendered/* 已配置公开读)
# 使用裸 URLrendered/* 已配置公开读);找不到渲染视频时不立即报错,
# 因为步骤 E 可以直接从源素材抽帧(历史数据或 Worker 抽帧失败时的兜底)
primary_video_url = None
try:
if rendered_storage_key.startswith("http"):
primary_video_url = rendered_storage_key
else:
from packages.shared.storage import get_shared_storage_service
if rendered_storage_key:
plan_svc.update_plan_config(plan_id, {"rendered_storage_key": rendered_storage_key})
try:
if rendered_storage_key.startswith("http"):
primary_video_url = rendered_storage_key
else:
from packages.shared.storage import get_shared_storage_service
storage_svc = get_shared_storage_service()
primary_video_url = storage_svc.get_url(rendered_storage_key)
# 防御性规范化:合并路径中的双斜杠(// -> /),但保留协议头的 ://
# 历史数据中 project_id 为空时会产生 projects//tasks/ 路径,
# MediaKit 的 HTTP 客户端会规范化 URL 导致 404
if primary_video_url:
import re as _re
storage_svc = get_shared_storage_service()
primary_video_url = storage_svc.get_url(rendered_storage_key)
if primary_video_url:
import re as _re
primary_video_url = _re.sub(r"(?<!:)//", "/", primary_video_url)
logger.info(
"获取预览视频URL用于封面生成: plan_id=%s url=%s",
plan_id,
primary_video_url[:80] if primary_video_url else "",
)
except Exception as e:
raise HTTPException(
status_code=500,
detail=f"获取预览视频URL失败: {e}",
) from e
primary_video_url = _re.sub(r"(?<!:)//", "/", primary_video_url)
logger.info(
"获取预览视频URL用于封面生成: plan_id=%s url=%s",
plan_id,
primary_video_url[:80] if primary_video_url else "",
)
except Exception as e:
logger.warning("获取预览视频URL失败: plan_id=%s err=%s", plan_id, e)
primary_video_url = None
# 统一封面管道:优先从 GenerationTask.cover_url 读取渲染后视频抽帧的封面
# 多步查找 cover_url,和查找视频 URL 一样的 fallback 逻辑
@@ -310,6 +372,129 @@ def generate_cover(
exc_info=True,
)
# 步骤 D:从 plan.config.cover_candidates 读取(Worker 渲染时写入)
if not cover_url_from_task:
_candidates = (plan.config or {}).get("cover_candidates") or []
if isinstance(_candidates, list) and _candidates:
_first = _candidates[0]
if isinstance(_first, dict):
cover_url_from_task = _first.get("image_url") or _first.get("url") or ""
if cover_url_from_task:
logger.info(
"[封面生成] 统一管道封面(步骤D-cover_candidates): plan_id=%s url=%s",
plan_id,
cover_url_from_task[:80],
)
# 步骤 E1:如果有已渲染的预览视频 URL 但 cover_url 未持久化(历史数据),
# 直接从渲染视频抽帧
if not cover_url_from_task and primary_video_url:
try:
from packages.shared.mediakit_client import get_mediakit_client
mk_client = get_mediakit_client()
if mk_client.is_available:
logger.info(
"[封面生成] 步骤E1-从渲染视频抽帧: plan_id=%s url=%s",
plan_id,
primary_video_url[:80],
)
snapshots = mk_client.extract_frames(
video_url=primary_video_url,
strategy="SpecifiedFrames",
max_frames=1,
poll_interval=2.0,
max_poll_attempts=5,
max_retries=0,
)
if snapshots:
raw = snapshots[0].get("image_url") or snapshots[0].get("url") or ""
if raw:
cover_url_from_task = _persist_cover_frame(raw, plan_id)
logger.info(
"[封面生成] 统一管道封面(步骤E1-rendered-video): plan_id=%s url=%s",
plan_id,
cover_url_from_task[:80],
)
except Exception:
logger.warning(
"[封面生成] 步骤E1从渲染视频抽帧失败: plan_id=%s",
plan_id,
exc_info=True,
)
# 步骤 E2:当 A/B/C/D/E1 均未命中(如历史预览任务无 cover_url)时,
# 直接从用户选择的第一个视频素材中抽取封面帧作为兜底。API 请求内短超时,不阻塞。
if not cover_url_from_task and body.asset_ids:
from packages.adapters.sqlalchemy_impl.asset_repository import (
SQLAlchemyAssetRepository,
)
from packages.shared.mediakit_client import get_mediakit_client
from packages.shared.storage import get_shared_storage_service
asset_repo = SQLAlchemyAssetRepository(db)
storage_svc = get_shared_storage_service()
mk_client = get_mediakit_client()
# 从 plan.config 读取完整标题样式,E2 从源素材抽帧时叠加(源素材本身无标题)
_e2_title_cfg = (plan.config or {}).get("title", {}) or {}
if not isinstance(_e2_title_cfg, dict):
_e2_title_cfg = {}
_e2_title_text = (_e2_title_cfg.get("text", "") or "").strip() if _e2_title_cfg.get("enabled", True) else ""
# 读取标题样式:前端可能传 color 或 font_color,都兼容
_e2_title_color = _e2_title_cfg.get("color") or _e2_title_cfg.get("font_color") or "#ffffff"
_e2_title_position = _e2_title_cfg.get("position", "bottom") or "bottom"
_e2_title_font_size = _e2_title_cfg.get("font_size") or _e2_title_cfg.get("size")
if mk_client.is_available:
for aid in body.asset_ids:
try:
asset = asset_repo.get(aid)
if not asset or asset.file_type != "video":
continue
sk = asset.storage_key or ""
if not sk:
continue
src_url = sk if sk.startswith("http") else storage_svc.get_url(sk)
if not src_url:
continue
logger.info(
"[封面生成] 步骤E-从素材抽帧: plan_id=%s asset_id=%s url=%s",
plan_id,
aid,
src_url[:80],
)
snapshots = mk_client.extract_frames(
video_url=src_url,
strategy="SpecifiedFrames",
max_frames=1,
poll_interval=2.0,
max_poll_attempts=5,
max_retries=0,
)
if snapshots:
raw = snapshots[0].get("image_url") or snapshots[0].get("url") or ""
if raw:
cover_url_from_task = _persist_cover_frame(
raw,
plan_id,
title_text=_e2_title_text,
title_color=_e2_title_color,
title_position=_e2_title_position,
title_font_size=_e2_title_font_size,
)
logger.info(
"[封面生成] 统一管道封面(步骤E-source-asset): plan_id=%s url=%s",
plan_id,
cover_url_from_task[:80],
)
break
except Exception:
logger.warning(
"[封面生成] 步骤E从素材抽帧失败: plan_id=%s asset_id=%s",
plan_id,
aid,
exc_info=True,
)
if cover_url_from_task:
# 标题已在预览视频渲染时烧录(ASS字幕),封面帧自然包含标题
cover_data = {
@@ -325,13 +510,13 @@ def generate_cover(
return GenerateCoverResponse(plan_id=plan_id, cover=cover_data)
logger.warning(
"[封面生成] 统一管道未找到 cover_url: plan_id=%s",
"[封面生成] 统一管道未找到 cover_url (A/B/C/D均未命中): plan_id=%s",
plan_id,
)
# ai_frame/ai_regenerate 类型必须从渲染管道获取,不再回退到 AI 服务
raise HTTPException(
status_code=400,
detail="封面尚未生成,请先重新生成预览视频以触发封面自动提取",
detail="封面生成失败:未找到可抽帧的视频素材,请确认已上传视频素材后重试",
)
from packages.shared.ai_service import run_generate_cover
+32 -15
View File
@@ -5,7 +5,6 @@
from __future__ import annotations
import json
import logging
from app.auth import AuthenticatedUser, get_current_user
@@ -265,22 +264,38 @@ def create_preview_generation_task(
if not video_ratio and request.template_id:
video_ratio = _infer_video_ratio_from_template(request.template_id, db, user_id)
# 根据 video_ratio 计算输出分辨率(默认竖屏 1080x1920)
output_width, output_height = 1080, 1920
if video_ratio:
parts = video_ratio.split(":")
if len(parts) == 2:
try:
w, h = int(parts[0]), int(parts[1])
base = 1920
if w < h:
# 竖屏
output_width = round(base * w / h)
output_height = base
else:
# 横屏
output_width = base
output_height = round(base * h / w)
# 对齐到偶数
output_width = output_width - output_width % 2
output_height = output_height - output_height % 2
except (ValueError, ZeroDivisionError):
output_width, output_height = 1080, 1920
resolution = f"{output_width}x{output_height}"
logger.info(
"[预览生成] 分辨率: video_ratio=%s%s (%dx%d)",
video_ratio, resolution, output_width, output_height,
)
# 从模板读取 editing_mode / mode 作为 strategy_id(渲染 pipeline 的 mode 参数)
strategy_id = _resolve_strategy_id_from_template(request.template_id, db, user_id)
# 处理标题配置:如果有标题文本,序列化到 custom_title 字段传递给 worker
title_config = request.title_config or {}
title_text = (title_config.get("text") or "").strip()
custom_title_value = ""
if title_text:
# 将标题文本和样式配置序列化为 JSON 存入 custom_title
# Worker 端会解析 JSON 获取完整标题配置
custom_title_value = json.dumps(title_config, ensure_ascii=False)
logger.info(
"[预览生成] 标题配置: text=%s, config_keys=%s",
title_text[:30],
list(title_config.keys()),
)
use_case = CreateGenerationTaskUseCase(generation_task_repository)
@@ -300,12 +315,14 @@ def create_preview_generation_task(
asset_select_mode="",
batch_id="",
video_title=request.video_title,
resolution="",
resolution=resolution,
bgm_config=request.bgm_config or {},
auto_retry_enabled=False,
auto_retry_max=0,
is_preview=True,
custom_title=custom_title_value,
title_config=title_config,
output_width=output_width,
output_height=output_height,
)
)
except ValueError as e:
+211 -5
View File
@@ -16,6 +16,7 @@ from app.core.task_enqueue import (
from app.dependencies import (
get_asset_library_repository,
get_asset_repository,
get_db_session,
get_generated_video_repository,
get_generation_task_repository,
get_project_repository,
@@ -32,6 +33,7 @@ from app.schemas.generation_task import (
ListGenerationTasksResponse,
)
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from packages.application import (
CreateGenerationTaskCommand,
@@ -68,7 +70,7 @@ def _to_generation_task_response(task) -> GenerationTaskResponse:
output_width=getattr(task, "output_width", 1280),
output_height=getattr(task, "output_height", 720),
cover_url=getattr(task, "cover_url", ""),
custom_title=getattr(task, "custom_title", ""),
title_config=getattr(task, "title_config", {}) or {},
logs=getattr(task, "logs", "[]"),
status=task.status,
progress=task.progress,
@@ -142,6 +144,68 @@ def _select_assets_from_library(
return [a.id for a in ready_video_assets]
def _writeback_edit_plan_config(
plan_id: str,
task_id: str,
title_config: dict | None,
db: Session,
) -> None:
"""任务入队成功后,回写 EditPlan.configgeneration_task_id + title_config。
用 merge 方式更新,不整体覆盖 config,避免丢失其他字段。
失败只记日志,不影响任务创建。
"""
if not plan_id:
return
try:
from packages.adapters.sqlalchemy_impl.models import EditPlanModel
plan_model = db.query(EditPlanModel).filter(EditPlanModel.id == plan_id).first()
if plan_model is None:
logger.warning("[生成任务] 回写plan.config失败: plan不存在 plan_id=%s", plan_id)
return
current_config = plan_model.config if isinstance(plan_model.config, dict) else {}
merged = dict(current_config)
merged["generation_task_id"] = task_id
# 检查标题是否发生变化,如果变化则清除 cover 字段强制重新生成封面
if title_config:
old_title_config = merged.get("title_config", {}) or {}
old_title_text = (old_title_config.get("text") or "").strip()
new_title_text = (title_config.get("text") or "").strip()
if old_title_text != new_title_text:
# 标题变化,清除旧封面
if "cover" in merged:
del merged["cover"]
logger.info(
"[生成任务] 标题变化,清除旧封面: plan_id=%s old_title=%s new_title=%s",
plan_id, old_title_text, new_title_text,
)
merged["title_config"] = title_config
plan_model.config = merged
db.commit()
logger.info(
"[生成任务] 回写plan.config成功: plan_id=%s task_id=%s keys=%s",
plan_id,
task_id,
list(merged.keys()),
)
except Exception as e:
logger.warning(
"[生成任务] 回写plan.config异常(不影响任务创建): plan_id=%s error=%s",
plan_id,
e,
exc_info=True,
)
try:
db.rollback()
except Exception:
pass
def _resolve_project_and_library(
request: CreateGenerationTaskRequest,
project_repository: Any,
@@ -187,6 +251,7 @@ def create_generation_task(
project_repository: Any = Depends(get_project_repository),
asset_library_repository: Any = Depends(get_asset_library_repository),
asset_repository: Any = Depends(get_asset_repository),
db: Session = Depends(get_db_session),
) -> BatchGenerationTaskResponse:
logger.info(
"[生成任务] 接收请求: user_id=%s, template_id=%s, asset_count=%d, mode=%s, count=%d",
@@ -242,6 +307,89 @@ def create_generation_task(
detail="当前项目没有符合条件的视频素材,请先上传并等待导入完成后再生成。",
)
# ── 兜底复用预览产物 ──
# 前端刷新后 previewTaskId 丢失,降级调 create 接口时,
# 如果同一 edit_plan 有已完成的预览任务,直接复用(秒出)。
if request.source_edit_plan_id and not request.is_preview:
try:
from packages.adapters.sqlalchemy_impl.models import (
GenerationTaskModel,
)
_preview_model = (
db.query(GenerationTaskModel)
.filter(
GenerationTaskModel.source_edit_plan_id == request.source_edit_plan_id,
GenerationTaskModel.is_preview.is_(True),
GenerationTaskModel.status == "completed",
GenerationTaskModel.created_by_user_id == authenticated_user.user.id,
)
.order_by(GenerationTaskModel.created_at.desc())
.first()
)
if _preview_model is not None:
# 校验分辨率一致性(与 confirm 端点逻辑相同)
req_w = request.output_width or 0
req_h = request.output_height or 0
src_w = getattr(_preview_model, "output_width", 0) or 0
src_h = getattr(_preview_model, "output_height", 0) or 0
resolution_match = (req_w == 0 or req_w == src_w) and (req_h == 0 or req_h == src_h)
if resolution_match:
from packages.adapters.sqlalchemy_impl.generation_task_repository import (
_to_domain,
)
preview_task = _to_domain(_preview_model)
# 如果传了标题,更新 title_config
fallback_title_config = None
if request.title_config and request.title_config.get("text", "").strip():
fallback_title_config = dict(preview_task.title_config or {})
fallback_title_config.update(request.title_config)
preview_task.mark_confirmed(
cover_url=request.cover_url or preview_task.cover_url,
output_width=request.output_width or preview_task.output_width,
output_height=request.output_height or preview_task.output_height,
title_config=fallback_title_config,
)
generation_task_repository.update(preview_task)
# 同步标题到 EditPlan.config
if fallback_title_config:
_writeback_edit_plan_config(
plan_id=request.source_edit_plan_id,
task_id=preview_task.id,
title_config=fallback_title_config,
db=db,
)
logger.info(
"[生成任务] 兜底复用预览产物: preview_task_id=%s, plan_id=%s",
preview_task.id,
request.source_edit_plan_id,
)
return BatchGenerationTaskResponse(
items=[_to_generation_task_response(preview_task)],
total=1,
)
else:
logger.info(
"[生成任务] 兜底复用跳过(分辨率不一致): plan_id=%s, src=%sx%s, req=%sx%s",
request.source_edit_plan_id,
src_w,
src_h,
req_w,
req_h,
)
except Exception:
logger.warning(
"[生成任务] 兜底复用预览产物异常(不影响主流程): plan_id=%s",
request.source_edit_plan_id,
exc_info=True,
)
use_case = CreateGenerationTaskUseCase(generation_task_repository)
count = request.count
created_tasks = []
@@ -303,10 +451,53 @@ def create_generation_task(
output_width=request.output_width,
output_height=request.output_height,
cover_url=request.cover_url,
custom_title=request.custom_title,
title_config=request.title_config or {},
)
)
try:
# 兜底关联编辑计划:前端未传 source_edit_plan_id 时,
# 通过 template_id + user_id 在 DB 层直接查找最新的 plan。
# 必须在 enqueue 之前执行,避免 worker 读取时 source_edit_plan_id 为空(竞态条件)
if not task.source_edit_plan_id and request.template_id:
try:
from packages.adapters.sqlalchemy_impl.models import EditPlanModel
_plan_model = (
db.query(EditPlanModel)
.filter(
EditPlanModel.template_id == request.template_id,
EditPlanModel.created_by_user_id == user_id,
)
.order_by(EditPlanModel.created_at.desc())
.first()
)
if _plan_model:
task.source_edit_plan_id = _plan_model.id
generation_task_repository.update(task)
logger.info(
"[生成任务] 自动关联编辑计划: task_id=%s plan_id=%s",
task.id,
_plan_model.id,
)
except Exception:
logger.warning(
"[生成任务] 查找关联编辑计划失败(不影响主流程): task_id=%s",
task.id,
exc_info=True,
)
# 回写 plan.config:必须在 enqueue 之前执行,
# 确保 worker 读取 plan 时 config 中已包含 generation_task_id。
# 只在首个任务时回写一次,避免批量生成时循环覆盖。
_effective_plan_id = task.source_edit_plan_id
if _effective_plan_id and len(created_tasks) == 0:
_writeback_edit_plan_config(
plan_id=_effective_plan_id,
task_id=task.id,
title_config=request.title_config,
db=db,
)
if safe_enqueue_generation_task(
task,
generation_task_repository,
@@ -351,6 +542,7 @@ def confirm_generation(
authenticated_user: AuthenticatedUser = Depends(get_current_user),
generation_task_repository: Any = Depends(get_generation_task_repository),
project_repository: Any = Depends(get_project_repository),
db: Session = Depends(get_db_session),
) -> BatchGenerationTaskResponse:
"""确认生成 -- 复用预览渲染产物(预览与正式品质一致)。
@@ -379,13 +571,29 @@ def confirm_generation(
resolution_match = (req_w == 0 or req_w == src_w) and (req_h == 0 or req_h == src_h)
if resolution_match:
# 如果用户传了 custom_title,同步更新 title_config
confirmed_title_config = None
if request.custom_title and request.custom_title.strip():
confirmed_title_config = dict(getattr(source_task, "title_config", {}) or {})
confirmed_title_config["text"] = request.custom_title.strip()
source_task.mark_confirmed(
cover_url=request.cover_url,
custom_title=request.custom_title,
output_width=request.output_width,
output_height=request.output_height,
title_config=confirmed_title_config,
)
generation_task_repository.update(source_task)
# 同步标题到 EditPlan.config
if confirmed_title_config and source_task.source_edit_plan_id:
_writeback_edit_plan_config(
plan_id=source_task.source_edit_plan_id,
task_id=source_task.id,
title_config=confirmed_title_config,
db=db,
)
logger.info(
"[确认生成] 复用预览产物: task_id=%s, user_id=%s",
task_id,
@@ -427,7 +635,6 @@ def confirm_generation(
output_width=request.output_width,
output_height=request.output_height,
cover_url=request.cover_url,
custom_title=request.custom_title,
)
)
@@ -560,7 +767,6 @@ def retry_generation_task(
output_width=getattr(task, "output_width", 1280),
output_height=getattr(task, "output_height", 720),
cover_url=getattr(task, "cover_url", ""),
custom_title=getattr(task, "custom_title", ""),
)
)
try:
@@ -1,10 +1,9 @@
"""模板编辑器 API 路由包.
将原来 2560 行的 templates_editor.py 巨无霸拆分为 12 个模块:
模块拆分
- schemas.py: 所有 Pydantic model
- dependencies.py: 依赖注入
- _utils.py: 工具函数
- _fallback.py: 自动兜底逻辑
- draft.py: 草稿管理(详情/更新/发布/版本/回滚)
- clips.py: 片段管理(CRUD/分割/合并/重排/批量删除/从素材创建)
- adjustments.py: 片段调整(速度/音量/裁剪/批量调速)
@@ -13,7 +12,6 @@
- export.py: 导出配置
- subtitles.py: 字幕管理
- ai_features.py: AI 推荐
- generation.py: 生成(触发/进度/记录)
- timeline.py: 时间线
挂载路径: /api/v1/templates/{template_id}/editor/
@@ -34,7 +32,6 @@ from .dependencies import get_draft_plan_id, get_editor_services # noqa: F401
from .draft import router as draft_router
from .effects import router as effects_router
from .export import router as export_router
from .generation import router as generation_router
from .subtitles import router as subtitles_router
from .timeline import router as timeline_router
@@ -51,7 +48,6 @@ _sub_routers = [
export_router,
subtitles_router,
ai_features_router,
generation_router,
timeline_router,
]
@@ -1,227 +0,0 @@
"""模板编辑器自动兜底逻辑.
generate_editor_draft 触发生成前的自动修复流程:
1. draft → editing 状态迁移
2. 无片段时从模板复制片段配置
3. 为无素材片段分配指定素材
4. 项目有素材库时自动选素材
"""
from __future__ import annotations
import logging
import random
from typing import Any
from app.services.edit_plan_service import EditPlanService
from sqlalchemy.orm import Session
from packages.adapters.sqlalchemy_impl.template_clip_config_repository import (
SQLAlchemyTemplateClipConfigRepository,
)
from packages.adapters.sqlalchemy_impl.template_repository import (
SQLAlchemyTemplateRepository,
)
from packages.domain.edit_plan import EditPlanStatus
logger = logging.getLogger(__name__)
def _auto_fallback_draft_to_editing(svc: EditPlanService, plan_id: str, plan_check) -> None:
"""自动兜底 1: draft → editing"""
if plan_check.status == EditPlanStatus.DRAFT:
logger.info("模板编辑器自动兜底: plan=%s draft→editing", plan_id)
svc.transition_status(plan_id, EditPlanStatus.EDITING)
def _auto_fallback_copy_template_clips(svc: EditPlanService, plan_id: str, plan_check, db: Session) -> None:
"""自动兜底 2: 无片段 + 有 template_id → 从模板复制片段配置"""
existing_clips = svc.count_clips(plan_id)
if existing_clips == 0 and plan_check.template_id:
logger.info(
"模板编辑器自动兜底: plan=%s 无片段,从模板 %s 复制片段配置",
plan_id,
plan_check.template_id,
)
clip_config_repo = SQLAlchemyTemplateClipConfigRepository(db)
configs = clip_config_repo.list_by_template(plan_check.template_id)
if configs:
for cfg in configs:
svc.create_clip(
plan_id=plan_id,
clip_type=cfg.clip_type.value if hasattr(cfg.clip_type, "value") else cfg.clip_type,
order=cfg.order,
template_clip_config_id=cfg.id,
duration=cfg.default_duration,
transition_effect=(
cfg.transition_effect.value
if hasattr(cfg.transition_effect, "value")
else cfg.transition_effect
),
)
logger.info(
"模板编辑器自动兜底: plan=%s 从 template_clip_configs 复制了 %d 个片段",
plan_id,
len(configs),
)
else:
tpl_repo = SQLAlchemyTemplateRepository(db)
segments = tpl_repo.list_segments(plan_check.template_id)
for seg in segments:
avg_duration = (seg.duration_min + seg.duration_max) / 2
svc.create_clip(
plan_id=plan_id,
clip_type="main",
order=seg.segment_order,
duration=avg_duration,
config={
"material_type": seg.material_type or "",
"template_segment_id": seg.id,
},
)
logger.info(
"模板编辑器自动兜底: plan=%s 从旧模板 segments 复制了 %d 个片段",
plan_id,
len(segments),
)
def _auto_fallback_assign_assets(svc: EditPlanService, plan_id: str, plan_check) -> list:
"""自动兜底 3: 为没有素材的片段分配素材。返回剩余无素材片段列表。"""
all_clips = svc.list_clips(plan_id)
clips_without_asset = [c for c in all_clips if not c.asset_id]
config_asset_ids = (plan_check.config or {}).get("asset_ids", [])
logger.info(
"模板编辑器自动兜底3 诊断: plan=%s total_clips=%d " "clips_without_asset=%d config_asset_ids=%r",
plan_id,
len(all_clips),
len(clips_without_asset),
config_asset_ids[:5] if config_asset_ids else [],
)
if clips_without_asset and config_asset_ids:
logger.info(
"模板编辑器自动兜底3: plan=%s%d 个无素材片段分配 %d 个指定素材",
plan_id,
len(clips_without_asset),
len(config_asset_ids),
)
assigned = 0
for i, clip in enumerate(clips_without_asset):
asset_idx = i % len(config_asset_ids)
try:
svc.assign_asset(clip.id, config_asset_ids[asset_idx])
assigned += 1
except Exception as exc:
logger.error(
"模板编辑器自动兜底3: plan=%s clip=%s 分配素材 %s 失败: %s",
plan_id,
clip.id,
config_asset_ids[asset_idx],
exc,
)
logger.info(
"模板编辑器自动兜底3: plan=%s 素材分配完成 assigned=%d/%d",
plan_id,
assigned,
len(clips_without_asset),
)
# 重新检查剩余无素材片段
all_clips_after = svc.list_clips(plan_id)
clips_without_asset = [c for c in all_clips_after if not c.asset_id]
if clips_without_asset:
logger.warning(
"模板编辑器自动兜底3: plan=%s 仍有 %d 个片段无素材",
plan_id,
len(clips_without_asset),
)
elif not clips_without_asset:
logger.info("模板编辑器自动兜底3: plan=%s 所有片段已有素材,跳过", plan_id)
elif not config_asset_ids:
logger.info(
"模板编辑器自动兜底3: plan=%s config.asset_ids 为空,跳过分配",
plan_id,
)
return clips_without_asset
def _auto_fallback_auto_material_mode(
svc: EditPlanService,
plan_id: str,
plan_check,
clips_without_asset: list,
asset_library_repo: Any,
asset_repo: Any,
user_id: str = "",
) -> None:
"""自动兜底 4: 自动选素材分配给无素材片段
查找策略(按优先级):
1. plan 有 project_id → 从项目素材库查找
2. plan 无 project_id 但有 user_id → 从用户上传的素材中查找
"""
if not clips_without_asset:
return
ready_videos: list = []
source_desc = ""
# 策略 1: 通过 project_id 查找项目素材库
if plan_check.project_id:
libs = asset_library_repo.find_by_project(plan_check.project_id)
video_lib = None
for lib in libs:
lib_kind = lib.kind.value if hasattr(lib.kind, "value") else lib.kind
if lib_kind == "video":
video_lib = lib
break
if video_lib:
assets = asset_repo.find_by_library(video_lib.id)
ready_videos = [
a
for a in assets
if (a.status.value if hasattr(a.status, "value") else a.status) == "ready"
and a.mime_type
and a.mime_type.startswith("video")
]
source_desc = f"素材库 {video_lib.name}"
# 策略 2: 通过 user_id 查找用户上传的素材
if not ready_videos and user_id and hasattr(asset_repo, "find_ready_videos_by_user"):
logger.info(
"模板编辑器自动兜底4: plan=%s project_id 为空,尝试通过 user_id=%s 查找素材",
plan_id,
user_id,
)
ready_videos = asset_repo.find_ready_videos_by_user(user_id)
source_desc = f"用户上传 (user_id={user_id[:8]}...)"
if not ready_videos:
logger.warning(
"模板编辑器自动兜底4: plan=%s 未找到可用素材 (project_id=%s, user_id=%s)",
plan_id,
plan_check.project_id or "(empty)",
user_id[:8] + "..." if user_id else "(empty)",
)
return
logger.info(
"模板编辑器自动兜底4: plan=%s 自动选素材分配给 %d 个无素材片段 (来源: %s, 共 %d 个)",
plan_id,
len(clips_without_asset),
source_desc,
len(ready_videos),
)
random.shuffle(ready_videos)
for i, clip in enumerate(clips_without_asset):
asset = ready_videos[i % len(ready_videos)]
svc.assign_asset(clip.id, asset.id)
logger.info(
"模板编辑器自动兜底4: plan=%s%s 分配了 %d 个素材给 %d 个片段",
plan_id,
source_desc,
len(ready_videos),
len(clips_without_asset),
)
+481 -32
View File
@@ -15,16 +15,25 @@
from __future__ import annotations
import json
import logging
import random
import re
from app.auth import AuthenticatedUser, get_current_user
from app.core.storage import get_storage_service
from app.dependencies import get_asset_repository
from app.dependencies import get_asset_repository, get_db_session
from app.services.edit_plan_service import EditPlanService
from app.services.edit_template_service import EditTemplateService
from fastapi import APIRouter, Depends, HTTPException, Query, status
from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException, Query, status
from sqlalchemy.orm import Session
from packages.adapters.sqlalchemy_impl.asset_repository import SQLAlchemyAssetRepository
from packages.adapters.sqlalchemy_impl.template_repository import (
SQLAlchemyTemplateRepository,
)
from packages.domain.plan_generator_utils import _calc_random_start_time
from packages.shared.mediakit_client import get_mediakit_client
from .dependencies import get_draft_plan_id, get_editor_services
from .schemas import (
@@ -45,6 +54,9 @@ from .schemas import (
logger = logging.getLogger(__name__)
router = APIRouter(tags=["Template Editor"])
# 编辑器默认片段时长(秒)
_DEFAULT_EDITOR_CLIP_DURATION = 5.0
def _clip_to_response(clip, asset_url: str | None = None) -> EditorClipResponse:
"""统一构造片段响应 — 与 edit_plan_clips 表字段完全对齐"""
@@ -155,10 +167,7 @@ def list_draft_clips(
url_map = _build_asset_url_map(asset_ids, asset_repo)
return EditorClipListResponse(
items=[
_clip_to_response(c, asset_url=url_map.get(getattr(c, "asset_id", "") or ""))
for c in clips
],
items=[_clip_to_response(c, asset_url=url_map.get(getattr(c, "asset_id", "") or "")) for c in clips],
total=total,
)
@@ -272,9 +281,7 @@ def split_draft_clip(
try:
result = plan_svc.split_clip(clip_id, body.split_time)
except ValueError as exc:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST, detail=str(exc)
) from exc
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(exc)) from exc
left = result["left_clip"]
right = result["right_clip"]
asset_ids = [getattr(left, "asset_id", "") or "", getattr(right, "asset_id", "") or ""]
@@ -304,9 +311,7 @@ def merge_draft_clips(
try:
merged = plan_svc.merge_clips(body.clip_ids)
except ValueError as exc:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST, detail=str(exc)
) from exc
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(exc)) from exc
asset_id = getattr(merged, "asset_id", "") or ""
url_map = _build_asset_url_map([asset_id], asset_repo) if asset_id else {}
return {
@@ -354,40 +359,484 @@ def batch_delete_editor_clips(
return ClipBatchDeleteResponse(deleted_count=deleted, plan_id=plan_id)
def _safe_segment_duration(value, default: float) -> float:
"""安全地将数据库中的时长值转换为正浮点数.
处理 None、无效类型、负数、NaN 等异常情况。
"""
if value is None:
return default
try:
result = float(value)
except (ValueError, TypeError):
return default
if result != result or result <= 0: # NaN check or non-positive
return default
return result
def _get_template_segments(
template_id: str,
tpl_svc: EditTemplateService,
db: Session,
) -> list[tuple[int, float, float]]:
"""获取模板的片段配置(顺序、最短时长、最长时长).
优先从新模板系统(template_clip_configs)查询,
若不存在则回退到旧模板系统(template_segments)。
Returns:
[(segment_order, duration_min, duration_max), ...] 按 order 排序
"""
# 优先查新模板系统
try:
clip_configs = tpl_svc.list_clip_configs(template_id)
if clip_configs:
result = []
for cc in clip_configs:
dur_min = _safe_segment_duration(
cc.min_duration, _DEFAULT_EDITOR_CLIP_DURATION
)
dur_max = _safe_segment_duration(
cc.max_duration or cc.min_duration,
_DEFAULT_EDITOR_CLIP_DURATION,
)
dur_min, dur_max = min(dur_min, dur_max), max(dur_min, dur_max)
result.append((cc.order, dur_min, dur_max))
return sorted(result, key=lambda x: x[0])
except Exception:
logger.warning("新模板系统查询clip_configs失败,回退到旧系统", exc_info=True)
# 回退到旧模板系统(template_segments表)
try:
old_repo = SQLAlchemyTemplateRepository(db)
segments = old_repo.list_segments(template_id)
if segments:
result = []
for s in segments:
dur_min = _safe_segment_duration(s.duration_min, _DEFAULT_EDITOR_CLIP_DURATION)
dur_max = _safe_segment_duration(s.duration_max, _DEFAULT_EDITOR_CLIP_DURATION)
dur_min, dur_max = min(dur_min, dur_max), max(dur_min, dur_max)
result.append((s.segment_order, dur_min, dur_max))
return sorted(result, key=lambda x: x[0])
except Exception:
logger.warning("旧模板系统查询segments失败", exc_info=True)
return []
def _recommended_time_conflicts(
start: float,
duration: float,
used: list[tuple[float, float]],
) -> bool:
"""检查推荐起始时间是否与已使用时间段冲突."""
end = start + duration
for used_start, used_end in used:
if start < used_end and end > used_start:
return True
return False
def _get_mediakit_recommendations(
asset_ids: list[str],
asset_repo,
) -> dict[str, float]:
"""调用 MediaKit 视频理解,获取智能选片推荐起始时间.
尝试让 MediaKit 分析视频内容,返回每个素材的推荐起始时间。
任何异常都优雅降级,返回空字典(调用方降级到随机选择)。
"""
try:
client = get_mediakit_client()
if not client.is_available:
logger.info("MediaKit 未配置,使用随机起始时间")
return {}
storage = get_storage_service()
video_urls: list[str] = []
valid_asset_ids: list[str] = []
for asset_id in asset_ids[:10]:
asset = asset_repo.get(asset_id)
if not asset or not getattr(asset, "storage_key", None):
continue
mime = getattr(asset, "mime_type", "")
if not mime.startswith("video/"):
continue
try:
url = storage.get_download_url(asset.storage_key)
if url:
video_urls.append(url)
valid_asset_ids.append(asset_id)
except Exception as e:
logger.warning("获取素材URL失败: asset_id=%s error=%s", asset_id, e)
if not video_urls:
return {}
prompt = (
"请分析每段视频,找出最精彩的5秒片段应该从哪个时间点开始。"
"考虑因素:画面清晰度、主体是否明确、是否有明显的动作或场景变化。"
'请严格以JSON数组格式返回,不要包含其他文字:'
'[{"asset_id": "素材ID", "recommended_start_time": 12.5, "reason": "原因"}]'
)
contents = client.analyze_videos(
video_urls=video_urls,
prompt=prompt,
level="Economy",
poll_interval=2.0,
max_poll_attempts=15,
)
if not contents:
logger.info("MediaKit 分析无结果,降级为随机选择")
return {}
# 按索引映射结果:contents[i] 对应 valid_asset_ids[i]
recommendations: dict[str, float] = {}
for idx, content_text in enumerate(contents):
if idx >= len(valid_asset_ids):
break
asset_id = valid_asset_ids[idx]
if not content_text:
continue
# 尝试从文本中提取 JSON
parsed = False
# 尝试直接解析
try:
data = json.loads(content_text.strip())
if isinstance(data, list) and data:
for item in data:
if isinstance(item, dict) and "recommended_start_time" in item:
recommendations[asset_id] = float(item["recommended_start_time"])
parsed = True
break
except (json.JSONDecodeError, ValueError, TypeError):
pass
# 尝试从 markdown 代码块中提取 JSON
if not parsed:
json_match = re.search(r"\[\s*(\{.*?\})\s*\]", content_text, re.DOTALL)
if json_match:
try:
item = json.loads(json_match.group(1))
if isinstance(item, dict) and "recommended_start_time" in item:
recommendations[asset_id] = float(item["recommended_start_time"])
parsed = True
except (json.JSONDecodeError, ValueError, TypeError):
pass
# 尝试正则提取
if not parsed:
time_match = re.search(
r'recommended_start_time["\s:]+([\d.]+)', content_text
)
if time_match:
try:
recommendations[asset_id] = float(time_match.group(1))
except (ValueError, TypeError):
pass
if recommendations:
logger.info("MediaKit 智能选片推荐: %s", recommendations)
else:
logger.info("MediaKit 结果解析失败,降级为随机选择")
return recommendations
except Exception as e:
logger.warning("MediaKit 智能选片异常,降级为随机选择: %s", e)
return {}
@router.post("/clips/from-assets", response_model=ClipsFromAssetsResponse)
def create_clips_from_assets_editor(
template_id: str,
body: ClipsFromAssetsRequest,
background_tasks: BackgroundTasks,
plan_id: str = Depends(get_draft_plan_id),
services: tuple[EditTemplateService, EditPlanService] = Depends(get_editor_services),
asset_repo: SQLAlchemyAssetRepository = Depends(get_asset_repository),
db: Session = Depends(get_db_session),
current_user: AuthenticatedUser = Depends(get_current_user),
) -> ClipsFromAssetsResponse:
"""从素材批量创建片段"""
_, plan_svc = services
clips = []
for i, asset_id in enumerate(body.asset_ids):
try:
clip = plan_svc.create_clip(
plan_id,
clip_type="main",
order=body.start_order + i if hasattr(body, "start_order") else i,
duration=5.0,
asset_id=asset_id,
"""从素材批量创建片段(按模板segment配置创建,MediaKit异步更新).
逻辑:
1. 从模板读取 segments,片段数量 = segment 数量(忽略前端传的 required_clips_count
2. 每个片段时长在 segment 的 duration_min ~ duration_max 之间随机取值(保留一位小数)
3. 素材按片段顺序轮询分配,素材不够时同一素材切多个片段
4. 使用 replace_all_clips_transactional 原子性地清空旧片段并创建新的(随机起始时间)
5. 立即返回响应(目标 <1秒)
6. 后台异步任务:调用 MediaKit 智能选片并更新片段的 start_time
7. 素材时长为 0 或缺失时报 400,不创建无效片段
"""
tpl_svc, plan_svc = services
# 1. 查询模板 segments
segments = _get_template_segments(template_id, tpl_svc, db)
if not segments:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="模板没有片段配置,无法创建片段",
)
if not body.asset_ids:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="素材列表为空,无法创建片段",
)
# 2. 获取素材实际时长(去重查询)
unique_asset_ids = list(dict.fromkeys(body.asset_ids))
asset_durations: dict[str, float] = {}
for asset_id in unique_asset_ids:
asset = asset_repo.get(asset_id)
if asset and hasattr(asset, "duration"):
asset_durations[asset_id] = float(asset.duration or 0.0)
# 3. 在内存中计算所有片段数据(使用随机起始时间,不调用MediaKit)
used_segments: dict[str, list[tuple[float, float]]] = {}
clips_data: list[dict] = []
for i, (_seg_order, dur_min, dur_max) in enumerate(segments):
# 轮询分配素材
asset_id = body.asset_ids[i % len(body.asset_ids)]
asset_total = asset_durations.get(asset_id, 0.0)
# 素材时长为 0 或缺失时无法创建有效片段
if asset_total <= 0:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"素材 {asset_id} 时长信息缺失或为0,无法创建片段",
)
clips.append(clip)
except ValueError:
pass
# 在 segment 的 duration_min ~ duration_max 之间随机取值(保留一位小数)
raw_duration = random.uniform(dur_min, dur_max)
clip_duration = round(raw_duration, 1)
# 素材时长不足时缩短 clip duration
clip_duration = min(clip_duration, asset_total)
if clip_duration <= 0:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"素材 {asset_id} 时长不足,无法创建有效片段",
)
# 使用随机起始时间(不调用MediaKit,保证接口快速返回)
start_time = _calc_random_start_time(
asset_id, clip_duration, asset_durations, used_segments
)
if start_time is None:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"素材 {asset_id} 时长信息缺失,无法计算起始时间",
)
# 记录已使用时间段
used_segments.setdefault(asset_id, []).append(
(start_time, start_time + clip_duration)
)
clips_data.append(
{
"order": i,
"asset_id": asset_id,
"start_time": start_time,
"duration": clip_duration,
"clip_type": body.clip_type or "main",
}
)
# 4. 事务性替换:清空旧片段 → 创建新片段 → 标记ready(单事务,失败自动回滚)
created_count = plan_svc.replace_all_clips_transactional(plan_id, clips_data)
logger.info(
"模板编辑器从素材创建片段: template_id=%s plan_id=%s count=%d by user=%s",
"from-assets按模板创建片段(异步): template_id=%s plan_id=%s segments=%d created=%d by user=%s",
template_id,
plan_id,
len(clips),
len(segments),
created_count,
current_user.user.id,
)
return ClipsFromAssetsResponse(
created_count=len(clips),
plan_id=plan_id,
clip_ids=[c.id for c in clips],
# 5. 触发后台任务:异步调用 MediaKit 并更新片段起始时间
background_tasks.add_task(
_update_mediakit_recommendations_async,
plan_id,
unique_asset_ids,
)
# 6. 立即返回响应
return ClipsFromAssetsResponse(
created_count=created_count,
plan_id=plan_id,
clip_ids=[],
)
def _update_mediakit_recommendations_async( # pragma: no cover
plan_id: str,
asset_ids: list[str],
) -> None:
"""后台任务:调用 MediaKit 智能选片并更新片段的起始时间.
此函数在后台异步执行,不影响接口响应时间。
失败时静默处理,不影响已创建的片段。
"""
from collections import defaultdict
from packages.adapters.sqlalchemy_impl.asset_repository import SQLAlchemyAssetRepository
from packages.adapters.sqlalchemy_impl.session import SessionLocal
db = None
try:
# 复用应用全局 Session(避免每次创建新连接池导致资源泄漏)
if SessionLocal is None:
logger.warning("后台任务: SessionLocal 未初始化,跳过 MediaKit 更新")
return
db = SessionLocal()
# 初始化服务
asset_repo = SQLAlchemyAssetRepository(db)
plan_svc = EditPlanService(db)
# 调用 MediaKit 获取推荐时间
recommendations = _get_mediakit_recommendations(asset_ids, asset_repo)
if not recommendations:
logger.info("后台任务: MediaKit 无推荐结果,跳过更新")
return
# 查询该 plan 的所有片段(分批获取,避免硬编码 limit 截断)
batch_size = 500
all_clips = []
offset = 0
while True:
batch = plan_svc.list_clips(plan_id, skip=offset, limit=batch_size)
if not batch:
break
all_clips.extend(batch)
if len(batch) < batch_size:
break
offset += batch_size
clips = all_clips
if not clips:
logger.info("后台任务: plan_id=%s 无片段,跳过更新", plan_id)
return
# 批量预加载所有涉及的素材(消除 N+1 查询)
unique_asset_ids = list({getattr(c, "asset_id", "") or "" for c in clips} - {""})
assets_map: dict[str, object] = {
a.id: a for a in asset_repo.find_by_ids(unique_asset_ids)
}
# 按 asset_id 预分组片段时间段(消除 O(N^2) 嵌套循环)
clips_by_asset: dict[str, list[tuple[str, float, float]]] = defaultdict(list)
for clip in clips:
aid = getattr(clip, "asset_id", "") or ""
if aid and clip.start_time is not None:
clips_by_asset[aid].append(
(clip.id, clip.start_time, clip.start_time + clip.duration)
)
# 已更新的片段ID(用于排除已移动的旧时间段)
updated_clip_ids: set[str] = set()
# 已更新的时间段
updated_segments: dict[str, list[tuple[float, float]]] = {}
updated_count = 0
# 遍历片段,按 asset_id 匹配推荐时间
for clip in clips:
asset_id = getattr(clip, "asset_id", "") or ""
if not asset_id or asset_id not in recommendations:
continue
recommended_start = recommendations[asset_id]
clip_duration = clip.duration
# 从预加载字典获取素材(O(1) 查找)
asset = assets_map.get(asset_id)
if not asset:
continue
asset_total = float(getattr(asset, "duration", 0.0) or 0.0)
if asset_total <= 0:
continue
# 推荐时间 + 片段时长不能超过素材总时长
if recommended_start + clip_duration > asset_total:
logger.info(
"后台任务: 推荐时间越界,跳过: asset_id=%s recommended=%.2f duration=%.1f total=%.1f",
asset_id,
recommended_start,
clip_duration,
asset_total,
)
continue
# 构建排除当前片段及已更新片段后的占用列表(O(M),M=同素材片段数)
other_segments: list[tuple[float, float]] = [
(cs, ce)
for cid, cs, ce in clips_by_asset.get(asset_id, [])
if cid != clip.id and cid not in updated_clip_ids
]
other_segments.extend(updated_segments.get(asset_id, []))
# 检查是否与同素材其他片段时间段冲突
if _recommended_time_conflicts(recommended_start, clip_duration, other_segments):
logger.info(
"后台任务: 推荐时间冲突,跳过: asset_id=%s recommended=%.2f",
asset_id,
recommended_start,
)
continue
# 逐个更新并捕获异常(单点失败不影响其他片段)
try:
plan_svc.update_clip(clip.id, start_time=recommended_start)
db.commit()
updated_count += 1
updated_clip_ids.add(clip.id)
except Exception as ue:
logger.warning(
"后台任务: 单个片段更新失败: clip_id=%s error=%s", clip.id, ue
)
try:
db.rollback()
except Exception:
pass
continue
updated_segments.setdefault(asset_id, []).append(
(recommended_start, recommended_start + clip_duration)
)
logger.info(
"后台任务: 更新片段起始时间: clip_id=%s asset_id=%s start_time=%.2f",
clip.id,
asset_id,
recommended_start,
)
logger.info("后台任务完成: plan_id=%s 成功更新 %d 个片段", plan_id, updated_count)
except Exception as e:
# 后台任务失败不影响已创建的片段,静默处理
logger.warning("后台任务异常: plan_id=%s error=%s", plan_id, e, exc_info=True)
if db:
try:
db.rollback()
except Exception:
pass
finally:
if db:
try:
db.close()
except Exception:
pass
@@ -3,7 +3,6 @@
核心依赖:
- get_editor_services: 获取模板+计划服务
- get_draft_plan_id: 根据 template_id 获取或创建草稿,返回 plan_id
- _check_queue_limits: 生成队列限流检查
"""
from __future__ import annotations
@@ -11,7 +10,6 @@ from __future__ import annotations
import logging
from app.auth import AuthenticatedUser, get_current_user
from app.core.task_enqueue import GLOBAL_PENDING_LIMIT, USER_PENDING_LIMIT
from app.dependencies import get_db_session
from app.services.edit_plan_service import EditPlanService
from app.services.edit_template_service import EditTemplateService
@@ -113,29 +111,3 @@ def get_draft_plan_id(
user_id,
)
return plan.id
def _check_queue_limits(gen_task_repo, user_id: str) -> None:
"""队列限流预检查"""
try:
has_count = (
hasattr(gen_task_repo, "count_pending_by_user")
and hasattr(gen_task_repo, "count_pending_total")
)
if has_count:
user_pending = gen_task_repo.count_pending_by_user(user_id)
global_pending = gen_task_repo.count_pending_total()
if user_pending >= USER_PENDING_LIMIT:
raise HTTPException(
status_code=429,
detail=f"您的待处理任务过多(当前 {user_pending}/{USER_PENDING_LIMIT}),请等待完成后再提交",
)
if global_pending >= GLOBAL_PENDING_LIMIT:
raise HTTPException(
status_code=503,
detail="系统繁忙,请稍后再试",
)
except HTTPException:
raise
except Exception as e:
logger.warning("[模板编辑器队列限流] 检查失败,跳过: %s", e)
@@ -17,6 +17,8 @@ from fastapi import APIRouter, Depends, HTTPException, Query, status
from .dependencies import get_draft_plan_id, get_editor_services
from .schemas import (
EditorClipBatchUpdateRequest,
EditorClipBatchUpdateResponse,
EditorDraftResponse,
EditorPublishResponse,
EditorRollbackRequest,
@@ -126,11 +128,7 @@ def list_template_versions(
clip_count=len(v.clip_configs),
change_note=v.change_note,
published_by=v.published_by,
created_at=(
v.created_at.isoformat()
if hasattr(v.created_at, "isoformat")
else str(v.created_at)
),
created_at=(v.created_at.isoformat() if hasattr(v.created_at, "isoformat") else str(v.created_at)),
)
for v in versions
]
@@ -162,3 +160,35 @@ def rollback_template(
new_version=tpl.version,
clip_count=len(clip_configs),
)
@router.put("/clips", response_model=EditorClipBatchUpdateResponse)
def batch_update_clips(
template_id: str,
req: EditorClipBatchUpdateRequest,
plan_id: str = Depends(get_draft_plan_id),
services: tuple[EditTemplateService, EditPlanService] = Depends(get_editor_services),
_: AuthenticatedUser = Depends(get_current_user),
):
"""批量替换草稿clips(全量覆盖,用于前端选择素材后同步片段)
事务保证:清空→创建→标记ready 在同一数据库事务内完成,
任何步骤失败时自动回滚,避免数据不一致。
"""
_, plan_svc = services
plan_svc.get_plan_or_raise(plan_id)
clips_data = []
for clip_item in req.clips:
item = {
"asset_id": clip_item.asset_id,
"start_time": clip_item.start_time,
"duration": clip_item.duration,
}
if clip_item.order is not None:
item["order"] = clip_item.order
clips_data.append(item)
plan_svc.replace_all_clips_transactional(plan_id, clips_data)
return EditorClipBatchUpdateResponse(plan_id=plan_id, clip_count=len(req.clips))
@@ -1,383 +0,0 @@
"""草稿生成路由.
端点:
- POST /generate 触发生成
- GET /generation-status 生成进度
- GET /generations 生成记录列表
"""
from __future__ import annotations
import json
import logging
from typing import Any, Optional
from app.auth import AuthenticatedUser, get_current_user
from app.core.celery_app import celery_app
from app.core.storage import OSSStorageService, get_storage_service
from app.dependencies import (
get_asset_library_repository,
get_asset_repository,
get_db_session,
get_generated_video_repository,
)
from app.schemas.generation_task import GenerationTaskResponse
from app.services.edit_plan_service import EditPlanService
from app.services.edit_template_service import EditTemplateService
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm import Session
from packages.adapters.sqlalchemy_impl.generation_task_repository import (
SQLAlchemyGenerationTaskRepository,
)
from packages.application.generated_videos import ListGeneratedVideosByTaskUseCase
from packages.application.generation_tasks import (
CreateGenerationTaskCommand,
CreateGenerationTaskUseCase,
)
from packages.domain.edit_plan import EditPlanStatus
from ._fallback import (
_auto_fallback_assign_assets,
_auto_fallback_auto_material_mode,
_auto_fallback_copy_template_clips,
_auto_fallback_draft_to_editing,
)
from .dependencies import _check_queue_limits, get_draft_plan_id, get_editor_services
from .schemas import (
ClipStatusItem,
EditPlanGenerateRequest,
EditPlanGenerateResponse,
EditPlanGenerationsResponse,
EditPlanGenerationStatusResponse,
)
logger = logging.getLogger(__name__)
router = APIRouter(tags=["Template Editor"])
@router.post("/generate", response_model=EditPlanGenerateResponse)
def generate_editor_draft(
template_id: str,
request: Optional[EditPlanGenerateRequest] = None,
plan_id: str = Depends(get_draft_plan_id),
services: tuple[EditTemplateService, EditPlanService] = Depends(get_editor_services),
db: Session = Depends(get_db_session),
current_user: AuthenticatedUser = Depends(get_current_user),
asset_library_repo: Any = Depends(get_asset_library_repository),
asset_repo: Any = Depends(get_asset_repository),
) -> EditPlanGenerateResponse:
"""触发模板草稿渲染生成"""
req = request or EditPlanGenerateRequest()
_, plan_svc = services
plan_check = plan_svc.get_plan_or_raise(plan_id)
# 自动兜底流程
_auto_fallback_draft_to_editing(plan_svc, plan_id, plan_check)
_auto_fallback_copy_template_clips(plan_svc, plan_id, plan_check, db)
clips_without_asset = _auto_fallback_assign_assets(plan_svc, plan_id, plan_check)
_auto_fallback_auto_material_mode(
plan_svc,
plan_id,
plan_check,
clips_without_asset,
asset_library_repo,
asset_repo,
user_id=str(current_user.user.id),
)
# 检查是否可复用已完成的预览产物(预览品质已与正式一致)
gen_task_repo = SQLAlchemyGenerationTaskRepository(db)
reusable_task = _find_reusable_preview_task(gen_task_repo, plan_id, plan_check)
if reusable_task:
# 复用预览产物:标记为正式产出,跳过渲染
# 如果前端传了 title_config,需要创建新任务(因为预览任务的 custom_title 可能不同)
title_config_reuse = req.title_config or {}
title_text_reuse = (title_config_reuse.get("text") or "").strip()
existing_custom_title = getattr(reusable_task, "custom_title", "") or ""
if title_text_reuse and existing_custom_title:
# 如果新标题和已有标题不同,不能复用,走新建任务流程
new_title_json = json.dumps(title_config_reuse, ensure_ascii=False)
if new_title_json != existing_custom_title:
logger.info(
"[模板生成] 标题已变更,跳过复用: task_id=%s",
reusable_task.id,
)
reusable_task = None
elif title_text_reuse and not existing_custom_title:
# 原来没标题,现在有标题,不能复用
logger.info(
"[模板生成] 新增标题,跳过复用: task_id=%s",
reusable_task.id,
)
reusable_task = None
elif not title_text_reuse and existing_custom_title:
# 原来有标题,现在移除了,不能复用
logger.info(
"[模板生成] 移除标题,跳过复用: task_id=%s",
reusable_task.id,
)
reusable_task = None
if reusable_task:
# 复用预览产物:标记为正式产出,跳过渲染
reusable_task.mark_confirmed()
gen_task_repo.update(reusable_task)
# 将产物 URL 写入 plan config
rendered_url = _get_task_output_url(reusable_task, gen_task_repo, db)
plan_svc.update_plan_config(
plan_id,
{
"generation_task_id": reusable_task.id,
"rendered_storage_key": rendered_url, # 统一用 rendered_storage_key
},
)
plan_svc.transition_status(plan_id, EditPlanStatus.COMPLETED)
updated_plan = plan_svc.get_plan_or_raise(plan_id)
logger.info(
"模板编辑器复用预览产物: template_id=%s plan_id=%s task_id=%s by user=%s",
template_id,
plan_id,
reusable_task.id,
current_user.user.id,
)
return EditPlanGenerateResponse(
plan_id=plan_id,
plan_status=updated_plan.status.value if hasattr(updated_plan.status, "value") else updated_plan.status,
generation_task_id=reusable_task.id,
clip_count=len((plan_check.config or {}).get("clips", [])),
)
# 检查是否可生成(含最后防线自动修复 + 诊断日志)
try:
can_gen, reason = plan_svc.can_generate(plan_id)
except ValueError as exc:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(exc)) from exc
if not can_gen:
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=reason)
try:
clip_count = plan_svc.mark_clips_ready(plan_id)
user_id = current_user.user.id
_check_queue_limits(gen_task_repo, user_id)
gen_task_use_case = CreateGenerationTaskUseCase(gen_task_repo)
plan = plan_svc.get_plan_or_raise(plan_id)
config_asset_ids = (plan.config or {}).get("asset_ids", [])
# 从 plan config 读取封面 URL(由 generate-cover 保存)
cover_url_from_config = (plan.config or {}).get("cover", {}).get("image_url", "")
# 处理标题配置:序列化 title_config 为 JSON 存入 custom_title
title_config = req.title_config or {}
title_text = (title_config.get("text") or "").strip()
custom_title_value = ""
if title_text:
custom_title_value = json.dumps(title_config, ensure_ascii=False)
logger.info(
"[模板生成] 标题配置: text=%s, config_keys=%s",
title_text[:30],
list(title_config.keys()),
)
gen_task = gen_task_use_case.execute(
CreateGenerationTaskCommand(
project_id=plan.project_id or "",
template_id=plan.template_id,
created_by_user_id=current_user.user.id,
source_edit_plan_id=plan_id,
asset_ids=list(config_asset_ids) if config_asset_ids else [],
cover_url=cover_url_from_config,
custom_title=custom_title_value,
),
)
plan_svc.update_plan_config(plan_id, {"generation_task_id": gen_task.id})
plan_svc.transition_status(plan_id, EditPlanStatus.RENDERING)
celery_app.send_task("worker.render_edit_plan", args=[plan_id])
updated_plan = plan_svc.get_plan_or_raise(plan_id)
logger.info(
"模板编辑器触发生成: template_id=%s plan_id=%s gen_task_id=%s clips=%d by user=%s",
template_id,
plan_id,
gen_task.id,
clip_count,
current_user.user.id,
)
return EditPlanGenerateResponse(
plan_id=plan_id,
plan_status=updated_plan.status.value if hasattr(updated_plan.status, "value") else updated_plan.status,
generation_task_id=gen_task.id,
clip_count=clip_count,
)
except HTTPException:
raise
except Exception as _e:
logger.exception(
"模板编辑器触发生成失败: template_id=%s plan_id=%s",
template_id,
plan_id,
)
try:
plan_svc.transition_status(plan_id, EditPlanStatus.FAILED)
except Exception:
pass
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="生成失败,请稍后重试",
) from _e
def _find_reusable_preview_task(gen_task_repo, plan_id: str, plan) -> "object | None":
"""查找该 plan 关联的已完成预览任务,判断是否可复用。
复用条件:
1. 存在 source_edit_plan_id == plan_id 的已完成预览任务
2. plan 在预览完成后未被修改(updated_at <= 预览完成时间)
Returns:
可复用的 GenerationTask,或 None
"""
try:
tasks = gen_task_repo.list_by_source_edit_plan(plan_id)
except Exception:
return None
for task in tasks:
if not getattr(task, "is_preview", False):
continue
if not task.is_completed:
continue
# 检查 plan 是否在预览完成后被修改
completed_at = getattr(task, "completed_at", None)
if completed_at and hasattr(plan, "updated_at"):
plan_updated = plan.updated_at
# 如果 plan.updated_at 为空,无法判断是否修改过,跳过
if plan_updated is None:
continue
# 如果 plan 在预览完成后又被修改了,不能复用
if plan_updated > completed_at:
continue
return task
return None
def _get_task_output_url(task, gen_task_repo, db) -> str:
"""获取任务的输出视频 URL。"""
try:
video_repo = get_generated_video_repository(db)
use_case = ListGeneratedVideosByTaskUseCase(video_repo)
videos = use_case.execute(task.id)
if videos:
url = getattr(videos[0], "file_url", "") or ""
# 规范化:合并路径中的双斜杠(保留协议头 ://)
if url:
import re as _re
url = _re.sub(r"(?<!:)//", "/", url)
return url
except Exception:
pass
return ""
@router.get("/generation-status", response_model=EditPlanGenerationStatusResponse)
def get_editor_generation_status(
template_id: str,
plan_id: str = Depends(get_draft_plan_id),
services: tuple[EditTemplateService, EditPlanService] = Depends(get_editor_services),
storage_service: OSSStorageService = Depends(get_storage_service),
_: AuthenticatedUser = Depends(get_current_user),
) -> EditPlanGenerationStatusResponse:
"""查询草稿生成进度"""
_, plan_svc = services
try:
gen_status = plan_svc.get_generation_status(plan_id)
except ValueError as exc:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(exc)) from exc
plan = gen_status["plan"]
clips = gen_status["clips"]
clip_items = [
ClipStatusItem(
clip_id=c.id,
clip_type=c.clip_type,
order=c.order,
status=c.status.value if hasattr(c.status, "value") else c.status,
asset_id=c.asset_id or "",
text_content=c.text_content or "",
duration=c.duration,
)
for c in clips
]
raw_video_url = (plan.config or {}).get("rendered_storage_key", "") or (plan.config or {}).get("rendered_url", "")
video_url = ""
if raw_video_url:
if raw_video_url.startswith("http"):
video_url = raw_video_url # 已经是完整 URL
else:
try:
video_url = storage_service.get_url(raw_video_url) # storage_key -> 完整 URL
except Exception as e:
logger.warning("生成视频URL获取失败: template_id=%s error=%s", template_id, e)
video_url = raw_video_url
progress = gen_status.get("progress", 0.0)
error_message = gen_status.get("error_message", "")
gen_task_status = gen_status.get("generation_task_status")
plan_status_val = plan.status.value if hasattr(plan.status, "value") else plan.status
if plan_status_val == "completed" and progress < 100:
progress = 100.0
return EditPlanGenerationStatusResponse(
plan_id=plan_id,
plan_status=plan_status_val,
generation_task_id=gen_status["generation_task_id"],
generation_task_status=gen_task_status,
progress=progress,
video_url=video_url,
error_message=error_message,
clips=clip_items,
)
@router.get("/generations", response_model=EditPlanGenerationsResponse)
def list_editor_generations(
template_id: str,
plan_id: str = Depends(get_draft_plan_id),
services: tuple[EditTemplateService, EditPlanService] = Depends(get_editor_services),
db: Session = Depends(get_db_session),
_: AuthenticatedUser = Depends(get_current_user),
) -> EditPlanGenerationsResponse:
"""查询草稿关联的生成记录列表"""
_, plan_svc = services
plan_svc.get_plan_or_raise(plan_id)
gen_task_repo = SQLAlchemyGenerationTaskRepository(db)
tasks = gen_task_repo.list_by_source_edit_plan(plan_id)
items = [
GenerationTaskResponse(
id=t.id,
project_id=t.project_id,
asset_library_id=t.asset_library_id,
strategy_id=t.strategy_id,
voice_library_id=t.voice_library_id,
template_id=t.template_id,
asset_ids=t.asset_ids,
title_ids=t.title_ids,
voice_ids=t.voice_ids,
source_edit_plan_id=t.source_edit_plan_id or "",
status=t.status.value if hasattr(t.status, "value") else t.status,
progress=t.progress,
result_count=t.result_count,
error_message=t.error_message,
)
for t in tasks
]
return EditPlanGenerationsResponse(items=items, total=len(items))
@@ -6,9 +6,8 @@
from __future__ import annotations
import re as _re
from typing import Any, Dict, List, Optional
from typing import Any, List, Optional
from app.schemas.generation_task import GenerationTaskResponse
from pydantic import BaseModel, Field, validator
_EXPORT_RESOLUTION_PATTERN = _re.compile(r"^\d+x\d+$")
@@ -16,58 +15,6 @@ _EXPORT_VALID_QUALITY_PRESETS = {"ultra_fast", "fast", "balanced", "high", "best
_EXPORT_VALID_FORMATS = {"mp4", "mov"}
# ── 生成状态相关 ────────────────────────────────────────────────────────────
class ClipStatusItem(BaseModel):
"""片段生成状态"""
clip_id: str
clip_type: str
order: int
status: str
asset_id: str
text_content: str
duration: float
class EditPlanGenerationStatusResponse(BaseModel):
"""剪辑计划生成进度响应体"""
plan_id: str
plan_status: str
generation_task_id: Optional[str] = None
generation_task_status: Optional[str] = None
progress: float = 0.0
video_url: str = ""
error_message: str = ""
clips: List[ClipStatusItem]
class EditPlanGenerateRequest(BaseModel):
"""模板编辑器触发生成请求体"""
title_config: Optional[Dict[str, Any]] = Field(
default_factory=dict,
description="标题配置(可选),渲染时烧录到视频中。支持字段: text/font/font_size/font_color/position/bold/stroke/shadow",
)
class EditPlanGenerateResponse(BaseModel):
"""剪辑计划触发生成响应体"""
plan_id: str
plan_status: str
generation_task_id: str
clip_count: int
class EditPlanGenerationsResponse(BaseModel):
"""剪辑计划关联的生成记录列表响应体"""
items: List[GenerationTaskResponse]
total: int
# ── AI 推荐 ────────────────────────────────────────────────────────────────
@@ -75,12 +22,8 @@ class AIRecommendRequest(BaseModel):
"""AI 推荐片段方案请求体"""
asset_ids: List[str] = Field(default_factory=list, description="素材 ID 列表")
editing_mode: str = Field(
default="one_take", description="剪辑模式: one_take / pip / voice_over / voice_pip"
)
target_duration: float = Field(
default=30.0, ge=1.0, le=600.0, description="目标时长(秒)"
)
editing_mode: str = Field(default="one_take", description="剪辑模式: one_take / pip / voice_over / voice_pip")
target_duration: float = Field(default=30.0, ge=1.0, le=600.0, description="目标时长(秒)")
class AIRecommendClipItem(BaseModel):
@@ -107,8 +50,6 @@ class AIRecommendResponse(BaseModel):
confidence: float = Field(..., ge=0.0, le=1.0, description="AI 推荐置信度 (0~1)")
# ── BGM ────────────────────────────────────────────────────────────────────
@@ -224,10 +165,9 @@ class ClipBatchDeleteResponse(BaseModel):
class ClipsFromAssetsRequest(BaseModel):
"""从素材批量创建片段请求"""
asset_ids: List[str] = Field(
..., min_length=1, max_length=200, description="素材 ID 列表,按顺序追加到时间线末尾"
)
asset_ids: List[str] = Field(..., min_length=1, max_length=200, description="素材 ID 列表,按顺序追加到时间线末尾")
clip_type: str = Field(default="main", description="片段类型,默认 main")
required_clips_count: Optional[int] = Field(default=None, ge=1, le=200, description="要求创建的片段数量;不传则等于素材数量")
class ClipsFromAssetsResponse(BaseModel):
@@ -501,6 +441,28 @@ class EditorClipUpdateRequest(BaseModel):
config: Optional[dict[str, Any]] = None
class EditorClipBatchItem(BaseModel):
"""批量更新clips的单个片段"""
asset_id: str = Field(default="", max_length=100, description="关联素材ID,可为空(占位片段)")
start_time: float = Field(default=0.0, ge=0.0)
duration: float = Field(default=0.0, ge=0.0)
order: Optional[int] = Field(default=None, ge=0, description="排序,None表示按数组顺序")
class EditorClipBatchUpdateRequest(BaseModel):
"""批量替换clips请求(全量覆盖)"""
clips: List[EditorClipBatchItem] = Field(default_factory=list)
class EditorClipBatchUpdateResponse(BaseModel):
"""批量更新clips响应"""
plan_id: str
clip_count: int
class EditorPublishResponse(BaseModel):
"""发布草稿响应"""
+56 -1
View File
@@ -20,6 +20,8 @@ from app.schemas.tts import (
SaveToLibraryRequest,
SaveToLibraryResponse,
TTSJobResponse,
TTSPreviewRequest,
TTSPreviewResponse,
TTSStatusResponse,
TTSSynthesizeRequest,
TTSSynthesizeResponse,
@@ -31,7 +33,7 @@ from packages.adapters.sqlalchemy_impl.tts_job_repository import (
SQLAlchemyTTSJobRepository,
)
from packages.adapters.sqlalchemy_impl.voice_library_repository import SQLAlchemyVoiceLibraryRepository
from packages.application.cosyvoice_service import CosyVoiceService
from packages.application.cosyvoice_service import CosyVoiceError, CosyVoiceService
from packages.application.tts_job.streaming_service import TTSStreamingService
from packages.application.tts_job.use_cases import (
CreateTTSJobUseCase,
@@ -373,6 +375,59 @@ def save_tts_job_to_library(
)
@router.post("/preview", response_model=TTSPreviewResponse)
def preview_tts(
request: TTSPreviewRequest,
authenticated_user: AuthenticatedUser = Depends(get_current_user),
cosyvoice_service: CosyVoiceService = Depends(get_cosyvoice_service),
voice_clone_repo=Depends(get_voice_clone_profile_repository),
) -> TTSPreviewResponse:
"""TTS 预览(试听)——同步合成,立即返回音频 URL。
用于前端预览配音效果,限制文本长度 200 字以内。
支持预设音色和克隆音色:克隆音色传的是 profile UUID,需解析为 CosyVoice voice_id。
"""
# 解析 voice_id:前端可能传 VoiceCloneProfile UUID 或预设音色 ID
actual_voice_id = request.voice_id
profile = voice_clone_repo.get(request.voice_id)
if profile is not None:
# 命中克隆音色 profile — 校验归属权限
if profile.user_id != authenticated_user.user.id:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="无权访问该音色",
)
if not profile.voice_id:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="音色克隆尚未完成,请稍后再试",
)
actual_voice_id = profile.voice_id
try:
result = cosyvoice_service.synthesize_speech(
text=request.text,
voice_id=actual_voice_id,
speed=request.speed,
)
except CosyVoiceError as e:
raise HTTPException(
status_code=status.HTTP_502_BAD_GATEWAY,
detail=f"TTS 合成失败: {e}",
) from e
except ValueError as e:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=str(e),
) from e
return TTSPreviewResponse(
audio_url=result.audio_url,
duration=result.duration if result.duration and result.duration > 0 else None,
)
@router.websocket("/ws/tts/stream")
async def tts_websocket_stream(
websocket: WebSocket,
+7 -3
View File
@@ -10,7 +10,7 @@ class ConfirmGenerationRequest(BaseModel):
output_width: int = Field(default=1080, ge=100, description="输出视频宽度")
output_height: int = Field(default=1920, ge=100, description="输出视频高度")
cover_url: str = Field(default="", description="自定义封面图片 URL")
custom_title: str = Field(default="", description="自定义视频标题")
custom_title: str = Field(default="", description="用户自定义标题文本,非空时同步到任务和编辑计划")
class CreateGenerationTaskRequest(BaseModel):
@@ -33,6 +33,11 @@ class CreateGenerationTaskRequest(BaseModel):
voice_ids: list[str] = Field(default_factory=list)
# ── 来源剪辑计划 ──
source_edit_plan_id: str = ""
# ── 标题配置(结构化)──
title_config: dict | None = Field(
default=None,
description="标题样式对象,包含 text/font/font_size/font_color/position/bold/stroke/shadow 等。为空时不影响现有行为。",
)
# ── 视频标题 ──
video_title: str = Field(default="", description="生成视频的标题/名称,为空则使用默认命名")
# ── 批量生成 ──
@@ -72,7 +77,6 @@ class CreateGenerationTaskRequest(BaseModel):
output_width: int = Field(default=1280, description="输出视频宽度")
output_height: int = Field(default=720, description="输出视频高度")
cover_url: str = Field(default="", description="封面图片 URL")
custom_title: str = Field(default="", description="自定义视频标题")
@model_validator(mode="after")
def _check_at_least_one_mode(self) -> "CreateGenerationTaskRequest":
@@ -108,7 +112,7 @@ class GenerationTaskResponse(BaseModel):
output_width: int = 1280
output_height: int = 720
cover_url: str = ""
custom_title: str = ""
title_config: dict = Field(default_factory=dict)
status: str
progress: float
result_count: int
+16
View File
@@ -101,3 +101,19 @@ class SaveToLibraryResponse(BaseModel):
voice_id: str
voice_name: str
status: str
class TTSPreviewRequest(BaseModel):
"""TTS 预览(试听)请求。"""
text: str = Field(..., min_length=1, max_length=200, description="合成文本,限制 200 字")
voice_id: str = Field(..., min_length=1, description="音色 ID")
speed: float = Field(1.0, ge=0.5, le=2.0, description="语速")
pitch: float = Field(1.0, ge=0.5, le=2.0, description="音调(预留,当前未使用)")
class TTSPreviewResponse(BaseModel):
"""TTS 预览(试听)响应。"""
audio_url: str = Field(..., description="合成音频 URL")
duration: Optional[float] = Field(default=None, description="音频时长(秒)")
@@ -371,6 +371,88 @@ class EditPlanService:
logger.info("删除所有片段: plan_id=%s count=%d", plan_id, count)
return count
def replace_all_clips_transactional(
self,
plan_id: str,
clips_data: list[dict],
) -> int:
"""事务性地替换所有片段:清空→创建→标记ready,单事务保证原子性。
Args:
plan_id: 计划 ID
clips_data: 片段数据列表,每项包含 asset_id/start_time/duration/order
Returns:
int: 创建的片段数量
Raises:
Exception: 任何步骤失败时自动回滚
"""
from packages.adapters.sqlalchemy_impl.models import EditPlanClipModel
db = self._clip_repo.session
try:
# 1. 清空现有 clips(不 commit
deleted_count = db.query(EditPlanClipModel).filter(EditPlanClipModel.plan_id == plan_id).delete()
# 2. 批量创建新 clips(不 commit
for i, clip_item in enumerate(clips_data):
order = clip_item.get("order") or i
clip = EditPlanClip.create(
plan_id=plan_id,
clip_type=clip_item.get("clip_type", "main"),
order=order,
asset_id=clip_item.get("asset_id", ""),
start_time=clip_item.get("start_time", 0.0),
duration=clip_item.get("duration", 0.0),
)
model = EditPlanClipModel(
id=clip.id,
plan_id=clip.plan_id,
clip_type=clip.clip_type,
order=clip.order,
asset_id=clip.asset_id,
text_content=clip.text_content,
start_time=clip.start_time,
duration=clip.duration,
transition_effect=clip.transition_effect,
transition_duration=clip.transition_duration,
playback_speed=clip.playback_speed,
status=clip.status.value,
config=clip.config,
)
db.add(model)
# flush 让新建 clip 写入当前事务(未 commit),后续查询才能找到它们
db.flush()
# 3. 标记有 asset_id 的 clips 为 ready(不 commit
pending_with_asset = (
db.query(EditPlanClipModel)
.filter(
EditPlanClipModel.plan_id == plan_id,
EditPlanClipModel.status == "pending",
EditPlanClipModel.asset_id != "",
)
.all()
)
for m in pending_with_asset:
m.status = "ready"
# 4. 一次性提交
db.commit()
logger.info(
"事务性替换片段: plan_id=%s deleted=%d created=%d",
plan_id,
deleted_count,
len(clips_data),
)
return len(clips_data)
except Exception:
db.rollback()
logger.exception("事务性替换片段失败: plan_id=%s", plan_id)
raise
# ── 片段分割与合并 ──────────────────────────────────────────────────────
def split_clip(self, clip_id: str, split_time: float) -> Dict[str, Any]:
@@ -118,9 +118,9 @@ class PlanGeneratorService:
# 4. 按 editing_mode 分配素材
if asset_ids:
# 如果是随机预览模式,获取素材时长信息
# 获取素材时长信息,用于随机起始时间
asset_durations = None
if random_preview and self._asset_repo:
if self._asset_repo:
asset_durations = self._fetch_asset_durations(asset_ids)
self._distribute_assets(
clips,
+9 -10
View File
@@ -185,15 +185,17 @@ test.describe("Core generation flow", () => {
await expect(page.locator(".xx-choice-item.selected")).toBeVisible()
await page.getByRole("button", { name: "下一步" }).click()
// Step 2: select material
// Step 2: select material (card grid UI)
await expect(page.getByRole("heading", { name: /选择素材/ })).toBeVisible()
const librarySelect = page.locator("select").first()
await librarySelect.selectOption({ label: libraryName })
const materialLabel = page.getByText(sourceFileName).locator("..")
await expect(materialLabel.locator("input[type='checkbox']")).toBeVisible({
timeout: 10_000,
})
await materialLabel.locator("input[type='checkbox']").check()
// 新 UI: 素材以 9:16 竖屏卡片展示,点击卡片选中
// 注意:卡片中心是播放按钮(stopPropagation 会阻止选中),所以点击左上角避开
const materialCard = page.getByTestId("material-card").filter({ hasText: sourceFileName })
await expect(materialCard).toBeVisible({ timeout: 10_000 })
await materialCard.click({ position: { x: 15, y: 15 } })
// 验证选中:卡片应出现勾选标记(用 testid 定位,避免 ✓ 字符文本匹配不稳定)
await expect(materialCard.getByTestId("material-card-check")).toBeVisible({ timeout: 5_000 })
await page.getByRole("button", { name: "下一步" }).click()
// Step 3: voice (可选步骤,新注册用户无配音素材,直接跳过)
@@ -231,10 +233,7 @@ test.describe("Core generation flow", () => {
(response) => {
const url = response.url()
const path = new URL(url).pathname
return (
response.request().method() === "POST" &&
path.endsWith("/generation/tasks")
)
return response.request().method() === "POST" && path.endsWith("/generation/tasks")
},
{ timeout: 30_000 },
)
+22 -3
View File
@@ -37,14 +37,33 @@ async function loginWithRetry(
})
}
async function registerWithRetry(
request: APIRequestContext,
email: string,
username: string,
password: string,
displayName: string,
maxRetries = 2,
) {
for (let i = 0; i <= maxRetries; i++) {
const response = await request.post(`${apiBase}/auth/register`, {
data: { email, password, username, display_name: displayName },
})
if (response.status() !== 429) return response
console.log(`[register] 触发限流,等待 65s 后重试 (${i + 1}/${maxRetries})`)
await new Promise((r) => setTimeout(r, 65000))
}
return request.post(`${apiBase}/auth/register`, {
data: { email, password, username, display_name: displayName },
})
}
/** 注册并登录,返回 { headers, email, username, userId } */
async function createAuthedUser(request: APIRequestContext, label: string) {
const email = uniqueEmail(label)
const username = uniqueUsername(label)
const reg = await request.post(`${apiBase}/auth/register`, {
data: { email, password: PASSWORD, username, display_name: `E2E ${label}` },
})
const reg = await registerWithRetry(request, email, username, PASSWORD, `E2E ${label}`)
expect(reg.ok(), `注册应成功: ${await reg.text()}`).toBeTruthy()
const regData = await reg.json()
+12 -3
View File
@@ -4,11 +4,20 @@
import apiClient from "../client"
import type { BgmPreset, BgmPresetsQuery } from "./types"
/** 获取 BGM 预设列表 */
export const getBgmPresets = async (params?: BgmPresetsQuery): Promise<BgmPreset[]> => {
/**
* 获取 BGM 预设列表
* @param templateId 模板/草稿 ID
* @param params 分类/关键词筛选
*/
export const getBgmPresets = async (
templateId: string,
params?: BgmPresetsQuery,
): Promise<BgmPreset[]> => {
const searchParams: Record<string, string> = {}
if (params?.category) searchParams.category = params.category
if (params?.keyword) searchParams.keyword = params.keyword
const res = await apiClient.get("/bgm/presets", { params: searchParams })
const res = await apiClient.get(`/templates/${templateId}/editor/bgm/presets`, {
params: searchParams,
})
return res.data?.data ?? res.data ?? []
}
+13
View File
@@ -1,9 +1,22 @@
import apiClient from "../client"
export interface GenerateCoverTitleConfig {
text?: string
font?: string
font_size?: number
font_color?: string
position?: string
bold?: boolean
stroke?: boolean
shadow?: boolean
}
export interface GenerateCoverRequest {
asset_ids: string[]
cover_type?: "ai_frame" | "manual" | "upload" | "ai_regenerate"
frame_time?: number
/** 标题样式,用于在封面上叠加标题文字 */
title_config?: GenerateCoverTitleConfig
}
export interface GenerateCoverResponse {
+6
View File
@@ -13,6 +13,10 @@ export interface CreatePreviewRequest {
video_title?: string
duration?: number
video_ratio?: string
/** 输出视频宽度(与 video_ratio 匹配,如 9:16 → 1080 */
output_width?: number
/** 输出视频高度(与 video_ratio 匹配,如 9:16 → 1920 */
output_height?: number
/* 标题烧录配置(可选,传入后 ASS 渲染标题到预览视频中) */
title_config?: {
text?: string
@@ -38,6 +42,8 @@ export interface CreatePreviewResponse {
is_preview: boolean
resolution: string
created_at: string
/** 后端自动关联的编辑计划 ID(用于 fallback 路径传递 source_edit_plan_id */
source_edit_plan_id?: string
}
/** 预览任务详情响应 */
+7
View File
@@ -6,6 +6,7 @@ import apiClient from "../client"
import type {
CreateGenerationTaskRequest,
CreateGenerationTaskResponse,
GenerationTaskDetail,
TaskItem,
TaskListParams,
TaskListResponse,
@@ -19,6 +20,12 @@ export const createGenerationTask = async (
return data
}
/** 获取单个生成任务详情(轮询用) */
export const getGenerationTask = async (taskId: string): Promise<GenerationTaskDetail> => {
const { data } = await apiClient.get<GenerationTaskDetail>(`/generation/tasks/${taskId}`)
return data
}
/** 获取任务列表(支持分页和筛选) */
export const getTasks = async (params?: TaskListParams): Promise<TaskListResponse> => {
const { data } = await apiClient.get<TaskListResponse>("/tasks", {
+22 -2
View File
@@ -82,10 +82,20 @@ export interface CreateGenerationTaskRequest {
stroke?: boolean
shadow?: boolean
}
/** 关联的草稿 ID(编辑流程数据链路用) */
source_edit_plan_id?: string
/** 配音素材库 ID(用户上传的音频或 AI 配音素材) */
voice_library_id?: string
/** 自定义 BGM 配置,覆盖模板 BGM 设置 */
bgm_config?: {
enabled: boolean
preset_id?: string
volume?: number
}
}
/** 创建生成任务响应(对齐后端 GenerationTaskResponse */
export interface CreateGenerationTaskResponse {
/** 单个生成任务详情(对齐后端 GenerationTaskResponse */
export interface GenerationTaskDetail {
id: string
project_id: string
asset_library_id: string
@@ -95,8 +105,18 @@ export interface CreateGenerationTaskResponse {
asset_ids: string[]
title_ids: string[]
voice_ids: string[]
source_edit_plan_id?: string
status: string
progress: number
result_count: number
error_message: string
error_info?: TaskErrorInfo
created_at?: string | null
updated_at?: string | null
}
/** 创建生成任务响应(后端返回批量结构 {items, total} */
export interface CreateGenerationTaskResponse {
items: GenerationTaskDetail[]
total: number
}
+12 -1
View File
@@ -90,10 +90,21 @@ export async function createClipsFromAssets(
templateId: string,
assetIds: string[],
clipType = "main",
requiredClipsCount?: number,
opts?: { signal?: AbortSignal },
): Promise<ClipsFromAssetsResponse> {
const body: Record<string, unknown> = {
asset_ids: assetIds,
clip_type: clipType,
}
if (requiredClipsCount !== undefined) {
body.required_clips_count = requiredClipsCount
}
// from-assets 后端会调用 MediaKit 智能选片(最长 60s),单独延长超时
const response = await apiClient.post<ClipsFromAssetsResponse>(
`/templates/${templateId}/editor/clips/from-assets`,
{ asset_ids: assetIds, clip_type: clipType },
body,
{ timeout: 60000, signal: opts?.signal },
)
return response.data
}
+24 -62
View File
@@ -1,27 +1,8 @@
/**
* 模板草稿 CRUD + 生成相关 API
* 模板草稿 CRUD API
*/
import apiClient from "../client"
import type {
EditPlan,
EditPlanListParams,
EditPlanListResponse,
CreateEditPlanRequest,
UpdateEditPlanRequest,
GenerateResponse,
GenerationStatusResponse,
EditPlanGeneration,
GeneratedVideo,
CopyEditPlanRequest,
} from "./types"
/** 获取模板草稿列表(支持分页和筛选) */
export async function getEditPlans(params?: EditPlanListParams): Promise<EditPlanListResponse> {
const response = await apiClient.get<EditPlanListResponse>("/templates/drafts", {
params,
})
return response.data
}
import type { EditPlan, UpdateEditPlanRequest, GeneratedVideo } from "./types"
/** 获取单个模板草稿 */
export async function getEditPlan(templateId: string): Promise<EditPlan> {
@@ -29,63 +10,44 @@ export async function getEditPlan(templateId: string): Promise<EditPlan> {
return response.data
}
/** 创建模板草稿 */
export async function createEditPlan(data: CreateEditPlanRequest): Promise<EditPlan> {
const response = await apiClient.post("/templates/drafts", data)
return response.data
}
/** 更新模板草稿 */
/** 更新模板草稿(支持传入 AbortSignal 用于自动保存竞态取消) */
export async function updateEditPlan(
templateId: string,
data: UpdateEditPlanRequest,
signal?: AbortSignal,
): Promise<EditPlan> {
const response = await apiClient.put(`/templates/${templateId}/editor`, data)
const response = await apiClient.put(`/templates/${templateId}/editor`, data, { signal })
return response.data
}
/** 删除模板草稿 */
export async function deleteEditPlan(templateId: string): Promise<void> {
await apiClient.delete(`/templates/${templateId}/editor`)
}
/** 触发生成 */
export async function generateEditPlan(templateId: string): Promise<GenerateResponse> {
const response = await apiClient.post(`/templates/${templateId}/editor/generate`)
return response.data
}
/** 获取生成状态(轮询用) */
export async function getGenerationStatus(templateId: string): Promise<GenerationStatusResponse> {
const response = await apiClient.get(`/templates/${templateId}/editor/generation-status`)
return response.data
}
/** 获取模板草稿关联的生成记录 */
export async function getEditPlanGenerations(templateId: string): Promise<EditPlanGeneration[]> {
const response = await apiClient.get(`/templates/${templateId}/editor/generations`)
return response.data.items || []
}
/** 获取生成任务的视频结果列表 */
export async function getGenerationTaskResults(taskId: string): Promise<GeneratedVideo[]> {
const response = await apiClient.get(`/generation/tasks/${taskId}/results`)
return response.data.items || response.data || []
}
/** 取消生成任务 */
export async function cancelGeneration(templateId: string): Promise<void> {
await apiClient.post(`/templates/${templateId}/editor/cancel`)
/** ── 草稿 clips 批量更新 ── */
export interface EditPlanClipInput {
asset_id: string
start_time: number
duration: number
order: number
}
/** 复制模板草稿(含所有片段配置) */
export async function copyEditPlan(
/**
* 批量替换草稿的 clips(先全删再批量插入)
* 后端路由:PUT /templates/{template_id}/editor/clips
*/
export async function updateEditPlanClips(
templateId: string,
data?: CopyEditPlanRequest,
): Promise<EditPlan> {
const response = await apiClient.post<EditPlan>(
`/templates/${templateId}/editor/copy`,
data || {},
clips: EditPlanClipInput[],
signal?: AbortSignal,
): Promise<{ count: number }> {
const response = await apiClient.put(
`/templates/${templateId}/editor/clips`,
{ clips },
{ signal },
)
return response.data
}
+2 -15
View File
@@ -15,14 +15,8 @@ export type {
EditPlanSegment,
EditPlanConfig,
EditPlan,
CreateEditPlanRequest,
UpdateEditPlanRequest,
EditPlanListParams,
EditPlanListResponse,
GenerateResponse,
EditPlanGeneration,
ClipStatusItem,
GenerationStatusResponse,
GeneratedVideo,
AIRecommendRequest,
AIRecommendClipItem,
@@ -37,7 +31,6 @@ export type {
ClipReorderResponse,
ClipBatchDeleteResponse,
ClipsFromAssetsResponse,
CopyEditPlanRequest,
TransitionEffect,
MediaAsset,
} from "./types"
@@ -53,18 +46,12 @@ export {
// 模板草稿 CRUD + 生成
export {
getEditPlans,
getEditPlan,
createEditPlan,
updateEditPlan,
deleteEditPlan,
generateEditPlan,
getGenerationStatus,
getEditPlanGenerations,
updateEditPlanClips,
getGenerationTaskResults,
cancelGeneration,
copyEditPlan,
} from "./editPlans"
export type { EditPlanClipInput } from "./editPlans"
// 片段 CRUD + 批量操作
export {
+11 -38
View File
@@ -114,10 +114,19 @@ export interface EditPlanConfig {
auto_subtitles?: boolean
/** 是否启用 BGM */
bgm?: boolean
/** 生成数量 */
generate_count?: number
/** 素材模式 */
material_mode?: string
/** 前端标题设置(Step4 自动保存,与 title_config 字段分离,不影响后端渲染) */
title?: {
text?: string
font?: string
font_size?: number
color?: string
position?: string
bold?: boolean
stroke?: boolean
shadow?: boolean
}
/** 预览视频 URL(封面生成用) */
rendered_storage_key?: string
/** 生成任务 ID */
@@ -176,31 +185,6 @@ export interface EditPlanListResponse {
/* ── 生成相关 ── */
/** 生成响应 */
export interface GenerateResponse {
plan_id: string
plan_status: EditPlanStatus
generation_task_id: string
clip_count: number
}
/** 模板草稿关联的生成记录 */
export interface EditPlanGeneration {
id: string
source_edit_plan_id: string
template_id: string
asset_ids: string[]
status: EditPlanStatus
progress: number
result_count: number
error_message: string
error_info: Record<string, unknown>
logs: Array<Record<string, unknown>>
retry_count: number
created_at?: string
updated_at?: string
}
/** 片段生成状态 */
export interface ClipStatusItem {
clip_id: string
@@ -213,17 +197,6 @@ export interface ClipStatusItem {
error_message?: string
}
/** 生成状态轮询响应 */
export interface GenerationStatusResponse {
plan_id: string
plan_status: EditPlanStatus
generation_task_id?: string
error_message?: string
clips: ClipStatusItem[]
error?: string
message?: string
}
/** 生成视频详情 */
export interface GeneratedVideo {
id: string
-3
View File
@@ -9,8 +9,6 @@ export type {
TemplateSegment,
TemplateListParams,
TemplateListResponse,
GenerateFromTemplateRequest,
GenerateFromTemplateResponse,
CopyTemplateResponse,
} from "./types"
@@ -24,5 +22,4 @@ export {
getTemplate,
toggleFavoriteTemplate,
copyTemplate,
generateFromTemplate,
} from "./templates"
-14
View File
@@ -5,8 +5,6 @@
import apiClient from "../client"
import type {
CopyTemplateResponse,
GenerateFromTemplateRequest,
GenerateFromTemplateResponse,
TemplateItem,
TemplateListParams,
TemplateListResponse,
@@ -45,15 +43,3 @@ export const copyTemplate = async (templateId: string): Promise<CopyTemplateResp
const response = await apiClient.post<CopyTemplateResponse>(`/templates/${templateId}/copy`)
return response.data
}
/** 从模板生成 */
export const generateFromTemplate = async (
templateId: string,
data?: GenerateFromTemplateRequest,
): Promise<GenerateFromTemplateResponse> => {
const response = await apiClient.post<GenerateFromTemplateResponse>(
`/templates/${templateId}/generate`,
data,
)
return response.data
}
+2 -2
View File
@@ -71,7 +71,7 @@ export const NAV_ITEMS: NavItem[] = [
},
{
key: "editing-planner",
label: "剪辑编辑器",
label: "剪辑模板",
path: "/app/editing-planner",
icon: React.createElement(EditOutlined),
},
@@ -133,7 +133,7 @@ export const NAV_GROUPS: NavGroup[] = [
},
{
key: "editing-planner",
label: "剪辑编辑器",
label: "剪辑模板",
path: "/app/editing-planner",
icon: React.createElement(EditOutlined),
},
@@ -15,8 +15,6 @@ import React, { useState } from "react"
import { useSearchParams } from "react-router-dom"
import { MODE_LABELS } from "@/api/editing-planner"
import { MODE_LIST } from "./constants"
import type { MediaAsset } from "@/api/template-editor"
import MediaPanel from "./components/MediaPanel"
import PreviewPlayer from "./components/PreviewPlayer"
import TimelinePanel from "./components/TimelinePanel"
@@ -79,14 +77,6 @@ const EditingPlanner: React.FC = () => {
/* ── 右侧栏 Tab ── */
const [rightTab, setRightTab] = useState<"properties" | "clips">("properties")
/* ── 素材库 ── */
const [mediaAssets, setMediaAssets] = useState<MediaAsset[]>([])
const [selectedAssetIds, setSelectedAssetIds] = useState<string[]>([])
const handleAssetSelect = (ids: string[]) => {
setSelectedAssetIds(ids)
}
/* ── 配音素材 ── */
const {
voiceMaterials,
@@ -113,7 +103,6 @@ const EditingPlanner: React.FC = () => {
resetClips,
setClips,
setSelectedClipId: clipOps.setSelectedClipId,
setMediaAssets,
setTitleConfig,
setSubtitleSettings,
setBgmSettings,
@@ -164,9 +153,6 @@ const EditingPlanner: React.FC = () => {
onLoadTemplate={tpl.handleLoadTemplate}
onSearchChange={tpl.setSearchQuery}
onFilterChange={tpl.setCurrentFilter}
mediaAssets={mediaAssets}
onAssetSelect={handleAssetSelect}
selectedAssetIds={selectedAssetIds}
/>
{/* 中栏 flex-1 */}
@@ -1,116 +0,0 @@
/**
* 生成历史弹窗 — 展示当前模板草稿的生成任务记录
* 从 EditingPlanner 拆分,避免主文件过大
*/
import React from "react"
import { CloseOutlined, InboxOutlined } from "@ant-design/icons"
import type { EditPlanGeneration } from "@/api/template-editor"
import { PLAN_STATUS_LABELS } from "@/api/template-editor"
interface GenerationHistoryModalProps {
open: boolean
loading: boolean
history: EditPlanGeneration[]
onClose: () => void
onCancel?: (taskId: string) => void
cancelLoading?: boolean
}
const GenerationHistoryModal: React.FC<GenerationHistoryModalProps> = ({
open,
loading,
history,
onClose,
onCancel,
cancelLoading,
}) => {
if (!open) return null
return (
<div className="ep-modal-overlay" onClick={onClose}>
<div className="ep-modal ep-gh-modal" onClick={(e) => e.stopPropagation()}>
<div className="ep-modal-header">
<h3></h3>
<button className="ep-modal-close" onClick={onClose}>
<CloseOutlined />
</button>
</div>
<div className="ep-modal-body ep-gh-body">
{loading ? (
<div className="ep-gh-empty">
<div className="ep-skeleton">
<div className="ep-skeleton-item ep-skeleton-item--header" />
<div className="ep-skeleton-item" />
<div className="ep-skeleton-item" />
<div className="ep-skeleton-item" />
</div>
</div>
) : history.length === 0 ? (
<div className="ep-gh-empty">
<InboxOutlined style={{ fontSize: 32, opacity: 0.4 }} />
<span></span>
</div>
) : (
<table className="ep-gh-table">
<thead>
<tr className="ep-gh-table-header-row">
<th className="ep-gh-th">ID</th>
<th className="ep-gh-th"></th>
<th className="ep-gh-th"></th>
<th className="ep-gh-th"></th>
{onCancel && <th className="ep-gh-th"></th>}
</tr>
</thead>
<tbody>
{history.map((gen) => {
const statusClass = `ep-gh-status-tag--${gen.status}`
const canCancel = gen.status === "rendering" || gen.status === "editing"
return (
<tr key={gen.id} className="ep-gh-table-row">
<td className="ep-gh-td ep-gh-td-id">
{gen.id ? `${gen.id.slice(0, 8)}...` : "—"}
</td>
<td className="ep-gh-td">
<span className={`ep-gh-status-tag ${statusClass}`}>
{PLAN_STATUS_LABELS[gen.status] || gen.status}
</span>
</td>
<td className="ep-gh-td ep-gh-td-time">
{gen.created_at ? new Date(gen.created_at).toLocaleString("zh-CN") : "—"}
</td>
<td className="ep-gh-td ep-gh-td-time">
{gen.updated_at ? new Date(gen.updated_at).toLocaleString("zh-CN") : "—"}
</td>
{onCancel && (
<td className="ep-gh-td ep-gh-td-action">
{canCancel ? (
<button
className="ep-gh-cancel-btn"
onClick={() => onCancel(gen.id)}
disabled={cancelLoading}
>
</button>
) : (
<span className="ep-gh-action-placeholder"></span>
)}
</td>
)}
</tr>
)
})}
</tbody>
</table>
)}
</div>
<div className="ep-modal-footer">
<button className="ep-btn ep-btn-secondary" onClick={onClose}>
</button>
</div>
</div>
</div>
)
}
export default GenerationHistoryModal
@@ -1,6 +0,0 @@
/**
* 生成进度弹窗 — 入口文件(向后兼容)
* 实际实现已移至 ./generation-progress-modal/ 目录
*/
export { default } from "./generation-progress-modal"
export type { GenPhase, GenerationProgressModalProps } from "./generation-progress-modal"
@@ -1,12 +1,10 @@
/**
* 左侧面板 — V8 原型 1:1 还原
* Tab 切换:模板列表 + 素材库
* 左侧面板 — 模板列表
* 模板编辑器只负责定义模板规则(片段数量、时长范围),不承载素材管理。
*/
import React, { useState } from "react"
import React from "react"
import type { EditingTemplate } from "@/api/editing-planner"
import { MODE_LABELS } from "@/api/editing-planner"
import type { MediaAsset } from "@/api/template-editor"
import AssetSelector from "@/components/asset-selector/AssetSelector"
interface MediaPanelProps {
templates: EditingTemplate[]
@@ -18,10 +16,6 @@ interface MediaPanelProps {
onLoadTemplate: (id: string) => void
onSearchChange: (q: string) => void
onFilterChange: (f: string) => void
// 素材相关
mediaAssets?: MediaAsset[]
onAssetSelect?: (ids: string[]) => void
selectedAssetIds?: string[]
}
const MediaPanel: React.FC<MediaPanelProps> = ({
@@ -34,113 +28,73 @@ const MediaPanel: React.FC<MediaPanelProps> = ({
onLoadTemplate,
onSearchChange,
onFilterChange,
mediaAssets = [],
onAssetSelect,
selectedAssetIds = [],
}) => {
const [activeTab, setActiveTab] = useState<"templates" | "assets">("templates")
return (
<div className="ep-left-panel">
{/* Tab 切换 */}
<div className="ep-left-tabs">
<button
className={`ep-left-tab ${activeTab === "templates" ? "active" : ""}`}
onClick={() => setActiveTab("templates")}
>
📋
</button>
<button
className={`ep-left-tab ${activeTab === "assets" ? "active" : ""}`}
onClick={() => setActiveTab("assets")}
>
📁
</button>
{/* 搜索 */}
<div className="ep-search-wrap ep-media-panel-inner">
<span className="ep-search-icon">🔍</span>
<input
className="ep-search-input"
placeholder="搜索模板..."
value={searchQuery}
onChange={(e) => onSearchChange(e.target.value)}
/>
</div>
{/* 模板 Tab */}
{activeTab === "templates" && (
<>
{/* 搜索 */}
<div className="ep-search-wrap ep-media-panel-inner">
<span className="ep-search-icon">🔍</span>
<input
className="ep-search-input"
placeholder="搜索模板..."
value={searchQuery}
onChange={(e) => onSearchChange(e.target.value)}
/>
</div>
{/* Chip 分类筛选 */}
<div className="ep-filter-chips">
{filterCategories.map((cat) => (
<button
key={cat}
className={`ep-filter-chip ${currentFilter === cat ? "active" : ""}`}
onClick={() => onFilterChange(cat)}
>
{cat}
</button>
))}
</div>
{/* Chip 分类筛选 */}
<div className="ep-filter-chips">
{filterCategories.map((cat) => (
<button
key={cat}
className={`ep-filter-chip ${currentFilter === cat ? "active" : ""}`}
onClick={() => onFilterChange(cat)}
>
{cat}
</button>
))}
{/* 模板列表 */}
<div className="ep-template-list">
{loading ? (
<div className="ep-loading">
<span></span>
<span>...</span>
</div>
{/* 模板列表 */}
<div className="ep-template-list">
{loading ? (
<div className="ep-loading">
<span></span>
<span>...</span>
) : templates.length === 0 ? (
<div className="ep-empty">
<span>📭</span>
<span></span>
</div>
) : (
templates.map((tpl) => (
<div
key={tpl.id}
className={`ep-template-card ${loadedTemplateId === tpl.id ? "active" : ""}`}
onClick={() => onLoadTemplate(tpl.id)}
>
<div className="ep-template-card-header">
<span className="ep-template-card-name">{tpl.name}</span>
<span className="ep-template-card-mode">{MODE_LABELS[tpl.mode]}</span>
</div>
) : templates.length === 0 ? (
<div className="ep-empty">
<span>📭</span>
<span></span>
<div className="ep-template-card-meta">
<span> {tpl.estimated_duration}s</span>
<span>📐 {tpl.segments.length}</span>
</div>
) : (
templates.map((tpl) => (
<div
key={tpl.id}
className={`ep-template-card ${loadedTemplateId === tpl.id ? "active" : ""}`}
onClick={() => onLoadTemplate(tpl.id)}
>
<div className="ep-template-card-header">
<span className="ep-template-card-name">{tpl.name}</span>
<span className="ep-template-card-mode">{MODE_LABELS[tpl.mode]}</span>
</div>
<div className="ep-template-card-meta">
<span> {tpl.estimated_duration}s</span>
<span>📐 {tpl.segments.length}</span>
</div>
{tpl.tags.length > 0 && (
<div className="ep-template-card-tags">
{tpl.tags.map((tag) => (
<span key={tag} className="ep-template-tag">
{tag}
</span>
))}
</div>
)}
{tpl.tags.length > 0 && (
<div className="ep-template-card-tags">
{tpl.tags.map((tag) => (
<span key={tag} className="ep-template-tag">
{tag}
</span>
))}
</div>
))
)}
</div>
</>
)}
{/* 素材 Tab */}
{activeTab === "assets" && (
<div className="ep-assets-tab">
<AssetSelector
assets={mediaAssets}
selectedIds={selectedAssetIds}
onSelectionChange={onAssetSelect}
showQualityFilter={false}
showBatchSelect={false}
compact
/>
</div>
)}
)}
</div>
))
)}
</div>
</div>
)
}
@@ -16,9 +16,17 @@ interface BgmSelectorProps {
onClose: () => void
config: BgmMixConfig
onChange: (config: BgmMixConfig) => void
/** 模板/草稿 ID,用于请求 BGM 预设 */
templateId?: string
}
const BgmSelector: React.FC<BgmSelectorProps> = ({ open, onClose, config, onChange }) => {
const BgmSelector: React.FC<BgmSelectorProps> = ({
open,
onClose,
config,
onChange,
templateId,
}) => {
const {
presets,
loading,
@@ -30,7 +38,7 @@ const BgmSelector: React.FC<BgmSelectorProps> = ({ open, onClose, config, onChan
loadPresets,
handlePreview,
stopPreview,
} = useBgmSelector(open)
} = useBgmSelector(open, templateId)
/* ── 选中 BGM ── */
const handleSelect = useCallback(
@@ -19,7 +19,7 @@ export const CATEGORY_LIST: {
* BGM 选择器数据与交互 Hook
* 封装列表加载、搜索、分类筛选、试听播放逻辑
*/
export function useBgmSelector(open: boolean) {
export function useBgmSelector(open: boolean, templateId?: string) {
const [presets, setPresets] = useState<BgmPreset[]>([])
const [loading, setLoading] = useState(false)
const [activeCategory, setActiveCategory] = useState<BgmCategory | "all">("all")
@@ -30,19 +30,23 @@ export function useBgmSelector(open: boolean) {
/* ── 加载 BGM 列表 ── */
const loadPresets = useCallback(async () => {
if (!templateId) {
setPresets([])
return
}
setLoading(true)
try {
const params: { category?: string; keyword?: string } = {}
if (activeCategory !== "all") params.category = activeCategory
if (keyword.trim()) params.keyword = keyword.trim()
const data = await getBgmPresets(params)
const data = await getBgmPresets(templateId, params)
setPresets(data)
} catch {
message.error("加载 BGM 列表失败")
} finally {
setLoading(false)
}
}, [activeCategory, keyword])
}, [activeCategory, keyword, templateId])
useEffect(() => {
if (open) loadPresets()
@@ -1,65 +0,0 @@
import React from "react"
import { Modal } from "@/components/ui"
import type { TaskItem } from "@/api/tasks"
import { getStepLabel, getStatusColor } from "./constants"
interface ProgressPhaseProps {
open: boolean
task: TaskItem | null
onCancel: () => void
}
/** progress(进度轮询)阶段弹窗 */
export const ProgressPhase: React.FC<ProgressPhaseProps> = ({ open, task, onCancel }) => {
const progress = task?.progress ?? 0
const status = task?.status ?? ""
const currentStep = task?.current_step ?? ""
const userMessage = task?.user_message ?? ""
const stepColor = getStatusColor(status, currentStep)
return (
<Modal open={open} title="视频生成中" footer={null} onCancel={onCancel} closable width={480}>
<div className="ep-gen-progress">
{/* 进度环 */}
<div className="ep-gen-progress-ring-wrap">
<svg className="ep-gen-progress-ring" viewBox="0 0 120 120">
<circle className="ep-gen-progress-ring-bg" cx="60" cy="60" r="52" />
<circle
className="ep-gen-progress-ring-fill"
cx="60"
cy="60"
r="52"
style={{
strokeDasharray: `${2 * Math.PI * 52}`,
strokeDashoffset: `${2 * Math.PI * 52 * (1 - progress / 100)}`,
stroke: stepColor,
}}
/>
</svg>
<span className="ep-gen-progress-pct" style={{ color: stepColor }}>
{progress}%
</span>
</div>
{/* 当前步骤 */}
<div className="ep-gen-step-text">
{userMessage || getStepLabel(currentStep) || "处理中…"}
</div>
{/* 进度条 */}
<div className="ep-gen-progress-bar">
<div
className="ep-gen-progress-bar-fill"
style={{
width: `${progress}%`,
backgroundColor: stepColor,
}}
/>
</div>
{/* 任务 ID */}
{task?.id && <div className="ep-gen-task-id"> ID: {task.id}</div>}
</div>
</Modal>
)
}
@@ -1,82 +0,0 @@
import React from "react"
import { Modal, Button } from "@/components/ui"
import type { TaskItem } from "@/api/tasks"
interface ResultPhaseProps {
open: boolean
phase: "completed" | "failed"
task: TaskItem | null
onCancel: () => void
onRetry?: () => void
onClose?: () => void
}
/** completed / failed(结果)阶段弹窗 */
export const ResultPhase: React.FC<ResultPhaseProps> = ({
open,
phase,
task,
onCancel,
onRetry,
onClose,
}) => {
const userMessage = task?.user_message ?? ""
const errorMessage = task?.error_message ?? ""
const retryable = task?.retryable ?? false
const handleClose = onClose || onCancel
if (phase === "completed") {
return (
<Modal
open={open}
title="✅ 生成完成"
footer={null}
onCancel={handleClose}
closable
width={440}
>
<div className="ep-gen-result">
<div className="ep-gen-result-icon">🎉</div>
<div className="ep-gen-result-title"></div>
{userMessage && <div className="ep-gen-result-msg">{userMessage}</div>}
<div className="ep-gen-result-actions">
<Button buttonType="primary" onClick={handleClose}>
</Button>
</div>
</div>
</Modal>
)
}
return (
<Modal
open={open}
title="❌ 生成失败"
footer={null}
onCancel={handleClose}
closable
width={440}
>
<div className="ep-gen-result ep-gen-result--error">
<div className="ep-gen-result-icon">😥</div>
<div className="ep-gen-result-title"></div>
{(errorMessage || userMessage) && (
<div className="ep-gen-result-msg ep-gen-result-msg--error">
{errorMessage || userMessage}
</div>
)}
<div className="ep-gen-result-actions">
{retryable && onRetry && (
<Button buttonType="primary" onClick={onRetry}>
🔄
</Button>
)}
<Button buttonType="secondary" onClick={handleClose}>
</Button>
</div>
</div>
</Modal>
)
}
@@ -1,53 +0,0 @@
import React from "react"
import { Modal } from "@/components/ui"
interface SetupPhaseProps {
open: boolean
voiceoverDuration: number | null
estimatedDuration: number
submitting: boolean
onDurationChange: (v: number | null) => void
onGenerate: () => void
onCancel: () => void
}
/** setup(配置)阶段弹窗 */
export const SetupPhase: React.FC<SetupPhaseProps> = ({
open,
voiceoverDuration,
estimatedDuration,
submitting,
onDurationChange,
onGenerate,
onCancel,
}) => (
<Modal
open={open}
title="使用模板生成视频"
confirmLoading={submitting}
onOk={onGenerate}
onCancel={onCancel}
okText="开始生成"
cancelText="取消"
width={440}
>
<div className="ep-gen-setup">
<label className="ep-gen-field-label"></label>
<input
type="number"
className="ep-gen-duration-input"
placeholder="请输入配音时长"
value={voiceoverDuration ?? ""}
onChange={(e) => {
const v = e.target.value ? Number(e.target.value) : null
onDurationChange(v)
}}
min={1}
max={600}
/>
<div className="ep-gen-estimate">
<strong>{estimatedDuration}s</strong>
</div>
</div>
</Modal>
)
@@ -1,31 +0,0 @@
/* ──────────── 步骤文案映射 ──────────── */
export const STEP_LABELS: Record<string, string> = {
queued: "排队中…",
preparing: "准备素材…",
generating_video: "渲染视频中…",
adding_effects: "添加特效…",
composing: "合成中…",
encoding: "编码输出中…",
completed: "生成完成!",
failed: "生成失败",
}
export const getStepLabel = (step: string) => STEP_LABELS[step] || step.replace(/_/g, " ")
/* ──────────── 状态徽标颜色 ──────────── */
export const STATUS_COLOR: Record<string, string> = {
queued: "#6b7280",
pending: "#6b7280",
preparing: "#f59e0b",
generating_video: "#4f46e5",
adding_effects: "#7c3aed",
composing: "#2563eb",
encoding: "#0891b2",
completed: "#10b981",
failed: "#ef4444",
}
export const getStatusColor = (status: string, currentStep: string) =>
STATUS_COLOR[status] || STATUS_COLOR[currentStep] || "#4f46e5"
@@ -1,70 +0,0 @@
/**
* 生成进度弹窗 — 任务 2.17
* 三阶段 UIsetup(配置)→ progress(进度轮询)→ completed / failed(结果)
* V21 设计系统,CSS 类名前缀 ep-gen-
*/
import React, { useEffect, useRef } from "react"
import type { GenPhase, GenerationProgressModalProps } from "./types"
import { SetupPhase } from "./SetupPhase"
import { ProgressPhase } from "./ProgressPhase"
import { ResultPhase } from "./ResultPhase"
/* 重新导出类型,保持向后兼容 */
export type { GenPhase, GenerationProgressModalProps }
const GenerationProgressModal: React.FC<GenerationProgressModalProps> = ({
open,
phase,
voiceoverDuration,
estimatedDuration,
onDurationChange,
onGenerate,
task,
submitting,
onCancel,
onRetry,
onClose,
}) => {
/* 关闭弹窗时重置(避免下次打开残留旧状态) */
const prevOpen = useRef(false)
useEffect(() => {
if (prevOpen.current && !open) {
/* modal just closed — parent handles reset */
}
prevOpen.current = open
}, [open])
/* setup 阶段 */
if (phase === "setup") {
return (
<SetupPhase
open={open}
voiceoverDuration={voiceoverDuration}
estimatedDuration={estimatedDuration}
submitting={submitting}
onDurationChange={onDurationChange}
onGenerate={onGenerate}
onCancel={onCancel}
/>
)
}
/* progress 阶段 */
if (phase === "progress") {
return <ProgressPhase open={open} task={task} onCancel={onCancel} />
}
/* completed / failed 阶段 */
return (
<ResultPhase
open={open}
phase={phase as "completed" | "failed"}
task={task}
onCancel={onCancel}
onRetry={onRetry}
onClose={onClose}
/>
)
}
export default GenerationProgressModal
@@ -1,23 +0,0 @@
import type { TaskItem } from "@/api/tasks"
export type GenPhase = "setup" | "progress" | "completed" | "failed"
export interface GenerationProgressModalProps {
open: boolean
phase: GenPhase
/* setup 阶段 */
voiceoverDuration: number | null
estimatedDuration: number
onDurationChange: (v: number | null) => void
onGenerate: () => void
/* progress / 结果阶段 */
task: TaskItem | null
/* 通用 */
submitting: boolean
onCancel: () => void
onRetry?: () => void
onClose?: () => void
}
@@ -6,16 +6,13 @@ import {
type EditingTemplate,
type TemplateCategory,
} from "@/api/editing-planner"
import { getMediaAssets, type MediaAsset } from "@/api/template-editor"
import { FILTER_CATEGORIES } from "../../constants"
/**
* 模板列表 + 分类 + 筛选搜索
* 模板编辑器只负责模板规则定义,不再加载/管理业务素材。
*/
export function useTemplateList(
setMediaAssets: (assets: MediaAsset[]) => void,
initialTemplateId: string | null,
) {
export function useTemplateList(initialTemplateId: string | null) {
const [templates, setTemplates] = useState<EditingTemplate[]>([])
const [categories, setCategories] = useState<TemplateCategory[]>([])
const [loadingTemplates, setLoadingTemplates] = useState(false)
@@ -24,26 +21,20 @@ export function useTemplateList(
const [loadedTemplateId, setLoadedTemplateId] = useState<string | null>(initialTemplateId)
/**
* 并行加载模板列表分类、素材库
* 三个接口无依赖关系,用 Promise.all 并发
* 并行加载模板列表分类(两者无依赖关系)
*/
const loadTemplates = useCallback(async () => {
setLoadingTemplates(true)
try {
const [tpls, cats, assets] = await Promise.all([
getEditingTemplates(),
getTemplateCategories(),
getMediaAssets(),
])
const [tpls, cats] = await Promise.all([getEditingTemplates(), getTemplateCategories()])
setTemplates(tpls)
setCategories(cats)
setMediaAssets(assets)
} catch {
message.error("加载模板失败")
} finally {
setLoadingTemplates(false)
}
}, [setMediaAssets])
}, [])
useEffect(() => {
loadTemplates()
@@ -1,6 +1,6 @@
import { useState, useCallback, type Dispatch, type SetStateAction } from "react"
import type { TemplateMode } from "@/api/editing-planner"
import type { MediaAsset, TitleConfig } from "@/api/template-editor"
import type { TitleConfig } from "@/api/template-editor"
import type {
ClipData,
WatermarkConfig,
@@ -24,7 +24,6 @@ interface UseTemplateManagementParams {
resetClips: (clips: ClipData[]) => void
setClips: (updater: (prev: ClipData[]) => ClipData[]) => void
setSelectedClipId: (id: string | null) => void
setMediaAssets: (assets: MediaAsset[]) => void
setTitleConfig: Dispatch<SetStateAction<TitleConfig>>
setSubtitleSettings: Dispatch<SetStateAction<SubtitleStyleConfig>>
setBgmSettings: Dispatch<SetStateAction<BgmMixConfig>>
@@ -52,7 +51,6 @@ export const useTemplateManagement = (params: UseTemplateManagementParams) => {
resetClips,
setClips,
setSelectedClipId,
setMediaAssets,
setTitleConfig,
setSubtitleSettings,
setBgmSettings,
@@ -86,7 +84,7 @@ export const useTemplateManagement = (params: UseTemplateManagementParams) => {
filteredTemplates,
currentTemplate,
loadTemplates,
} = useTemplateList(setMediaAssets, urlTemplateId || null)
} = useTemplateList(urlTemplateId || null)
/* ── 保存 ── */
const {
+137 -97
View File
@@ -1,30 +1,27 @@
/**
* 智能剪辑页面 — V24 前端预览播放器架构改造
* 智能剪辑页面 — 前端实时预览架构
* 7 步向导:选择模板 → 素材 → 配音 → 标题 → 预览 → 封面 → 确认生成
* 左右布局:左侧 generate-form + 右侧 generate-preview
*
* 架构改造
* - Step5 预览改为前端素材切片播放(FrontendPreviewPlayer
* - 完全去除后端 FFmpeg 预览依赖
* - 标题样式通过 CSS 层实时叠加,所见即所得
* - 最终成片仍走后端 FFmpeg 渲染(Step7 确认生成)
* 架构:
* - 步骤 4-6 右侧显示 FrontendPreviewPlayer 实时预览
* - 步骤 7 右侧内联播放生成的最终视频
* - 点"确认生成"时调用 createGenerationTask 创建一次服务器渲染任务
*/
import React, { useMemo } from "react"
import { Modal, message } from "antd"
import React, { useMemo, useState, useEffect, useRef } from "react"
import { message } from "antd"
import { useNavigate } from "react-router-dom"
import type { VoiceClone } from "@/api/voice-clone"
import { useQuery } from "@tanstack/react-query"
import { useCloneProgress } from "@/hooks/useCloneProgress"
import { getAssetsByKind } from "@/api/assets"
import CloneModal from "@/components/voice/CloneModal"
import GenerateHeader from "./components/GenerateHeader"
import {
calculateTotalVideoDuration,
estimateTotalVideoDuration,
} from "./utils/calculateTotalVideoDuration"
import FrontendPreviewPlayer from "./components/FrontendPreviewPlayer"
import GenerateStepsBar from "./components/GenerateStepsBar"
import GenerateResultPanel from "./components/GenerateResultPanel"
import PreviewVideoPanel from "./components/PreviewVideoPanel"
import GenerateStepContent from "./components/GenerateStepContent"
import GenerateStepActions from "./components/GenerateStepActions"
import { useGenerateFormState } from "./hooks/useGenerateFormState"
@@ -32,6 +29,8 @@ import { useStepNavigation } from "./hooks/useStepNavigation"
import { useGenerateVideo } from "./hooks/useGenerateVideo"
import { usePreviewAssets } from "./hooks/usePreviewAssets"
import { useTitleStyleUpdaters } from "./hooks/useStep4Title/useTitleStyleUpdaters"
import { getAssetsByKind } from "@/api/assets"
import { previewTts } from "@/api/tts"
import "./generate.css"
const GeneratePage: React.FC = () => {
@@ -64,26 +63,74 @@ const GeneratePage: React.FC = () => {
presetVoices,
cloneModalOpen,
setCloneModalOpen,
generateCount,
setGenerateCount,
videoRatio,
duration,
style,
autoSubtitles,
bgm,
editPlanId,
previewVideo,
setPreviewVideo,
previewModalOpen,
setPreviewModalOpen,
sourceEditPlanId,
previewTaskId,
setPreviewTaskId,
storedSourceEditPlanId,
setStoredSourceEditPlanId,
serverClips,
setServerClips,
} = formState
/* ── 标题样式回调(Step5 样式面板 + 右侧预览 CSS 层共用) ── */
/* ── 标题样式回调 ── */
const styleUpdaters = useTitleStyleUpdaters({
titleSettings,
onTitleSettingsChange: setTitleSettings,
})
/* ── 配音素材库(TTS 试听)── */
const { data: voiceMaterials = [] } = useQuery({
queryKey: ["assets", "voice"],
queryFn: () => getAssetsByKind("voice", { limit: 50 }),
})
const [previewVoiceAudioUrl, setPreviewVoiceAudioUrl] = useState<string | null>(null)
const ttsAbortRef = useRef<AbortController | null>(null)
useEffect(() => {
const voiceAsset = voiceMaterials.find((m) => m.id === selectedVoice)
if (voiceAsset?.file_url) {
setPreviewVoiceAudioUrl(voiceAsset.file_url)
return
}
const voiceId = selectedClonedVoice || selectedVoice
if (!voiceId || !titleSettings.title) {
setPreviewVoiceAudioUrl(null)
return
}
ttsAbortRef.current?.abort()
const controller = new AbortController()
ttsAbortRef.current = controller
let cancelled = false
previewTts({ text: titleSettings.title, voice_id: voiceId })
.then((res) => {
if (!cancelled && res.audio_url) {
setPreviewVoiceAudioUrl(res.audio_url)
}
})
.catch((err) => {
if (!cancelled) {
console.warn("[预览配音生成失败]", err)
setPreviewVoiceAudioUrl(null)
}
})
return () => {
cancelled = true
controller.abort()
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [selectedVoice, selectedClonedVoice, titleSettings.title, voiceMaterials])
/* ── 克隆声音 ── */
const { clones: clonedVoices, addClone, hasProcessing } = useCloneProgress()
@@ -93,44 +140,38 @@ const GeneratePage: React.FC = () => {
message.success("音色克隆成功!")
}
/* ── 前端预览:加载选中素材的视频文件信息 ── */
/* ── 素材 ID 列表 ── */
const previewAssetIds = useMemo(
() => (materialMode === "auto" ? smartSelectedIds : selectedMaterials),
[materialMode, smartSelectedIds, selectedMaterials],
)
const previewAssetsEnabled = currentStep >= 4 && previewAssetIds.length > 0
const {
assets: previewAssets,
loading: previewAssetsLoading,
ready: previewAssetsReady,
} = usePreviewAssets(previewAssetIds, previewAssetsEnabled)
/* ── 当前模板对象(传给前端预览播放器) ── */
/* ── 当前模板对象 ── */
const currentTemplate = useMemo(
() => userTemplates.find((t) => t.id === selectedTemplate) || null,
[userTemplates, selectedTemplate],
)
/* ── 视频总时长计算(用于配音时长校验) ── */
/* ── BGM 配置 ── */
const bgmConfig = useMemo(
() => ({
enabled: bgm,
music_id: currentTemplate?.bgm_config?.music_id || "",
}),
[bgm, currentTemplate],
)
/* ── 加载素材详情(供前端预览播放器使用 + 配音时长校验) ── */
const previewAssetsEnabled = previewAssetIds.length > 0
const { assets: previewAssets } = usePreviewAssets(previewAssetIds, previewAssetsEnabled)
/* ── 视频总时长计算 ── */
const totalVideoDuration = useMemo(() => {
// 优先用素材精确时长;素材未加载时用模板 segments 的 duration_max 之和估算
const exact = calculateTotalVideoDuration(previewAssets, currentTemplate ?? undefined)
if (exact > 0) return exact
return estimateTotalVideoDuration(currentTemplate ?? undefined)
}, [previewAssets, currentTemplate])
/* ── 配音音频 URL ── */
const { data: voiceMaterials = [] } = useQuery({
queryKey: ["assets", "voice"],
queryFn: () => getAssetsByKind("voice", { limit: 50 }),
})
const voiceAudioUrl = useMemo(() => {
if (!selectedVoice) return undefined
const asset = voiceMaterials.find((v) => v.id === selectedVoice)
return asset?.file_url || undefined
}, [selectedVoice, voiceMaterials])
/* ── 步骤导航 ── */
const { goNext, goPrev } = useStepNavigation({
currentStep,
@@ -140,7 +181,6 @@ const GeneratePage: React.FC = () => {
selectedMaterials,
smartSelectedIds,
titleSettings,
previewReady: previewAssetsReady,
})
/* ── 视频生成核心逻辑 ── */
@@ -170,23 +210,26 @@ const GeneratePage: React.FC = () => {
duration,
autoSubtitles,
bgm,
generateCount,
sourceEditPlanId: storedSourceEditPlanId || sourceEditPlanId,
previewTaskId,
bgmConfig,
onGenerationSuccess: () => {
setPreviewTaskId(null)
setStoredSourceEditPlanId(null)
},
})
/* ================================================================
渲染 — 主页面
渲染
================================================================ */
return (
<div className="xx-generate-page">
{/* ── 页头 ── */}
<GenerateHeader fromEditPlan={!!editPlanId} />
{/* ── 步骤条 ── */}
<GenerateStepsBar currentStep={currentStep} onStepClick={setCurrentStep} />
{/* ── 主布局 ── */}
<div className="xx-generate-layout">
<div className={`xx-generate-layout${currentStep < 4 ? " full-width" : ""}`}>
{/* ════ 左侧:表单区 ════ */}
<div className="xx-generate-form">
<GenerateStepContent
@@ -202,7 +245,6 @@ const GeneratePage: React.FC = () => {
onSmartSelectedIdsChange={setSmartSelectedIds}
titleSettings={titleSettings}
onTitleSettingsChange={setTitleSettings}
/* 标题样式回调 */
onUpdatePosition={styleUpdaters.updatePosition}
onUpdateFont={styleUpdaters.updateFont}
onUpdateSize={styleUpdaters.updateSize}
@@ -213,12 +255,17 @@ const GeneratePage: React.FC = () => {
onApplyPreset={styleUpdaters.applyPreset}
activePreset={styleUpdaters.activePreset}
titlePresets={styleUpdaters.titlePresets}
onPreviewTaskCreated={setPreviewTaskId}
onSourceEditPlanIdExtracted={setStoredSourceEditPlanId}
bgm={bgm}
bgmConfig={bgmConfig}
coverSettings={coverSettings}
onCoverSettingsChange={setCoverSettings}
duration={duration}
selectedVoice={selectedVoice}
onSelectedVoiceChange={setSelectedVoice}
totalVideoDuration={totalVideoDuration}
onServerClipsChange={setServerClips}
voiceMode={voiceMode}
onVoiceModeChange={setVoiceMode}
selectedClonedVoice={selectedClonedVoice}
@@ -228,8 +275,6 @@ const GeneratePage: React.FC = () => {
hasProcessing={hasProcessing}
cloneModalOpen={cloneModalOpen}
onCloneModalOpenChange={setCloneModalOpen}
generateCount={generateCount}
onGenerateCountChange={setGenerateCount}
generating={generating}
generated={generated}
generateError={generateError}
@@ -251,63 +296,58 @@ const GeneratePage: React.FC = () => {
/>
</div>
{/* ════ 右侧:预览 + 生成结果 ════ */}
{/* ════ 右侧:步骤 4-6 实时预览,步骤 7 最终视频 ════ */}
<div className="xx-generate-right-col">
{/* 预览视频面板(Step4+ 显示,含 CSS 标题实时预览层) */}
{currentStep >= 4 && (
<PreviewVideoPanel
{currentStep >= 4 && currentStep <= 6 && !!currentTemplate && (
<FrontendPreviewPlayer
assets={previewAssets}
template={currentTemplate}
videoRatio={videoRatio}
assetsReady={previewAssetsReady}
assetsLoading={previewAssetsLoading}
titleSettings={titleSettings}
voiceAudioUrl={voiceAudioUrl}
ready={previewAssets.length > 0}
serverClips={serverClips}
voiceAudioUrl={previewVoiceAudioUrl || undefined}
titleSettings={{
title: titleSettings.title,
size: titleSettings.size,
font: titleSettings.font,
color: titleSettings.color,
position: titleSettings.position as "top" | "center" | "bottom",
bold: titleSettings.bold,
italic: titleSettings.italic,
stroke: titleSettings.stroke,
shadow: titleSettings.shadow,
}}
/>
)}
{currentStep >= 6 && (
<GenerateResultPanel
generated={generated}
generating={generating}
progress={progress}
generateError={generateError}
generatedVideos={generatedVideos}
onVideoPreview={(video) => {
setPreviewVideo(video)
setPreviewModalOpen(true)
}}
onDownload={handleDownload}
onShare={handleShare}
onGoToLibrary={() => navigate("/app/products")}
/>
{currentStep === 7 && generated && generatedVideos.length > 0 && (
<div className="xx-inline-video-player">
<video
src={generatedVideos[0].download_url || generatedVideos[0].file_url}
controls
autoPlay
style={{ width: "100%", maxHeight: "70vh", objectFit: "contain", borderRadius: 12 }}
poster={generatedVideos[0].thumbnail_url || undefined}
/>
<div style={{ display: "flex", gap: 8, marginTop: 12, justifyContent: "center" }}>
<button className="xx-btn xx-btn-ghost xx-btn-sm" onClick={handleDownload}>
</button>
<button className="xx-btn xx-btn-ghost xx-btn-sm" onClick={handleShare}>
🔗
</button>
<button
className="xx-btn xx-btn-ghost xx-btn-sm"
onClick={() => navigate("/app/products")}
>
📁
</button>
</div>
</div>
)}
</div>
</div>
{/* ── 视频预览弹窗 ── */}
<Modal
className="xx-preview-modal"
open={previewModalOpen}
onCancel={() => setPreviewModalOpen(false)}
footer={null}
width="80vw"
centered
destroyOnClose
>
{previewVideo && (
<div className="xx-preview-modal-content">
<video
src={previewVideo.download_url || previewVideo.file_url}
controls
autoPlay
style={{ width: "100%", maxHeight: "70vh", objectFit: "contain" }}
poster={previewVideo.thumbnail_url || undefined}
/>
</div>
)}
</Modal>
{/* ── 音色克隆弹窗 ── */}
{/* 音色克隆弹窗 */}
<CloneModal
open={cloneModalOpen}
onClose={() => setCloneModalOpen(false)}
@@ -16,14 +16,16 @@ import {
} from "@ant-design/icons"
import type { AssetItem } from "@/api/assets"
import type { EditingTemplate } from "@/api/editing-planner"
import type { EditPlanClip } from "@/api/template-editor"
import { useSegmentScheduler, type PlaybackSegment } from "../hooks/useSegmentScheduler"
import { useCanvasPlayer, isWebCodecsSupported } from "../hooks/useCanvasPlayer"
import { useCanvasPlayer } from "../hooks/useCanvasPlayer"
interface FrontendPreviewPlayerProps {
assets: AssetItem[]
template: EditingTemplate | null
videoRatio: string
ready: boolean
serverClips?: EditPlanClip[]
voiceAudioUrl?: string
titleSettings?: {
title: string
@@ -50,9 +52,31 @@ function formatTime(seconds: number): string {
function buildPlaybackSegments(
assets: AssetItem[],
template: EditingTemplate | null,
serverClips?: EditPlanClip[],
): PlaybackSegment[] {
if (!assets.length) return []
// Build asset lookup map
const assetMap = new Map(assets.map((a) => [a.id, a]))
// 优先使用服务端 clips(含随机 start_time 和正确数量),与最终生成结果一致
if (serverClips && serverClips.length > 0) {
const segments: PlaybackSegment[] = []
for (const clip of serverClips) {
const asset = assetMap.get(clip.asset_id)
if (!asset) continue
const assetDuration = asset.duration || asset.metadata?.duration || 30
const startTime = clip.start_time || 0
const endTime = Math.min(startTime + (clip.duration || assetDuration), assetDuration)
const videoUrl = asset.file_url || asset.storage_key
segments.push({ assetId: asset.id, videoUrl, startTime, endTime, order: clip.order })
}
if (segments.length > 0) {
return segments.sort((a, b) => a.order - b.order)
}
}
// Fallback: 本地构建片段(与旧行为一致)
const templateSegments = template?.segments || []
const segments: PlaybackSegment[] = []
@@ -76,13 +100,66 @@ function buildPlaybackSegments(
const FrontendPreviewPlayer: React.FC<FrontendPreviewPlayerProps> = ({
assets,
template,
videoRatio: _videoRatio,
videoRatio,
ready,
serverClips,
voiceAudioUrl,
titleSettings,
}) => {
const segments = useMemo(() => buildPlaybackSegments(assets, template), [assets, template])
const useWebCodecs = isWebCodecsSupported()
const segments = useMemo(
() => buildPlaybackSegments(assets, template, serverClips),
[assets, template, serverClips],
)
// ── ASS 坐标系参数(与后端 ass_subtitle_builder.py 一致) ──
const TITLE_MARGIN_TOP = 120
const TITLE_MARGIN_BOTTOM = 60
const TITLE_MARGIN_SIDE = 40
const playRes = (() => {
switch (videoRatio) {
case "16:9":
return { width: 1920, height: 1080 }
case "1:1":
return { width: 1080, height: 1080 }
case "9:16":
default:
return { width: 1080, height: 1920 }
}
})()
const playerContainerRef = useRef<HTMLDivElement>(null)
const [containerHeight, setContainerHeight] = useState(0)
useEffect(() => {
const el = playerContainerRef.current
if (!el) return
const ro = new ResizeObserver((entries) => {
for (const entry of entries) {
const h = entry.contentRect.height
if (h > 0) setContainerHeight(h)
}
})
ro.observe(el)
const rect = el.getBoundingClientRect()
if (rect.height > 0) setContainerHeight(rect.height)
return () => ro.disconnect()
}, [])
// 标题字号按容器高度与 PlayResY 的比例缩放
const titleFontSizePx =
containerHeight > 0
? ((titleSettings?.size ?? 36) / playRes.height) * containerHeight
: (titleSettings?.size ?? 36)
const titleSidePct = (TITLE_MARGIN_SIDE / playRes.width) * 100
const titleTopPct = (TITLE_MARGIN_TOP / playRes.height) * 100
const titleBottomPct = (TITLE_MARGIN_BOTTOM / playRes.height) * 100
// 描边/阴影也要按缩放比例放大
const titleScale = containerHeight > 0 ? containerHeight / playRes.height : 1
const titleStrokeWidth = Math.max(1, 2 * titleScale)
const titleShadowBlur = 4 * titleScale
const titleShadowOffset = 2 * titleScale
// 默认走原生 video 播放(浏览器硬件解码,独立线程,不阻塞 UI)
// WebCodecs 仅在明确需要时启用(保留代码作为兜底)
const useWebCodecs = false
// ── 两条路径共用同一个 canvas ref(fallback 路径不使用) ──
const canvasRef = useRef<HTMLCanvasElement>(null)
@@ -112,12 +189,30 @@ const FrontendPreviewPlayer: React.FC<FrontendPreviewPlayerProps> = ({
[segments],
)
// WebCodecs 解码失败后强制走 video fallback
const [forceVideoFallback, setForceVideoFallback] = useState(false)
const handleCanvasError = useCallback((err: Error) => {
console.error("[FrontendPreviewPlayer] Canvas decode Error, switching to video fallback:", err)
setForceVideoFallback(true)
}, [])
const { state: canvasState, controls: canvasControls } = useCanvasPlayer(
canvasRef,
canvasSegments,
useWebCodecs ? canvasTitle : undefined,
useWebCodecs && !forceVideoFallback ? canvasSegments : [],
useWebCodecs && !forceVideoFallback ? canvasTitle : undefined,
handleCanvasError,
useWebCodecs && !forceVideoFallback,
)
// WebCodecs 报告解码失败时自动切换到 video fallback
useEffect(() => {
if (canvasState.hasDecodeError && !forceVideoFallback) {
console.warn("[FrontendPreviewPlayer] hasDecodeError detected, forcing video fallback")
setForceVideoFallback(true)
}
}, [canvasState.hasDecodeError, forceVideoFallback])
// ── Video 播放器(fallback 路径) ──
const {
isPlaying: videoIsPlaying,
@@ -130,12 +225,13 @@ const FrontendPreviewPlayer: React.FC<FrontendPreviewPlayerProps> = ({
videoRefs,
} = useSegmentScheduler(segments)
// 选择哪条路径的状态
const isPlaying = useWebCodecs ? canvasState.isPlaying : videoIsPlaying
const currentTime = useWebCodecs ? canvasState.currentTime : videoCurrentTime
const totalDuration = useWebCodecs ? canvasState.duration : videoTotalDuration
const canPlay = useWebCodecs ? canvasState.isReady : videoCanPlay
const isBuffering = useWebCodecs ? canvasState.isBuffering : false
// 选择哪条路径的状态(WebCodecs 解码失败时强制走 video fallback
const effectiveUseWebCodecs = useWebCodecs && !forceVideoFallback
const isPlaying = effectiveUseWebCodecs ? canvasState.isPlaying : videoIsPlaying
const currentTime = effectiveUseWebCodecs ? canvasState.currentTime : videoCurrentTime
const totalDuration = effectiveUseWebCodecs ? canvasState.duration : videoTotalDuration
const canPlay = effectiveUseWebCodecs ? canvasState.isReady : videoCanPlay
const isBuffering = effectiveUseWebCodecs ? canvasState.isBuffering : false
// ── 配音音频同步 ──
const audioRef = useRef<HTMLAudioElement | null>(null)
@@ -172,16 +268,18 @@ const FrontendPreviewPlayer: React.FC<FrontendPreviewPlayerProps> = ({
}, [isPlaying, currentTime])
// 片段切换时同步音频(仅 fallback 路径需要)
const segmentSyncKey = useWebCodecs ? -1 : videoCurrentSegIdx
const segmentSyncKey = effectiveUseWebCodecs ? -1 : videoCurrentSegIdx
useEffect(() => {
const audio = audioRef.current
if (!audio || !audio.src || !isPlaying) return
audio.currentTime = currentTime
}, [segmentSyncKey, isPlaying, currentTime])
// 注意:不要把 currentTime 放进依赖数组,否则每200ms会重置音频位置导致卡顿
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [segmentSyncKey, isPlaying])
const handleSeekTo = useCallback(
(time: number) => {
if (useWebCodecs) {
if (effectiveUseWebCodecs) {
canvasControls.seek(time)
} else {
videoSeekTo(time)
@@ -191,11 +289,11 @@ const FrontendPreviewPlayer: React.FC<FrontendPreviewPlayerProps> = ({
audio.currentTime = time
}
},
[useWebCodecs, canvasControls, videoSeekTo],
[effectiveUseWebCodecs, canvasControls, videoSeekTo],
)
const handleTogglePlay = useCallback(() => {
if (useWebCodecs) {
if (effectiveUseWebCodecs) {
if (canvasState.isPlaying) {
canvasControls.pause()
} else {
@@ -204,7 +302,7 @@ const FrontendPreviewPlayer: React.FC<FrontendPreviewPlayerProps> = ({
} else {
videoTogglePlayPause()
}
}, [useWebCodecs, canvasState.isPlaying, canvasControls, videoTogglePlayPause])
}, [effectiveUseWebCodecs, canvasState.isPlaying, canvasControls, videoTogglePlayPause])
// ── 进度条拖拽 ──
const [isDragging, setIsDragging] = useState(false)
@@ -247,82 +345,102 @@ const FrontendPreviewPlayer: React.FC<FrontendPreviewPlayerProps> = ({
const progressPercent = totalDuration > 0 ? (currentTime / totalDuration) * 100 : 0
// ── Canvas ResizeObserver ──
// ── Canvas 容器 ref(保留声明,WebCodecs 兜底路径仍引用) ──
const canvasContainerRef = useRef<HTMLDivElement>(null)
useEffect(() => {
if (!useWebCodecs || !canPlay) return
const container = canvasContainerRef.current
const canvas = canvasRef.current
if (!container || !canvas) return
// 立即设置一次 canvas 像素分辨率,避免默认 300×150 导致首帧变形
const initRect = container.getBoundingClientRect()
if (initRect.width > 0 && initRect.height > 0) {
const dpr = window.devicePixelRatio || 1
canvas.width = initRect.width * dpr
canvas.height = initRect.height * dpr
}
const ro = new ResizeObserver((entries) => {
for (const entry of entries) {
const { width, height } = entry.contentRect
if (width > 0 && height > 0) {
canvas.width = width * window.devicePixelRatio
canvas.height = height * window.devicePixelRatio
}
}
})
ro.observe(container)
return () => ro.disconnect()
}, [useWebCodecs, canPlay])
// ── 未就绪 ──
if (!ready || !assets.length) {
return (
<div
className="xx-preview-empty"
style={{
position: "absolute",
inset: 0,
position: "relative",
width: "100%",
maxWidth: 280,
aspectRatio: "9 / 16",
background: "#0a0a0a",
borderRadius: 24,
overflow: "hidden",
boxShadow:
"0 4px 6px -1px rgba(0,0,0,0.3), 0 20px 50px -12px rgba(0,0,0,0.5), inset 0 0 0 1px rgba(255,255,255,0.06)",
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
zIndex: 1,
}}
>
<SoundOutlined style={{ fontSize: 48, color: "var(--text-tertiary)", marginBottom: 12 }} />
<p className="xx-preview-empty-title">...</p>
<p className="xx-preview-empty-desc"></p>
<SoundOutlined style={{ fontSize: 40, color: "rgba(255,255,255,0.3)", marginBottom: 12 }} />
<p style={{ color: "rgba(255,255,255,0.6)", fontSize: 14, margin: "0 0 4px" }}>
...
</p>
<p style={{ color: "rgba(255,255,255,0.35)", fontSize: 12, margin: 0 }}>
</p>
</div>
)
}
// ── 无播放片段 ──
if (!canPlay) {
const showDecodeError = forceVideoFallback && canvasState.hasDecodeError
return (
<div
className="xx-preview-empty"
style={{
position: "absolute",
inset: 0,
position: "relative",
width: "100%",
maxWidth: 280,
aspectRatio: "9 / 16",
background: "#0a0a0a",
borderRadius: 24,
overflow: "hidden",
boxShadow:
"0 4px 6px -1px rgba(0,0,0,0.3), 0 20px 50px -12px rgba(0,0,0,0.5), inset 0 0 0 1px rgba(255,255,255,0.06)",
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
zIndex: 1,
padding: 24,
}}
>
{isBuffering ? (
<>
<LoadingOutlined style={{ fontSize: 48, color: "#fff", marginBottom: 12 }} spin />
<p style={{ color: "rgba(255,255,255,0.8)" }}>...</p>
<LoadingOutlined style={{ fontSize: 40, color: "#fff", marginBottom: 12 }} spin />
<p style={{ color: "rgba(255,255,255,0.8)", fontSize: 14, margin: 0 }}>...</p>
</>
) : showDecodeError ? (
<>
<PlayCircleOutlined style={{ fontSize: 40, color: "#ef4444", marginBottom: 12 }} />
<p
style={{
color: "rgba(255,255,255,0.9)",
fontSize: 14,
margin: "0 0 4px",
fontWeight: 500,
}}
>
</p>
<p
style={{
color: "rgba(255,255,255,0.5)",
fontSize: 12,
margin: 0,
textAlign: "center",
}}
>
{canvasState.errorMessage || "当前浏览器不支持该视频编码格式,请刷新重试"}
</p>
</>
) : (
<>
<PlayCircleOutlined
style={{ fontSize: 48, color: "var(--text-tertiary)", marginBottom: 12 }}
style={{ fontSize: 40, color: "rgba(255,255,255,0.3)", marginBottom: 12 }}
/>
<p className="xx-preview-empty-title"></p>
<p className="xx-preview-empty-desc"></p>
<p style={{ color: "rgba(255,255,255,0.6)", fontSize: 14, margin: "0 0 4px" }}>
</p>
<p style={{ color: "rgba(255,255,255,0.35)", fontSize: 12, margin: 0 }}>
</p>
</>
)}
</div>
@@ -330,9 +448,22 @@ const FrontendPreviewPlayer: React.FC<FrontendPreviewPlayerProps> = ({
}
return (
<>
<div
ref={playerContainerRef}
style={{
position: "relative",
width: "100%",
maxWidth: 280,
aspectRatio: "9 / 16",
background: "#0a0a0a",
borderRadius: 24,
overflow: "hidden",
boxShadow:
"0 4px 6px -1px rgba(0,0,0,0.3), 0 20px 50px -12px rgba(0,0,0,0.5), inset 0 0 0 1px rgba(255,255,255,0.06)",
}}
>
{/* ── Canvas 渲染层(WebCodecs 路径) ── */}
{useWebCodecs && (
{effectiveUseWebCodecs && (
<div
ref={canvasContainerRef}
style={{
@@ -353,8 +484,8 @@ const FrontendPreviewPlayer: React.FC<FrontendPreviewPlayerProps> = ({
</div>
)}
{/* ── Video 渲染层(fallback 路径 ── */}
{!useWebCodecs &&
{/* ── Video 渲染层(默认路径,浏览器原生硬件解码 ── */}
{!effectiveUseWebCodecs &&
segments.map((seg, i) => (
<video
key={seg.assetId}
@@ -362,9 +493,7 @@ const FrontendPreviewPlayer: React.FC<FrontendPreviewPlayerProps> = ({
ref={(el) => {
videoRefs.current[i] = el
}}
preload={
i === videoCurrentSegIdx ? "auto" : i === videoCurrentSegIdx + 1 ? "metadata" : "none"
}
preload="auto"
src={seg.videoUrl}
style={{
position: "absolute",
@@ -381,54 +510,121 @@ const FrontendPreviewPlayer: React.FC<FrontendPreviewPlayerProps> = ({
/>
))}
{/* 播放按钮 */}
{/* 标题CSS叠加层 — 与后端 ASS 烧录坐标系 1:1 对齐 */}
{titleSettings?.title && (
<div
style={{
position: "absolute",
inset: 0,
zIndex: 5,
pointerEvents: "none",
overflow: "hidden",
}}
>
<div
style={{
position: "absolute",
left: `${titleSidePct}%`,
right: `${titleSidePct}%`,
textAlign: "center",
...(titleSettings.position === "top"
? { top: `${titleTopPct}%` }
: titleSettings.position === "center"
? { top: "50%", transform: "translateY(-50%)" }
: { bottom: `${titleBottomPct}%` }),
}}
>
<span
style={{
fontSize: `${titleFontSizePx}px`,
fontFamily: titleSettings.font || "思源黑体",
color: titleSettings.color || "#ffffff",
fontWeight: titleSettings.bold ? 700 : 400,
fontStyle: titleSettings.italic ? "italic" : "normal",
lineHeight: 1.05,
wordBreak: "break-word",
WebkitTextStroke: titleSettings.stroke
? `${titleStrokeWidth}px #000000`
: undefined,
textShadow: titleSettings.shadow
? `${titleShadowOffset}px ${titleShadowOffset}px ${titleShadowBlur}px rgba(0,0,0,0.8)`
: undefined,
}}
>
{titleSettings.title.split(/[/]/).map((part, i) => (
<span key={i}>
{i > 0 && <br />}
{part}
</span>
))}
</span>
</div>
</div>
)}
{/* 中央播放按钮 */}
{!isPlaying && (
<button
className="xx-preview-play-btn"
onClick={handleTogglePlay}
style={{
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
background: "rgba(0,0,0,0.5)",
border: "none",
background: "rgba(0,0,0,0.45)",
backdropFilter: "blur(12px)",
WebkitBackdropFilter: "blur(12px)",
border: "1px solid rgba(255,255,255,0.15)",
borderRadius: "50%",
width: 56,
height: 56,
width: 52,
height: 52,
cursor: "pointer",
display: "flex",
alignItems: "center",
justifyContent: "center",
color: "#fff",
fontSize: 28,
fontSize: 26,
zIndex: 10,
transition: "transform 0.2s ease, background 0.2s ease",
boxShadow: "0 4px 20px rgba(0,0,0,0.4)",
}}
onMouseEnter={(e) => {
e.currentTarget.style.transform = "translate(-50%, -50%) scale(1.08)"
e.currentTarget.style.background = "rgba(0,0,0,0.6)"
}}
onMouseLeave={(e) => {
e.currentTarget.style.transform = "translate(-50%, -50%) scale(1)"
e.currentTarget.style.background = "rgba(0,0,0,0.45)"
}}
>
<PlayCircleOutlined />
</button>
)}
{/* 片段指示器 */}
{/* 片段指示器 — 右上角胶囊 */}
<div
style={{
position: "absolute",
top: 8,
left: 8,
background: "rgba(0,0,0,0.6)",
color: "#fff",
fontSize: 11,
right: 8,
background: "rgba(0,0,0,0.45)",
backdropFilter: "blur(8px)",
WebkitBackdropFilter: "blur(8px)",
color: "rgba(255,255,255,0.9)",
fontSize: 10,
fontWeight: 500,
padding: "2px 8px",
borderRadius: 4,
borderRadius: 999,
zIndex: 10,
border: "1px solid rgba(255,255,255,0.1)",
letterSpacing: 0.3,
}}
>
{useWebCodecs ? "Canvas" : `片段 ${videoCurrentSegIdx + 1}/${segments.length}`}
{`${videoCurrentSegIdx + 1} / ${segments.length}`}
</div>
{/* 控制条 */}
{/* 控制条 — 手机风格毛玻璃 */}
<div
className="xx-preview-controls"
style={{
position: "absolute",
bottom: 0,
@@ -436,23 +632,36 @@ const FrontendPreviewPlayer: React.FC<FrontendPreviewPlayerProps> = ({
right: 0,
display: "flex",
alignItems: "center",
gap: 8,
padding: "8px 12px",
background: "linear-gradient(transparent, rgba(0,0,0,0.6))",
gap: 10,
padding: "12px 16px 16px",
background: "linear-gradient(transparent, rgba(0,0,0,0.7))",
backdropFilter: "blur(4px)",
WebkitBackdropFilter: "blur(4px)",
zIndex: 10,
}}
>
<button
onClick={handleTogglePlay}
style={{
background: "none",
background: "rgba(255,255,255,0.15)",
border: "none",
color: "#fff",
fontSize: 18,
fontSize: 16,
cursor: "pointer",
padding: 4,
width: 32,
height: 32,
borderRadius: "50%",
display: "flex",
alignItems: "center",
justifyContent: "center",
flexShrink: 0,
transition: "background 0.15s",
}}
onMouseEnter={(e) => {
e.currentTarget.style.background = "rgba(255,255,255,0.25)"
}}
onMouseLeave={(e) => {
e.currentTarget.style.background = "rgba(255,255,255,0.15)"
}}
>
{isPlaying ? <PauseCircleOutlined /> : <PlayCircleOutlined />}
@@ -460,10 +669,11 @@ const FrontendPreviewPlayer: React.FC<FrontendPreviewPlayerProps> = ({
<span
style={{
fontSize: 12,
color: "rgba(255,255,255,0.8)",
minWidth: 80,
fontSize: 11,
color: "rgba(255,255,255,0.85)",
minWidth: 72,
fontVariantNumeric: "tabular-nums",
letterSpacing: 0.2,
}}
>
{formatTime(currentTime)} / {formatTime(totalDuration)}
@@ -474,8 +684,8 @@ const FrontendPreviewPlayer: React.FC<FrontendPreviewPlayerProps> = ({
onMouseDown={handleMouseDown}
style={{
flex: 1,
height: 4,
background: "rgba(255,255,255,0.15)",
height: 3,
background: "rgba(255,255,255,0.2)",
borderRadius: 2,
cursor: "pointer",
position: "relative",
@@ -485,7 +695,7 @@ const FrontendPreviewPlayer: React.FC<FrontendPreviewPlayerProps> = ({
style={{
height: "100%",
width: `${progressPercent}%`,
background: "#3b82f6",
background: "#fff",
borderRadius: 2,
transition: isDragging ? "none" : "width 0.1s linear",
}}
@@ -499,15 +709,15 @@ const FrontendPreviewPlayer: React.FC<FrontendPreviewPlayerProps> = ({
width: 10,
height: 10,
borderRadius: "50%",
background: "#3b82f6",
border: "2px solid #fff",
background: "#fff",
boxShadow: "0 0 6px rgba(255,255,255,0.5)",
opacity: isDragging ? 1 : 0,
transition: "opacity 0.15s",
}}
/>
</div>
</div>
</>
</div>
)
}
@@ -7,6 +7,7 @@
*/
import React from "react"
import type { EditingTemplate } from "@/api/editing-planner"
import type { EditPlanClip } from "@/api/template-editor"
import type { PresetVoiceItem } from "@/api/voices"
import type { VoiceClone } from "@/api/voice-clone"
import type { CoverConfig } from "../types/cover"
@@ -55,6 +56,7 @@ export interface GenerateStepContentProps {
selectedVoice: string
onSelectedVoiceChange: (id: string) => void
totalVideoDuration?: number
onServerClipsChange: (clips: EditPlanClip[]) => void
voiceMode: "preset" | "custom" | "clone"
onVoiceModeChange: (mode: "preset" | "custom" | "clone") => void
selectedClonedVoice: string
@@ -65,8 +67,6 @@ export interface GenerateStepContentProps {
cloneModalOpen: boolean
onCloneModalOpenChange: (open: boolean) => void
/* 生成 */
generateCount: number
onGenerateCountChange: (n: number) => void
generating: boolean
generated: boolean
generateError: string | null
@@ -76,6 +76,14 @@ export interface GenerateStepContentProps {
onDismissError: () => void
/* 其他 */
presetVoices: PresetVoiceItem[]
/** 预览任务创建回调——传递给 Step6CoverSettings */
onPreviewTaskCreated?: (taskId: string) => void
/** 从预览响应中提取到 source_edit_plan_id 时的回调 */
onSourceEditPlanIdExtracted?: (planId: string) => void
/** BGM 开关 */
bgm: boolean
/** BGM 配置(来自模板) */
bgmConfig?: { enabled: boolean; music_id?: string }
}
export const GenerateStepContent: React.FC<GenerateStepContentProps> = (props) => {
@@ -108,11 +116,10 @@ export const GenerateStepContent: React.FC<GenerateStepContentProps> = (props) =
selectedVoice,
onSelectedVoiceChange,
totalVideoDuration,
onServerClipsChange,
voiceMode,
selectedClonedVoice,
clonedVoices,
generateCount,
onGenerateCountChange,
generating,
generated,
generateError,
@@ -121,8 +128,16 @@ export const GenerateStepContent: React.FC<GenerateStepContentProps> = (props) =
onRetry,
onDismissError,
presetVoices,
onPreviewTaskCreated,
onSourceEditPlanIdExtracted,
bgm,
bgmConfig,
} = props
/* 当前模板的 segments,传给 Step2 构建 clips */
const currentTemplate = userTemplates.find((t) => t.id === selectedTemplate)
const templateSegments = currentTemplate?.segments
switch (currentStep) {
case 1:
return (
@@ -141,6 +156,9 @@ export const GenerateStepContent: React.FC<GenerateStepContentProps> = (props) =
onSelectedMaterialsChange={onSelectedMaterialsChange}
smartSelectedIds={smartSelectedIds}
onSmartSelectedIdsChange={onSmartSelectedIdsChange}
selectedTemplate={selectedTemplate}
templateSegments={templateSegments}
onServerClipsChange={onServerClipsChange}
/>
)
case 3:
@@ -156,6 +174,7 @@ export const GenerateStepContent: React.FC<GenerateStepContentProps> = (props) =
<Step4TitleSettings
titleSettings={titleSettings}
onTitleSettingsChange={onTitleSettingsChange}
selectedTemplate={selectedTemplate}
/>
)
case 5:
@@ -182,6 +201,14 @@ export const GenerateStepContent: React.FC<GenerateStepContentProps> = (props) =
duration={duration}
assetIds={materialMode === "auto" ? smartSelectedIds : selectedMaterials}
selectedTemplate={selectedTemplate}
titleSettings={titleSettings}
onPreviewTaskCreated={onPreviewTaskCreated}
onSourceEditPlanIdExtracted={onSourceEditPlanIdExtracted}
voiceMode={voiceMode}
selectedVoice={selectedVoice}
selectedClonedVoice={selectedClonedVoice}
bgm={bgm}
bgmConfig={bgmConfig}
/>
)
case 7:
@@ -199,8 +226,6 @@ export const GenerateStepContent: React.FC<GenerateStepContentProps> = (props) =
presetVoices={presetVoices}
clonedVoices={clonedVoices}
coverSettings={coverSettings}
generateCount={generateCount}
onGenerateCountChange={onGenerateCountChange}
generating={generating}
generated={generated}
generateError={generateError}
@@ -1,57 +1,72 @@
/**
* 右侧预览视频面板
* Step4+: 显示预览视频面板
* Step5: 前端实时预览 — 用原生 video 播放素材片段 + CSS 标题叠加
* 右侧预览视频面板 — 服务器渲染预览架构
*
* 架构改造:完全去除后端 FFmpeg 预览依赖
* - 使用 FrontendPreviewPlayer 直接播放素材片段
* - TitleOverlay CSS 层实时响应标题样式变化
* Step4+: 显示预览面板
* Step5: 播放服务器渲染的真实视频(POST /generation/preview
*
* 布局:本组件提供 .xx-preview-video 容器(position: relative + overflow: hidden
* FrontendPreviewPlayer 的内容通过 absolute 定位填充容器
* TitleOverlay 通过 absolute 定位 + z-index: 30 覆盖在最上层
* 架构:
* - 进入 Step4/5 时自动创建服务器预览渲染任务
* - 轮询完成后用 <video> 标签播放返回的 video_url
* - 标题样式编辑时 CSS TitleOverlay 实时叠加预览
* - 素材/配音/BGM 变更自动重新渲染
* - 标题文字/样式变更标记 stale,保留旧视频 + 显示"重新预览"按钮
*
* 点"确认生成"时走 confirm 路径,成品就是预览视频本身,100% 一致。
*/
import React, { useMemo, useRef, useState, useEffect } from "react"
import { LoadingOutlined } from "@ant-design/icons"
import type { AssetItem } from "@/api/assets"
import type { EditingTemplate } from "@/api/editing-planner"
import { LoadingOutlined, ReloadOutlined, ExclamationCircleOutlined } from "@ant-design/icons"
import { Button } from "antd"
import type { TitleSettings } from "../types"
import FrontendPreviewPlayer from "./FrontendPreviewPlayer"
import { getFontFamily } from "../constants"
import type { ServerPreviewStatus } from "../hooks/useServerPreview"
interface PreviewVideoPanelProps {
/** 已加载的素材列表 */
assets: AssetItem[]
/** 当前模板 */
template: EditingTemplate | null
/** 服务器预览状态 */
previewStatus: ServerPreviewStatus
/** 服务器渲染视频 URL */
videoUrl: string | null
/** 渲染进度 0-100 */
progress: number
/** 错误信息 */
error: string | null
/** 重新预览回调 */
onRetry: () => void
/** 视频比例 */
videoRatio: string
/** 素材是否已加载就绪 */
assetsReady: boolean
/** 素材是否正在加载 */
assetsLoading: boolean
/** 标题设置 — 用于 CSS 实时预览层 */
/** 标题设置 — CSS 实时预览层 */
titleSettings?: TitleSettings
/** 配音音频 URL */
voiceAudioUrl?: string
/** 素材数量 */
assetCount?: number
}
/* ── ASS 坐标系参数(与后端 ass_subtitle_builder.py 一致) ── */
const ASS_VIDEO_HEIGHT = 720
const ASS_TITLE_MARGIN_TOP = 60
const ASS_TITLE_MARGIN_BOTTOM = 60
const ASS_TITLE_MARGIN_SIDE = 40
const TITLE_MARGIN_TOP = 120
const TITLE_MARGIN_BOTTOM = 60
const TITLE_MARGIN_SIDE = 40
/**
* 根据 position 计算 CSS 垂直定位
* 与后端 position_to_ass_alignment() 对齐:top→8, center→5, bottom→2
*/
function getPositionStyle(position: string): React.CSSProperties {
const sidePercent = (ASS_TITLE_MARGIN_SIDE / 1280) * 100
/** 根据视频比例返回后端实际渲染分辨率(PlayResX × PlayResY */
function getResolution(ratio: string): { width: number; height: number } {
switch (ratio) {
case "16:9":
return { width: 1920, height: 1080 }
case "1:1":
return { width: 1080, height: 1080 }
case "9:16":
default:
return { width: 1080, height: 1920 }
}
}
function getPositionStyle(
position: string,
playResX: number,
playResY: number,
): React.CSSProperties {
const sidePercent = (TITLE_MARGIN_SIDE / playResX) * 100
switch (position) {
case "bottom":
return {
bottom: `${(ASS_TITLE_MARGIN_BOTTOM / ASS_VIDEO_HEIGHT) * 100}%`,
bottom: `${(TITLE_MARGIN_BOTTOM / playResY) * 100}%`,
left: `${sidePercent}%`,
right: `${sidePercent}%`,
textAlign: "center",
@@ -67,7 +82,7 @@ function getPositionStyle(position: string): React.CSSProperties {
case "top":
default:
return {
top: `${(ASS_TITLE_MARGIN_TOP / ASS_VIDEO_HEIGHT) * 100}%`,
top: `${(TITLE_MARGIN_TOP / playResY) * 100}%`,
left: `${sidePercent}%`,
right: `${sidePercent}%`,
textAlign: "center",
@@ -75,52 +90,41 @@ function getPositionStyle(position: string): React.CSSProperties {
}
}
/**
* 构建 CSS 标题层的样式
* 所有渲染参数与后端 FFmpeg ASS 字幕一致
*/
function buildTitleStyle(settings: TitleSettings, containerHeight: number): React.CSSProperties {
// 用 px 计算 fontSize,不再依赖父元素 font-size 的百分比
function buildTitleStyle(
settings: TitleSettings,
containerHeight: number,
playResY: number,
): React.CSSProperties {
// 字号按容器高度与 PlayResY 的比例缩放,不设上限(与后端一致)
const fontSizePx =
containerHeight > 0
? (Math.min(settings.size, 96) / ASS_VIDEO_HEIGHT) * containerHeight
: (Math.min(settings.size, 96) / ASS_VIDEO_HEIGHT) * 400 // fallback
? (settings.size / playResY) * containerHeight
: (settings.size / playResY) * 400
const base: React.CSSProperties = {
fontFamily: settings.font || "思源黑体",
fontFamily: getFontFamily(settings.font),
fontSize: `${fontSizePx}px`,
color: settings.color || "#ffffff",
fontWeight: settings.bold ? 700 : 400,
fontStyle: settings.italic ? "italic" : "normal",
lineHeight: 1.3,
lineHeight: 1.05,
wordBreak: "break-word",
pointerEvents: "none",
userSelect: "none",
paddingLeft: `${(ASS_TITLE_MARGIN_SIDE / 1280) * 100}%`,
paddingRight: `${(ASS_TITLE_MARGIN_SIDE / 1280) * 100}%`,
}
if (settings.stroke) {
base.WebkitTextStroke = "1px #000000"
}
if (settings.shadow) {
base.textShadow = "2px 2px 4px rgba(0,0,0,0.8)"
}
if (settings.stroke) base.WebkitTextStroke = "1px #000000"
if (settings.shadow) base.textShadow = "2px 2px 4px rgba(0,0,0,0.8)"
return base
}
/**
* CSS 标题预览覆盖层
* 始终渲染:有标题显示标题,无标题显示占位文本"标题预览"
* z-index: 20(在视频 z-index:1 和控制条 z-index:10 之上)
*/
const TitleOverlay: React.FC<{ titleSettings: TitleSettings }> = ({ titleSettings }) => {
/** CSS 标题实时预览覆盖层 */
const TitleOverlay: React.FC<{ titleSettings: TitleSettings; videoRatio: string }> = ({
titleSettings,
videoRatio,
}) => {
const containerRef = useRef<HTMLDivElement>(null)
const [containerHeight, setContainerHeight] = useState(400) // fallback
const [containerHeight, setContainerHeight] = useState(400)
// ResizeObserver 获取容器实际高度
useEffect(() => {
const el = containerRef.current
if (!el) return
@@ -131,19 +135,21 @@ const TitleOverlay: React.FC<{ titleSettings: TitleSettings }> = ({ titleSetting
}
})
ro.observe(el)
// 初始化也读一次
const rect = el.getBoundingClientRect()
if (rect.height > 0) setContainerHeight(rect.height)
return () => ro.disconnect()
}, [])
const { width: playResX, height: playResY } = getResolution(videoRatio)
const positionStyle = useMemo(
() => getPositionStyle(titleSettings.position),
[titleSettings.position],
() => getPositionStyle(titleSettings.position, playResX, playResY),
// eslint-disable-next-line react-hooks/exhaustive-deps
[titleSettings.position, playResX, playResY],
)
const titleStyle = useMemo(
() => buildTitleStyle(titleSettings, containerHeight),
// eslint-disable-next-line react-hooks/exhaustive-deps -- 已逐字段列出 titleSettings 依赖
() => buildTitleStyle(titleSettings, containerHeight, playResY),
// eslint-disable-next-line react-hooks/exhaustive-deps
[
containerHeight,
titleSettings.font,
@@ -153,6 +159,7 @@ const TitleOverlay: React.FC<{ titleSettings: TitleSettings }> = ({ titleSetting
titleSettings.italic,
titleSettings.stroke,
titleSettings.shadow,
playResY,
],
)
@@ -169,14 +176,13 @@ const TitleOverlay: React.FC<{ titleSettings: TitleSettings }> = ({ titleSetting
overflow: "hidden",
}}
>
<div
style={{
...positionStyle,
...titleStyle,
position: "absolute",
}}
>
{displayTitle}
<div style={{ ...positionStyle, ...titleStyle, position: "absolute" }}>
{displayTitle.split(/[/]/).map((part, i) => (
<span key={i}>
{i > 0 && <br />}
{part}
</span>
))}
</div>
</div>
)
@@ -185,30 +191,47 @@ const TitleOverlay: React.FC<{ titleSettings: TitleSettings }> = ({ titleSetting
/* ── 主组件 ── */
export const PreviewVideoPanel: React.FC<PreviewVideoPanelProps> = ({
assets,
template,
previewStatus,
videoUrl,
progress,
error,
onRetry,
videoRatio,
assetsReady,
assetsLoading,
titleSettings,
voiceAudioUrl,
assetCount,
}) => {
const videoAspectStyle = { aspectRatio: (videoRatio || "9:16").replace(":", "/") }
const isLoading = previewStatus === "loading"
const isReady = previewStatus === "ready" || previewStatus === "stale"
const isFailed = previewStatus === "failed"
const isIdle = previewStatus === "idle"
const isStale = previewStatus === "stale"
return (
<div className="xx-generate-preview">
<div className="xx-preview-header">
<h3></h3>
{assetsReady && assets.length > 0 && <span className="xx-preview-badge"></span>}
{isReady && !isStale && <span className="xx-preview-badge"></span>}
{isStale && (
<span
style={{
fontSize: 12,
color: "#faad14",
display: "flex",
alignItems: "center",
gap: 4,
}}
>
<ExclamationCircleOutlined />
</span>
)}
{isLoading && <span className="xx-preview-badge"></span>}
</div>
{/* ✅ 预览容器 — 唯一的 .xx-preview-video 容器
内部所有内容(视频、控制条、标题叠加层)通过 absolute 定位填充 */}
<div className="xx-preview-video" style={{ ...videoAspectStyle, position: "relative" }}>
{/* 加载中状态 */}
{assetsLoading && (
{/* 加载中 */}
{isLoading && (
<div
className="xx-preview-loading-center"
style={{
position: "absolute",
inset: 0,
@@ -217,34 +240,132 @@ export const PreviewVideoPanel: React.FC<PreviewVideoPanelProps> = ({
alignItems: "center",
justifyContent: "center",
zIndex: 5,
background: "rgba(0,0,0,0.6)",
}}
>
<LoadingOutlined style={{ fontSize: 36, color: "#fff" }} spin />
<p style={{ marginTop: 12, color: "rgba(255,255,255,0.8)", fontSize: 14 }}>
...
<p style={{ marginTop: 12, color: "rgba(255,255,255,0.9)", fontSize: 14 }}>
{progress > 0 ? `...${progress}%` : "..."}
</p>
<p style={{ marginTop: 4, color: "rgba(255,255,255,0.5)", fontSize: 12 }}>
30-60
</p>
</div>
)}
{/* 前端播放器(视频 + 控制条 + 播放按钮)*/}
<FrontendPreviewPlayer
assets={assets}
template={template}
videoRatio={videoRatio}
ready={assetsReady}
voiceAudioUrl={voiceAudioUrl}
/>
{/* 空闲状态(尚未触发预览) */}
{isIdle && (
<div
style={{
position: "absolute",
inset: 0,
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
background: "rgba(0,0,0,0.3)",
zIndex: 5,
}}
>
<p style={{ color: "rgba(255,255,255,0.7)", fontSize: 14 }}>...</p>
</div>
)}
{/* CSS 标题实时预览层 — z-index: 20,始终渲染在内容层之上 */}
{titleSettings && <TitleOverlay titleSettings={titleSettings} />}
{/* 服务器渲染的真实视频 */}
{isReady && videoUrl && (
<video
key={videoUrl}
src={videoUrl}
controls
autoPlay
loop
playsInline
style={{
width: "100%",
height: "100%",
objectFit: "contain",
position: "absolute",
inset: 0,
zIndex: 1,
}}
/>
)}
{/* 标题样式实时预览层(仅在有视频时叠加) */}
{isReady && titleSettings && (
<TitleOverlay titleSettings={titleSettings} videoRatio={videoRatio} />
)}
{/* stale 遮罩:配置变更提示 */}
{isStale && (
<div
style={{
position: "absolute",
bottom: 0,
left: 0,
right: 0,
padding: "10px 16px",
background: "linear-gradient(transparent, rgba(0,0,0,0.85))",
display: "flex",
alignItems: "center",
justifyContent: "space-between",
gap: 8,
zIndex: 30,
}}
>
<span style={{ color: "rgba(255,255,255,0.9)", fontSize: 12 }}>
</span>
<Button size="small" type="primary" icon={<ReloadOutlined />} onClick={onRetry}>
</Button>
</div>
)}
{/* 错误状态 */}
{isFailed && (
<div
style={{
position: "absolute",
inset: 0,
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
background: "rgba(0,0,0,0.7)",
zIndex: 10,
padding: 24,
}}
>
<ExclamationCircleOutlined style={{ fontSize: 40, color: "#ff4d4f" }} />
<p
style={{
marginTop: 12,
color: "rgba(255,255,255,0.9)",
fontSize: 14,
textAlign: "center",
}}
>
{error || "预览渲染失败"}
</p>
<Button
type="primary"
icon={<ReloadOutlined />}
onClick={onRetry}
style={{ marginTop: 12 }}
>
</Button>
</div>
)}
</div>
{/* 素材信息 */}
{assetsReady && assets.length > 0 && (
{assetCount !== undefined && assetCount > 0 && (
<div className="xx-preview-info">
<div className="xx-preview-info-row">
<span></span>
<span>{assets.length} </span>
<span>{assetCount} </span>
</div>
<div className="xx-preview-info-row">
<span></span>
@@ -2,6 +2,8 @@
* Step 2 素材选择组件
*/
import React from "react"
import type { TemplateSegment } from "@/api/templates/types"
import type { EditPlanClip } from "@/api/template-editor"
import { useStep2Materials } from "../hooks/useStep2Materials"
import MaterialModeTabs from "./material/MaterialModeTabs"
import ManualMaterialList from "./material/ManualMaterialList"
@@ -15,6 +17,12 @@ interface Step2MaterialSelectProps {
onSelectedMaterialsChange: (ids: string[]) => void
smartSelectedIds: string[]
onSmartSelectedIdsChange: (ids: string[]) => void
/** 当前选中的模板/草稿 ID,用于自动保存 */
selectedTemplate?: string
/** 当前模板的 segments(用于构建 clips duration */
templateSegments?: TemplateSegment[]
/** 服务端 clips 创建成功后的回调 */
onServerClipsChange?: (clips: EditPlanClip[]) => void
}
const Step2MaterialSelect: React.FC<Step2MaterialSelectProps> = (props) => {
@@ -12,6 +12,8 @@ import AiTitleGenerator from "./title/AiTitleGenerator"
interface Step4TitleSettingsProps {
titleSettings: TitleSettings
onTitleSettingsChange: (settings: TitleSettings) => void
/** 当前选中的模板/草稿 ID,用于自动保存 */
selectedTemplate?: string
}
const Step4TitleSettings: React.FC<Step4TitleSettingsProps> = (props) => {
@@ -1,7 +1,10 @@
/**
* Step 5 生成预览组件
* 架构改造:移除后端预览生成,改为前端实时预览
* 左侧仅保留标题样式面板,视频在右侧 PreviewVideoPanel 实时播放
* Step 5 预览设置组件
*
* 前端实时预览架构:
* - 右侧面板使用 FrontendPreviewPlayer 实时播放素材片段
* - 标题样式可实时调整,CSS 层即时叠加预览
* - 点"确认生成"时触发一次服务器渲染
*/
import React from "react"
import { PlayCircleOutlined } from "@ant-design/icons"
@@ -10,7 +13,6 @@ import type { TitleSettings } from "../types"
import TitleStylePanel from "./title/TitleStylePanel"
interface Step5GeneratePreviewProps {
/* 标题样式 */
titleSettings: TitleSettings
onUpdatePosition: (position: string) => void
onUpdateFont: (font: string) => void
@@ -41,9 +43,7 @@ const Step5GeneratePreview: React.FC<Step5GeneratePreviewProps> = ({
<div className="xx-form-section">
<h3>🎬 </h3>
{/* 前端实时预览提示 */}
<div
className="xx-preview-tip"
style={{
display: "flex",
alignItems: "center",
@@ -57,11 +57,10 @@ const Step5GeneratePreview: React.FC<Step5GeneratePreviewProps> = ({
>
<PlayCircleOutlined style={{ fontSize: 18, color: "#3b82f6" }} />
<span style={{ fontSize: 13, color: "var(--text-secondary, #666)" }}>
</span>
</div>
{/* 标题样式面板 */}
<TitleStylePanel
settings={titleSettings}
onUpdatePosition={onUpdatePosition}
@@ -17,6 +17,16 @@ interface Step5VoiceSelectProps {
}
/** 格式化时长 mm:ss */
/** 获取素材实际时长(优先顶层 durationfallback 到 metadata.duration */
const getDuration = (item: AssetItem): number => {
return item.duration ?? (item.metadata?.duration as number) ?? 0
}
/** 获取素材实际文件大小 */
const getFileSize = (item: AssetItem): number => {
return item.file_size ?? (item.metadata?.file_size as number) ?? 0
}
const formatDuration = (seconds?: number): string => {
if (!seconds || seconds <= 0) return "00:00"
const m = Math.floor(seconds / 60)
@@ -89,7 +99,7 @@ const Step5VoiceSelect: React.FC<Step5VoiceSelectProps> = ({
// 如果启用了时长校验,且配音时长不足
if (totalVideoDuration > 0) {
const material = materials.find((m) => m.id === id)
if (material && (material.duration || 0) < totalVideoDuration) {
if (material && getDuration(material) < totalVideoDuration) {
setPendingVoiceId(id)
setDurationWarningOpen(true)
return
@@ -271,25 +281,24 @@ const Step5VoiceSelect: React.FC<Step5VoiceSelectProps> = ({
}}
>
<span style={{ display: "flex", alignItems: "center", gap: 4 }}>
{formatDuration(item.duration)}
{totalVideoDuration > 0 &&
(Number(item.duration) || 0) < Number(totalVideoDuration) && (
<span
style={{
color: "#ff4d4f",
fontSize: 11,
fontWeight: 500,
display: "inline-flex",
alignItems: "center",
gap: 2,
}}
>
<WarningOutlined />
</span>
)}
{formatDuration(getDuration(item))}
{totalVideoDuration > 0 && getDuration(item) < Number(totalVideoDuration) && (
<span
style={{
color: "#ff4d4f",
fontSize: 11,
fontWeight: 500,
display: "inline-flex",
alignItems: "center",
gap: 2,
}}
>
<WarningOutlined />
</span>
)}
</span>
<span>{formatFileSize(item.file_size)}</span>
<span>{formatFileSize(getFileSize(item))}</span>
</div>
</div>
)
@@ -318,7 +327,9 @@ const Step5VoiceSelect: React.FC<Step5VoiceSelectProps> = ({
return (
<p>
<strong>{pendingMaterial ? formatDuration(pendingMaterial.duration) : "--"}</strong>
<strong>
{pendingMaterial ? formatDuration(getDuration(pendingMaterial)) : "--"}
</strong>
<strong>{formatDuration(totalVideoDuration)}</strong>
@@ -14,6 +14,22 @@ interface Step6CoverSettingsProps {
assetIds?: string[]
/** 当前选中的模板 ID */
selectedTemplate?: string
/** Step4 标题设置,用于预览视频烧录标题 & 封面叠加标题 */
titleSettings?: import("../types").TitleSettings
/** 预览任务创建回调——将 task_id 暴露给父组件供 confirmGeneration 复用 */
onPreviewTaskCreated?: (taskId: string) => void
/** 从预览响应中提取到 source_edit_plan_id 时的回调 */
onSourceEditPlanIdExtracted?: (planId: string) => void
/** 配音模式 */
voiceMode?: "preset" | "custom" | "clone"
/** 选中的配音素材 ID */
selectedVoice?: string
/** 选中的克隆音色 ID */
selectedClonedVoice?: string
/** BGM 开关 */
bgm?: boolean
/** BGM 配置 */
bgmConfig?: { enabled: boolean; music_id?: string }
}
const Step6CoverSettings: React.FC<Step6CoverSettingsProps> = (props) => {
@@ -40,6 +56,14 @@ const Step6CoverSettings: React.FC<Step6CoverSettingsProps> = (props) => {
duration: props.duration,
assetIds: props.assetIds,
selectedTemplate: props.selectedTemplate,
titleSettings: props.titleSettings,
onPreviewTaskCreated: props.onPreviewTaskCreated,
onSourceEditPlanIdExtracted: props.onSourceEditPlanIdExtracted,
voiceMode: props.voiceMode,
selectedVoice: props.selectedVoice,
selectedClonedVoice: props.selectedClonedVoice,
bgm: props.bgm,
bgmConfig: props.bgmConfig,
})
const handleAutoGenerate = () => {
@@ -24,8 +24,6 @@ interface Step7ConfirmGenerateProps {
presetVoices: PresetVoiceItem[]
clonedVoices: VoiceClone[]
coverSettings: CoverConfig
generateCount: number
onGenerateCountChange: (count: number) => void
generating: boolean
generated: boolean
generateError: string | null
@@ -42,9 +40,6 @@ const Step7ConfirmGenerate: React.FC<Step7ConfirmGenerateProps> = (props) => {
title,
voiceName,
coverSummary,
generateCount,
handleDecrement,
handleIncrement,
generating,
generated,
generateError,
@@ -65,10 +60,6 @@ const Step7ConfirmGenerate: React.FC<Step7ConfirmGenerateProps> = (props) => {
title={title}
voiceName={voiceName}
coverSummary={coverSummary}
generateCount={generateCount}
generating={generating}
onDecrement={handleDecrement}
onIncrement={handleIncrement}
/>
<GenerationStatus
generating={generating}
@@ -1,7 +1,8 @@
/**
* 手动选择素材列表
* 手动选择素材列表 — 竖屏 9:16 卡片网格
* 交互:默认显示封面,点击播放按钮播放,播放中隐藏按钮,点击视频区域暂停
*/
import React, { useRef, useCallback } from "react"
import React, { useRef, useState, useCallback } from "react"
import { Typography } from "antd"
import type { AssetItem } from "@/api/assets"
@@ -14,39 +15,241 @@ interface ManualMaterialListProps {
onToggle: (materialId: string) => void
}
/** 秒数格式化为 mm:ss */
const fmtDuration = (seconds?: number): string => {
if (!seconds && seconds !== 0) return "--:--"
const m = Math.floor(seconds / 60)
const s = Math.floor(seconds % 60)
return `${String(m).padStart(2, "0")}:${String(s).padStart(2, "0")}`
}
/** 单个素材卡片 */
const MaterialCard: React.FC<{
asset: AssetItem
checked: boolean
onToggle: () => void
}> = ({ asset, checked, onToggle }) => {
const videoRef = useRef<HTMLVideoElement>(null)
const [isPlaying, setIsPlaying] = useState(false)
const isVideo = asset.mime_type?.startsWith("video/") ?? false
const thumbSrc = asset.thumbnail_url || undefined
const handlePlayToggle = useCallback(
(e: React.MouseEvent) => {
e.stopPropagation()
const video = videoRef.current
if (!video || !isVideo) return
if (isPlaying) {
video.pause()
setIsPlaying(false)
} else {
video.play().catch(() => {})
setIsPlaying(true)
}
},
[isPlaying, isVideo],
)
const handleVideoEnded = useCallback(() => {
setIsPlaying(false)
}, [])
const handleCardClick = useCallback(() => {
// 如果视频正在播放,点击卡片空白区域暂停视频
if (isPlaying) {
const video = videoRef.current
if (video) {
video.pause()
setIsPlaying(false)
}
return
}
onToggle()
}, [isPlaying, onToggle])
return (
<div
data-testid="material-card"
onClick={handleCardClick}
style={{
position: "relative",
aspectRatio: "9 / 16",
borderRadius: 10,
overflow: "hidden",
cursor: "pointer",
border: checked ? "2px solid var(--primary-color, #4f46e5)" : "2px solid transparent",
boxShadow: checked ? "0 0 0 2px rgba(79, 70, 229, 0.2)" : "0 1px 3px rgba(0, 0, 0, 0.1)",
background: "#1e293b",
transition: "all 0.15s ease",
}}
>
{/* 视频元素 */}
{isVideo && asset.file_url ? (
<video
ref={videoRef}
src={asset.file_url}
poster={thumbSrc}
muted
loop
playsInline
preload="metadata"
onEnded={handleVideoEnded}
style={{
width: "100%",
height: "100%",
objectFit: "cover",
display: "block",
}}
/>
) : thumbSrc ? (
<img
src={thumbSrc}
alt={asset.name}
style={{
width: "100%",
height: "100%",
objectFit: "cover",
display: "block",
}}
onError={(e) => {
const target = e.target as HTMLImageElement
target.style.display = "none"
}}
/>
) : (
<div
style={{
width: "100%",
height: "100%",
display: "flex",
alignItems: "center",
justifyContent: "center",
background: "linear-gradient(135deg, #334155, #1e293b)",
color: "rgba(255,255,255,0.5)",
fontSize: 28,
}}
>
{isVideo ? "🎬" : "🎵"}
</div>
)}
{/* 底部渐变遮罩 */}
<div
style={{
position: "absolute",
bottom: 0,
left: 0,
right: 0,
height: "50%",
background: "linear-gradient(0deg, rgba(0,0,0,0.6) 0%, transparent 100%)",
pointerEvents: "none",
}}
/>
{/* 播放按钮 — 播放中隐藏 */}
{!isPlaying && (
<div
onClick={handlePlayToggle}
style={{
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
width: 36,
height: 36,
borderRadius: "50%",
background: "rgba(99, 102, 241, 0.85)",
display: "flex",
alignItems: "center",
justifyContent: "center",
zIndex: 3,
transition: "opacity 0.2s ease",
}}
>
<svg width="16" height="16" viewBox="0 0 24 24" fill="white">
<path d="M8 5v14l11-7z" />
</svg>
</div>
)}
{/* 文件名(左下角) */}
<div
style={{
position: "absolute",
bottom: 6,
left: 6,
right: 50,
color: "white",
fontSize: 11,
fontWeight: 500,
whiteSpace: "nowrap",
overflow: "hidden",
textOverflow: "ellipsis",
textShadow: "0 1px 2px rgba(0,0,0,0.5)",
pointerEvents: "none",
zIndex: 1,
}}
>
{asset.name}
</div>
{/* 时长(右下角) */}
<div
style={{
position: "absolute",
bottom: 6,
right: 6,
background: "rgba(0, 0, 0, 0.7)",
color: "white",
padding: "1px 5px",
borderRadius: 3,
fontSize: 10,
fontWeight: 600,
fontVariantNumeric: "tabular-nums",
pointerEvents: "none",
zIndex: 1,
}}
>
{fmtDuration(asset.duration)}
</div>
{/* 选中勾选标记(左上角) */}
{checked && (
<div
data-testid="material-card-check"
aria-label="已选中"
style={{
position: "absolute",
top: 6,
left: 6,
width: 20,
height: 20,
borderRadius: "50%",
background: "var(--primary-color, #4f46e5)",
display: "flex",
alignItems: "center",
justifyContent: "center",
color: "white",
fontSize: 12,
fontWeight: 700,
zIndex: 2,
pointerEvents: "none",
}}
>
</div>
)}
</div>
)
}
const ManualMaterialList: React.FC<ManualMaterialListProps> = ({
materials,
materialsLoading,
selectedMaterials,
onToggle,
}) => {
// 追踪当前正在播放的视频元素,确保同时只有一个视频播放
const activeVideoRef = useRef<HTMLVideoElement | null>(null)
const handleVideoMouseEnter = useCallback((e: React.MouseEvent<HTMLVideoElement>) => {
const video = e.currentTarget
// 暂停之前正在播放的视频(检查是否仍在 DOM 中)
if (
activeVideoRef.current &&
activeVideoRef.current !== video &&
document.body.contains(activeVideoRef.current)
) {
activeVideoRef.current.pause()
activeVideoRef.current.currentTime = 0
}
activeVideoRef.current = video
video.play().catch(() => {})
}, [])
const handleVideoMouseLeave = useCallback((e: React.MouseEvent<HTMLVideoElement>) => {
const video = e.currentTarget
video.pause()
video.currentTime = 0
if (activeVideoRef.current === video) {
activeVideoRef.current = null
}
}, [])
return (
<div style={{ marginTop: 14 }}>
{materialsLoading ? (
@@ -56,145 +259,21 @@ const ManualMaterialList: React.FC<ManualMaterialListProps> = ({
</Text>
) : (
<div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
{materials.items.map((m) => {
const checked = selectedMaterials.includes(m.id)
const isVideo = m.mime_type?.startsWith("video/") ?? false
const thumbSrc = m.thumbnail_url || undefined
return (
<label
key={m.id}
style={{
display: "flex",
alignItems: "center",
gap: 10,
padding: "8px 12px",
background: checked ? "var(--primary-soft, #eef2ff)" : "#f8fafc",
borderRadius: 10,
cursor: "pointer",
border: checked
? "1px solid var(--primary-color, #4f46e5)"
: "1px solid transparent",
transition: "all 0.15s ease",
}}
>
<input
type="checkbox"
checked={checked}
onChange={() => onToggle(m.id)}
style={{
accentColor: "var(--primary-color, #4f46e5)",
flexShrink: 0,
}}
/>
{/* 缩略图预览 48×48 */}
<div
style={{
width: 48,
height: 48,
borderRadius: 6,
overflow: "hidden",
background: "#e2e8f0",
flexShrink: 0,
display: "flex",
alignItems: "center",
justifyContent: "center",
}}
>
{isVideo && m.file_url ? (
<video
src={m.file_url}
poster={m.thumbnail_url || undefined}
muted
loop
playsInline
preload="none"
onMouseEnter={handleVideoMouseEnter}
onMouseLeave={handleVideoMouseLeave}
style={{
width: "100%",
height: "100%",
objectFit: "cover",
cursor: "pointer",
}}
/>
) : thumbSrc ? (
<img
src={thumbSrc}
alt={m.name}
style={{
width: "100%",
height: "100%",
objectFit: "cover",
}}
onError={(e) => {
const target = e.target as HTMLImageElement
target.style.display = "none"
const fallback = target.nextElementSibling as HTMLElement | null
if (fallback) fallback.style.display = "flex"
}}
/>
) : null}
{!thumbSrc && !isVideo && (
<span
style={{
fontSize: 20,
opacity: 0.5,
display: "flex",
}}
>
🎵
</span>
)}
{!thumbSrc && isVideo && !m.file_url && (
<span
style={{
fontSize: 20,
opacity: 0.5,
display: "flex",
}}
>
🎬
</span>
)}
{/* img onError 时显示的 fallback(初始隐藏) */}
{thumbSrc && !(isVideo && m.file_url) && (
<span
style={{
fontSize: 20,
opacity: 0.5,
display: "none",
}}
>
{isVideo ? "🎬" : "🎵"}
</span>
)}
</div>
<span
style={{
fontSize: 13,
color: "var(--text-primary)",
flex: 1,
minWidth: 0,
overflow: "hidden",
textOverflow: "ellipsis",
whiteSpace: "nowrap",
}}
>
{m.name}
</span>
<span
style={{
fontSize: 11,
color: "var(--text-tertiary, #94a3b8)",
flexShrink: 0,
}}
>
{m.mime_type?.split("/")?.[1]?.toUpperCase() ?? "FILE"}
</span>
</label>
)
})}
<div
style={{
display: "grid",
gridTemplateColumns: "repeat(auto-fill, minmax(110px, 1fr))",
gap: 10,
}}
>
{materials.items.map((asset) => (
<MaterialCard
key={asset.id}
asset={asset}
checked={selectedMaterials.includes(asset.id)}
onToggle={() => onToggle(asset.id)}
/>
))}
</div>
)}
</div>
@@ -1,5 +1,4 @@
import React from "react"
import { MinusOutlined, PlusOutlined } from "@ant-design/icons"
interface SummaryCardProps {
templateName: string
@@ -7,10 +6,6 @@ interface SummaryCardProps {
title: string
voiceName: string
coverSummary: string
generateCount: number
generating: boolean
onDecrement: () => void
onIncrement: () => void
}
const SummaryCard: React.FC<SummaryCardProps> = ({
@@ -19,10 +14,6 @@ const SummaryCard: React.FC<SummaryCardProps> = ({
title,
voiceName,
coverSummary,
generateCount,
generating,
onDecrement,
onIncrement,
}) => {
return (
<div className="xx-summary-card">
@@ -46,29 +37,6 @@ const SummaryCard: React.FC<SummaryCardProps> = ({
<span className="xx-summary-label"></span>
<span className="xx-summary-value">{coverSummary}</span>
</div>
<div className="xx-summary-row">
<span className="xx-summary-label"></span>
<span className="xx-summary-value">
<div className="xx-count-stepper">
<button
className="xx-count-stepper-btn"
disabled={generateCount <= 1 || generating}
onClick={onDecrement}
>
<MinusOutlined />
</button>
<span className="xx-count-stepper-value">{generateCount}</span>
<button
className="xx-count-stepper-btn"
disabled={generateCount >= 10 || generating}
onClick={onIncrement}
>
<PlusOutlined />
</button>
<span className="xx-count-stepper-hint"></span>
</div>
</span>
</div>
</div>
)
}
@@ -2,6 +2,7 @@
* 标题预设样式网格
*/
import React from "react"
import { getFontFamily } from "../../constants"
interface TitlePresetItem {
key: string
@@ -35,7 +36,7 @@ const TitlePresetsGrid: React.FC<TitlePresetsGridProps> = ({
>
<span
className="xx-title-preset-preview-text"
style={{ ...p.previewStyle, ...(fontFamily ? { fontFamily } : {}) }}
style={{ ...p.previewStyle, fontFamily: getFontFamily(fontFamily || "思源黑体") }}
>
</span>
@@ -94,7 +94,7 @@ const TitleStylePanel: React.FC<TitleStylePanelProps> = ({
className="xx-slider"
type="range"
min={12}
max={48}
max={128}
value={settings.size}
onChange={(e) => onUpdateSize(Number(e.target.value))}
/>
+15
View File
@@ -56,6 +56,21 @@ export const FONT_OPTIONS = [
"华康俪金黑",
]
/* ── 标题字体 CSS font-family 映射(中文显示名 → 浏览器可识别的字体栈) ── */
export const FONT_FAMILY_MAP: Record<string, string> = {
: '"Source Han Sans SC", "Noto Sans SC", "PingFang SC", "Microsoft YaHei", sans-serif',
: '"Source Han Serif SC", "Noto Serif SC", "Songti SC", "SimSun", serif',
: '"PingFang SC", -apple-system, "Helvetica Neue", sans-serif',
PingFang: '"PingFang SC", -apple-system, "Helvetica Neue", sans-serif',
: '"Microsoft YaHei", "PingFang SC", sans-serif',
: '"KaiTi", "STKaiti", "DFKai-SB", serif',
: '"华康俪金黑", "DFLiJinHei-W8", "Source Han Sans SC", "Microsoft YaHei", sans-serif',
}
export function getFontFamily(font: string): string {
return FONT_FAMILY_MAP[font] || FONT_FAMILY_MAP["思源黑体"]
}
/* ── 标题样式预设 ── */
export const TITLE_PRESETS = [
{
+38 -57
View File
@@ -113,6 +113,14 @@
align-items: start;
}
.xx-generate-layout.full-width {
grid-template-columns: 1fr;
}
.xx-generate-layout.full-width .xx-generate-right-col {
display: none;
}
/* ============================================================
左侧表单区 generate-form
============================================================ */
@@ -186,16 +194,16 @@
============================================================ */
.xx-choice-list {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 12px;
grid-template-columns: repeat(6, 1fr);
gap: 8px;
}
.xx-choice-item {
position: relative;
background: var(--bg-primary);
border: 2px solid var(--border-color);
border-radius: var(--radius-md);
padding: 14px;
border-radius: var(--radius-sm);
padding: 6px;
cursor: pointer;
transition: 0.18s ease;
text-align: center;
@@ -211,18 +219,20 @@
}
.xx-choice-thumb {
height: 60px;
width: 33%;
max-width: 52px;
height: 24px;
border-radius: var(--radius-sm);
display: grid;
place-items: center;
color: var(--text-inverse);
font-size: 24px;
font-size: 12px;
font-weight: 700;
margin-bottom: 10px;
margin: 0 auto 4px;
}
.xx-choice-item h4 {
margin: 0 0 4px;
margin: 0 0 2px;
font-size: 13px;
font-weight: 600;
color: var(--text-primary);
@@ -230,7 +240,7 @@
.xx-choice-item p {
margin: 0;
font-size: 11px;
font-size: 12px;
color: var(--text-tertiary);
}
@@ -1055,7 +1065,7 @@
}
.xx-choice-list {
grid-template-columns: repeat(2, 1fr);
grid-template-columns: repeat(4, 1fr);
}
.xx-voice-choice-list {
@@ -1280,53 +1290,6 @@
}
}
/* ── 生成数量步进器 ── */
.xx-count-stepper {
display: inline-flex;
align-items: center;
gap: 6px;
}
.xx-count-stepper-btn {
display: inline-flex;
align-items: center;
justify-content: center;
width: 28px;
height: 28px;
border: 1px solid var(--border-primary, #e2e8f0);
border-radius: 8px;
background: var(--bg-surface, #fff);
color: var(--text-secondary, #64748b);
font-size: 13px;
cursor: pointer;
transition: all 0.15s;
}
.xx-count-stepper-btn:hover:not(:disabled) {
border-color: var(--primary-400, #818cf8);
color: var(--primary-600, #4f46e5);
background: var(--primary-50, #eef2ff);
}
.xx-count-stepper-btn:disabled {
opacity: 0.35;
cursor: not-allowed;
}
.xx-count-stepper-value {
min-width: 24px;
text-align: center;
font-size: 16px;
font-weight: 600;
color: var(--text-primary, #1e293b);
}
.xx-count-stepper-hint {
font-size: 12px;
color: var(--text-tertiary, #94a3b8);
margin-left: 2px;
}
/* ── 素材选择模式切换 Tab ── */
.xx-material-mode-tabs {
display: flex;
@@ -2309,6 +2272,8 @@
.xx-cover-preview-box {
position: relative;
aspect-ratio: 9 / 16;
max-width: 180px;
margin: 0 auto;
background: var(--bg-tertiary);
border-radius: var(--radius-md);
overflow: hidden;
@@ -2523,9 +2488,25 @@
.xx-generate-right-col {
display: flex;
flex-direction: column;
align-items: center;
gap: 16px;
}
/* ── 内联视频播放器(右侧) ── */
.xx-inline-video-player {
width: 100%;
max-width: 320px;
background: var(--bg-surface, #fff);
border: 1px solid var(--border-primary, #e2e8f0);
border-radius: 16px;
padding: 16px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
}
.xx-inline-video-player video {
background: #000;
}
.xx-preview-header {
display: flex;
align-items: center;
@@ -18,7 +18,17 @@ export interface UseGenerateVideoProps {
duration: number
autoSubtitles: boolean
bgm: boolean
generateCount: number
/** 当前草稿 IDURL 参数 edit_plan_id,用于后端回写任务关联) */
sourceEditPlanId?: string | null
/** 预览任务 ID(由 useStep6Cover 创建后写入,供 confirmGeneration 复用预览产物) */
previewTaskId?: string | null
/** BGM 配置(来自模板 bgm_config,受 bgm 开关控制) */
bgmConfig?: {
enabled: boolean
music_id?: string
}
/** 生成成功后的回调(用于清除持久化的 previewTaskId 等状态) */
onGenerationSuccess?: () => void
}
/** 生成阶段 */
@@ -1,87 +1,146 @@
import { useRef, useCallback } from "react"
import { message } from "antd"
import { getGenerationStatus, getGenerationTaskResults } from "@/api/template-editor"
import axios from "axios"
import { getGenerationTask } from "@/api/tasks/tasks"
import { getGenerationTaskResults } from "@/api/template-editor"
import { safeExtractError } from "./errorUtils"
interface UseGenerationPollingOptions {
templateId: string
onProgress: (progress: number) => void
onComplete: (videos: unknown[]) => void
onFailed: (errorMsg: string) => void
}
/** 最大连续错误次数(仅对可重试错误),超过后终止轮询 */
const MAX_RETRYABLE_ERRORS = 10
/** 获取结果的最大重试次数 */
const MAX_RESULTS_RETRIES = 3
/**
* 生成状态轮询 Hook
* 轮询生成状态,更新进度,处理完成/失败
* 生成状态轮询 Hookv2 — 改用 /generation/tasks/{task_id}
*
* 旧版轮询 GET /templates/{id}/editor/generation-status 依赖 plan 维度状态,
* 在编辑流程数据链路断裂时拿不到 task_id。新版直接使用 POST /generation/tasks
* 返回的 task_id 轮询任务详情,不再依赖 plan。
*
* 错误处理:
* - 4xx(尤其 404)视为不可恢复,立即 onFailed,不再重试
* - 5xx / 网络错误重试,最多连续 MAX_RETRYABLE_ERRORS 次
* - 任务完成后获取结果失败会重试 MAX_RESULTS_RETRIES 次,仍失败则 onFailed
*/
export const useGenerationPolling = ({
templateId,
onProgress,
onComplete,
onFailed,
}: UseGenerationPollingOptions) => {
const progressTimer = useRef<ReturnType<typeof setTimeout>>()
const cancelledRef = useRef(false)
const clearTimer = useCallback(() => {
cancelledRef.current = true
if (progressTimer.current) {
clearTimeout(progressTimer.current)
progressTimer.current = undefined
}
}, [])
const startPolling = useCallback(() => {
const poll = async () => {
/** 任务完成后拉取结果列表,带重试 */
const fetchResultsWithRetry = useCallback(
async (taskId: string, attempt = 0): Promise<unknown[] | null> => {
try {
const data = await getGenerationStatus(templateId)
if (data.plan_status === "completed") {
onProgress(100)
// 获取生成的视频结果
let videos: unknown[] = []
if (data.generation_task_id) {
try {
videos = await getGenerationTaskResults(data.generation_task_id)
} catch (err) {
console.error("[获取生成结果失败]", err)
}
}
onComplete(videos)
message.success("视频生成完成!")
return
return await getGenerationTaskResults(taskId)
} catch (err) {
if (cancelledRef.current) return null
console.error(`[获取生成结果失败] 第 ${attempt + 1}`, err)
if (attempt < MAX_RESULTS_RETRIES - 1) {
await new Promise((resolve) => setTimeout(resolve, 1000 * (attempt + 1)))
return fetchResultsWithRetry(taskId, attempt + 1)
}
if (data.plan_status === "failed") {
const dataAny = data as unknown as Record<string, unknown>
const rawMsg =
dataAny.error_message ||
dataAny.error ||
dataAny.message ||
(Array.isArray(data.clips)
? (data.clips as { status: string; error_message?: string }[]).find(
(c) => c.status === "failed",
)?.error_message
: undefined) ||
"视频生成失败,请联系管理员或重试"
const errorMsg = safeExtractError(rawMsg)
console.error("[生成失败] templateId:", templateId, "响应:", data)
onFailed(errorMsg)
message.error(errorMsg)
return
}
const clips = data.clips || []
const total = clips.length || 1
const done = (clips as { status: string }[]).filter((c) => c.status === "completed").length
onProgress(Math.round((done / total) * 100))
progressTimer.current = setTimeout(poll, 2000)
} catch (pollErr) {
console.error("[轮询出错] templateId:", templateId, pollErr)
progressTimer.current = setTimeout(poll, 3000)
return null
}
}
},
[],
)
progressTimer.current = setTimeout(poll, 2000)
}, [templateId, onProgress, onComplete, onFailed])
const startPolling = useCallback(
(taskId: string) => {
cancelledRef.current = false
let consecutiveErrors = 0
const poll = async () => {
if (cancelledRef.current) return
try {
const task = await getGenerationTask(taskId)
consecutiveErrors = 0
if (task.status === "completed") {
onProgress(100)
const videos = await fetchResultsWithRetry(taskId)
if (cancelledRef.current) return
if (videos === null) {
const errorMsg = "视频已生成,但获取结果列表失败,请稍后在任务列表查看"
console.error("[生成结果获取失败] taskId:", taskId)
onFailed(errorMsg)
message.error(errorMsg)
return
}
onComplete(videos)
message.success("视频生成完成!")
return
}
if (task.status === "failed" || task.status === "cancelled") {
const rawMsg =
task.error_info?.error_message ||
task.error_message ||
(task.status === "cancelled" ? "任务已取消" : "视频生成失败,请联系管理员或重试")
const errorMsg = safeExtractError(rawMsg)
console.error("[生成失败] taskId:", taskId, "响应:", task)
onFailed(errorMsg)
message.error(errorMsg)
return
}
// pending / waiting / running — 继续轮询
const pct = Math.max(0, Math.min(99, Math.round(Number(task.progress) || 0)))
onProgress(pct)
progressTimer.current = setTimeout(poll, 2000)
} catch (pollErr) {
if (cancelledRef.current) return
console.error("[轮询出错] taskId:", taskId, pollErr)
// 4xx 不可恢复,立即失败
const status = axios.isAxiosError(pollErr) ? pollErr.response?.status : undefined
if (status && status >= 400 && status < 500) {
const msg =
(axios.isAxiosError(pollErr) &&
(pollErr.response?.data as { detail?: string; message?: string } | undefined)
?.detail) ||
(axios.isAxiosError(pollErr) &&
(pollErr.response?.data as { detail?: string; message?: string } | undefined)
?.message) ||
`查询任务失败 (${status})`
const errorMsg = safeExtractError(msg)
onFailed(errorMsg)
message.error(errorMsg)
return
}
consecutiveErrors += 1
if (consecutiveErrors >= MAX_RETRYABLE_ERRORS) {
const errorMsg = "任务状态查询连续失败,请稍后在任务列表查看结果"
onFailed(errorMsg)
message.error(errorMsg)
return
}
progressTimer.current = setTimeout(poll, 3000)
}
}
progressTimer.current = setTimeout(poll, 1500)
},
[onProgress, onComplete, onFailed, fetchResultsWithRetry],
)
return { startPolling, clearTimer }
}
@@ -9,8 +9,21 @@ import { createFile } from "mp4box"
import type { Movie, Sample } from "mp4box"
// ── 常量 ──
/** 初始化预解码最大帧数(约 2 秒 @30fps),后续帧通过 decodeAroundPosition 按需解码 */
const MAX_INIT_FRAMES = 60
/**
* 规范化 mp4box 提取的 codec 字符串为 WebCodecs 兼容格式
* mp4box 返回的 codec 可能包含 mp4box 特有后缀(如 avc1.640028),
* WebCodecs 要求标准 ISO BMFF codec string(如 avc1.640028
* 大部分情况下格式一致,但需要做防御性处理
*/
function normalizeCodecString(codec: string): string {
// mp4box 有时返回带空格的 codec,去掉
const trimmed = codec.trim()
// HEVC: mp4box 可能返回 hev1.1.6.L93.B0 或 hvc1.1.6.L93.B0
// WebCodecs 接受 hev1.x.x 或 hvc1.x.x,两者都可
// H.264: mp4box 返回 avc1.640028WebCodecs 也接受
return trimmed
}
// ── MP4 Box 解析辅助函数 ──
@@ -96,7 +109,7 @@ class FrameQueue {
private frames: FrameEntry[] = []
private maxSize: number
constructor(maxSize = 5) {
constructor(maxSize = 200) {
this.maxSize = maxSize
}
@@ -108,24 +121,36 @@ class FrameQueue {
this.frames.push(entry)
}
/** 获取当前时间戳应显示的帧 */
/** 获取当前时间戳应显示的帧(二分查找,O(log n) */
getCurrentFrame(timestamp: number): VideoFrame | null {
let best: FrameEntry | null = null
let bestIdx = -1
for (let i = 0; i < this.frames.length; i++) {
const f = this.frames[i]
if (f.pts <= timestamp + 0.01) {
best = f
bestIdx = i
if (this.frames.length === 0) return null
const target = timestamp + 0.01
// 找到最后一个 pts <= target 的帧(右边界)
let lo = 0,
hi = this.frames.length - 1,
bestIdx = -1
while (lo <= hi) {
const mid = (lo + hi) >> 1
if (this.frames[mid].pts <= target) {
bestIdx = mid
lo = mid + 1
} else {
hi = mid - 1
}
}
if (bestIdx < 0) return null
// 关闭并移除 bestIdx 之前的所有已播放帧
for (let i = 0; i < bestIdx; i++) {
this.frames[i].frame.close()
}
if (bestIdx >= 0) {
this.frames = this.frames.slice(bestIdx)
}
return best?.frame ?? null
this.frames.splice(0, bestIdx)
// 此时 bestIdx 对应帧已在索引 0
return this.frames[0]?.frame ?? null
}
clear() {
@@ -172,6 +197,10 @@ export interface CanvasPlayerState {
duration: number
isReady: boolean
isBuffering: boolean
/** WebCodecs 解码失败时为 true,调用方应 fallback 到原生 video 播放 */
hasDecodeError: boolean
/** 解码错误信息(用于 UI 展示) */
errorMessage: string
}
export interface CanvasPlayerControls {
@@ -209,21 +238,29 @@ export function useCanvasPlayer(
stroke?: boolean
shadow?: boolean
},
onError?: (error: Error) => void,
enabled: boolean = true,
) {
const [state, setState] = useState<CanvasPlayerState>({
hasSupport: isWebCodecsSupported(),
hasSupport: enabled && isWebCodecsSupported(),
isPlaying: false,
currentTime: 0,
duration: 0,
isReady: false,
isBuffering: false,
hasDecodeError: false,
errorMessage: "",
})
// ── 内部引用 ──
const decoderRef = useRef<VideoDecoder | null>(null)
const frameQueueRef = useRef(new FrameQueue(600))
/** 已解码的片段索引集合,用于按需解码(先标记防重入,失败时移除允许重试) */
const decodedSegmentsRef = useRef(new Set<number>())
const frameQueueRef = useRef(new FrameQueue(200))
/** 每个片段持久化解码器,避免每次新建导致关键帧错误 */
const segmentDecodersRef = useRef(new Map<number, VideoDecoder>())
/** 每个片段已送入解码器的 sample 游标(用于续解码) */
const segmentSampleCursorRef = useRef(new Map<number, number>())
/** 后台补充解码是否正在运行(防重入) */
const isFeedingRef = useRef(false)
/** 解码代数计数器,seek 时递增以作废正在进行的异步解码 */
const decodeGenerationRef = useRef(0)
const rafRef = useRef<number>(0)
@@ -234,6 +271,8 @@ export function useCanvasPlayer(
const videoDimRef = useRef<{ width: number; height: number }>({ width: 0, height: 0 })
const isDestroyedRef = useRef(false)
const lastProgressUpdateRef = useRef<number>(0)
const onErrorRef = useRef(onError)
onErrorRef.current = onError
// 计算总时长
const totalDuration = segments.reduce((sum, seg) => sum + (seg.endTime - seg.startTime), 0)
@@ -367,7 +406,7 @@ export function useCanvasPlayer(
globalEndTime: globalStart + (segment.endTime - segment.startTime),
trackId: videoTrack.id ?? 1,
timescale: videoTrack.timescale ?? 90000,
codec: videoTrack.codec ?? "avc1.42E01E",
codec: normalizeCodecString(videoTrack.codec ?? "avc1.42E01E"),
videoWidth: videoTrack.track_width || 1280,
videoHeight: videoTrack.track_height || 720,
description,
@@ -451,87 +490,91 @@ export function useCanvasPlayer(
[segments, extractCodecDescription],
)
// ── 初始化 VideoDecoder 并解码指定片段 ──
const decodeSegment = useCallback(
async (_buffer: ArrayBuffer, meta: SegmentMeta, maxFrames?: number): Promise<void> => {
if (isDestroyedRef.current) return
// ── 解码片段的一批帧(使用持久化解码器,支持从断点续解码) ──
/**
* @param segIdx 片段索引
* @param maxFrames 本次最多解码多少帧
*/
const decodeSegmentBatch = useCallback(
async (segIdx: number, maxFrames: number = 60): Promise<number> => {
if (isDestroyedRef.current) return 0
const metas = segmentMetaRef.current
const meta = metas[segIdx]
if (!meta) return 0
const buffer = segmentDataRef.current.get(meta.assetId)
if (!buffer) return 0
let decoderReady = false
const gen = decodeGenerationRef.current
let decoder = segmentDecodersRef.current.get(segIdx)
let cursor = segmentSampleCursorRef.current.get(segIdx) ?? 0
const samples = meta.samples
// 配置解码器(每个片段可能需要不同的 codec/分辨率
const decoder = new VideoDecoder({
output: (frame: VideoFrame) => {
// 从第一帧获取实际尺寸
if (videoDimRef.current.width === 0 || videoDimRef.current.height === 0) {
videoDimRef.current = { width: frame.codedWidth, height: frame.codedHeight }
console.log(
`[useCanvasPlayer] Actual frame size: ${frame.codedWidth}x${frame.codedHeight}`,
)
}
const localTime = frame.timestamp / 1_000_000
const globalTime = localTime + meta.globalStartTime
frameQueueRef.current.push({
frame,
pts: globalTime,
duration: (frame.duration ?? 0) / 1_000_000,
})
},
error: (e: DOMException) => {
console.error("[useCanvasPlayer] Decoder error:", e)
},
})
console.log("[useCanvasPlayer] configure:", {
codec: meta.codec,
description: meta.description,
descriptionByteLength: meta.description?.byteLength,
videoWidth: meta.videoWidth,
videoHeight: meta.videoHeight,
})
try {
await decoder.configure({
codec: meta.codec,
...(meta.description ? { description: meta.description } : {}),
// 如果还没有解码器,新建一个(从关键帧开始,不会报 key frame 错误
if (!decoder || decoder.state === "closed") {
decoder = new VideoDecoder({
output: (frame: VideoFrame) => {
if (videoDimRef.current.width === 0 || videoDimRef.current.height === 0) {
videoDimRef.current = { width: frame.codedWidth, height: frame.codedHeight }
}
const localTime = frame.timestamp / 1_000_000
const globalTime = localTime + meta.globalStartTime
frameQueueRef.current.push({
frame,
pts: globalTime,
duration: (frame.duration ?? 0) / 1_000_000,
})
},
error: (e: DOMException) => {
console.error(`[useCanvasPlayer] Segment ${segIdx} decoder error:`, e)
// 重置该片段的解码器和游标,允许重试
segmentDecodersRef.current.delete(segIdx)
segmentSampleCursorRef.current.set(segIdx, 0)
},
})
decoderRef.current = decoder
decoderReady = true
// 标记缓冲结束,让 UI 开始渲染
try {
await decoder.configure({
codec: meta.codec,
...(meta.description ? { description: meta.description } : {}),
})
} catch (err) {
console.error(`[useCanvasPlayer] Segment ${segIdx} configure failed:`, err)
const error = err instanceof Error ? err : new Error(String(err))
setState((s) => ({
...s,
isBuffering: false,
hasDecodeError: true,
errorMessage: `视频解码失败: ${error.message || "不支持的编解码器"}`,
}))
onErrorRef.current?.(error)
return 0
}
segmentDecodersRef.current.set(segIdx, decoder)
cursor = 0
// 标记缓冲结束
setState((s) => ({ ...s, isBuffering: false }))
} catch (err) {
console.error("[useCanvasPlayer] Decoder configure failed for segment:", err)
return
}
if (!decoderReady) return
if (decoder.state !== "configured") return 0
// 使用 demuxSegment 中已提取并过滤的 samples(前端切片
const samplesCollected = meta.samples
console.log(
`[useCanvasPlayer] Segment ${meta.assetId}: ${samplesCollected.length} samples to decode`,
)
if (samplesCollected.length === 0) {
console.warn("[useCanvasPlayer] No samples to decode for segment", meta.assetId)
return
}
// 送入解码器
let decodedCount = 0
let skippedCount = 0
let decodeErrors = 0
for (const sample of samplesCollected) {
if (!sample.data || isDestroyedRef.current) {
skippedCount++
// 从 cursor 继续喂 sample(流水线批量提交,不 await 单个 decode
let decoded = 0
let si = cursor
while (si < samples.length && decoded < maxFrames) {
if (decodeGenerationRef.current !== gen || isDestroyedRef.current) break
if ((decoder.state as string) === "closed") break
// 帧队列快满时停止提交(这才是真正的背压)
if (frameQueueRef.current.size >= 180) break
// 解码器内部队列积压过多时短暂让出线程(阈值64,给硬件足够流水线深度)
if (decoder.decodeQueueSize > 64) {
await new Promise((r) => setTimeout(r, 5))
continue
}
if (decoder.state === "closed") break
// 初始化阶段限制解码帧数,避免帧缓冲溢出
if (maxFrames && decodedCount >= maxFrames) {
console.log(
`[useCanvasPlayer] Segment ${meta.assetId}: init decode limited to ${maxFrames} frames`,
)
break
}
const sample = samples[si]
si++
if (!sample.data) continue
const chunk = new EncodedVideoChunk({
type: sample.is_sync ? "key" : "delta",
@@ -541,85 +584,73 @@ export function useCanvasPlayer(
})
try {
await decoder.decode(chunk) // 修复:await 捕获异步错误
decodedCount++
decoder.decode(chunk)
decoded++
} catch (e) {
decodeErrors++
console.warn(`[useCanvasPlayer] Decode chunk error (${decodeErrors}):`, e)
// 连续 3 次解码失败,放弃当前片段
if (decodeErrors >= 3) {
console.error("[useCanvasPlayer] Too many decode errors, aborting segment")
break
}
console.warn(`[useCanvasPlayer] Segment ${segIdx} decode error:`, e)
break
}
}
cursor = si
segmentSampleCursorRef.current.set(segIdx, cursor)
// 等待解码器输出帧(最多500ms)
if (decoded > 0 && (decoder.state as string) === "configured") {
let waited = 0
while (frameQueueRef.current.size < Math.min(decoded, 10) && waited < 500) {
await new Promise((r) => setTimeout(r, 20))
waited += 20
if (isDestroyedRef.current) break
}
}
console.log(
`[useCanvasPlayer] Segment ${meta.assetId}: decoded ${decodedCount}, skipped ${skippedCount}, errors ${decodeErrors}, decoder.state=${decoder.state}`,
`[useCanvasPlayer] Segment ${segIdx} decoded ${decoded} frames, queue size: ${frameQueueRef.current.size}`,
)
// flush 仅在解码器状态正常时执行
if (decoder.state === "configured") {
try {
await decoder.flush()
console.log(`[useCanvasPlayer] Segment ${meta.assetId}: flush complete`)
} catch (e) {
console.warn("[useCanvasPlayer] Decoder flush error:", e)
}
}
return decoded
},
[],
)
// ── 后台持续补充帧 ──
/**
* 按需解码当前播放位置 ±1 个片段。
* 在渲染循环中定期调用,避免一次性解码所有片段导致环形缓冲区溢出丢帧。
* 使用"先标记再解码"模式防止并发重复解码,失败时移除标记允许重试。
* 根据当前播放时间,确保队列中有足够缓冲
* 播放循环每 200ms 调用一次
*/
const decodeAroundPosition = useCallback(
const feedFrames = useCallback(
async (currentTime: number) => {
const metas = segmentMetaRef.current
if (!metas || metas.length === 0) return
if (isFeedingRef.current) return
isFeedingRef.current = true
try {
const metas = segmentMetaRef.current
if (!metas || metas.length === 0) return
// 记录当前代数,seek 后代数变化则中止
const gen = decodeGenerationRef.current
// 队列帧数充足时不解码(目标:保持 >= 80 帧缓冲)
if (frameQueueRef.current.size >= 80) return
let targetIdx = -1
let acc = 0
for (let i = 0; i < metas.length; i++) {
const dur = metas[i].globalEndTime - metas[i].globalStartTime
if (currentTime < acc + dur) {
targetIdx = i
break
// 找到当前播放的片段
let targetIdx = 0
let acc = 0
for (let i = 0; i < metas.length; i++) {
const dur = metas[i].globalEndTime - metas[i].globalStartTime
if (currentTime < acc + dur) {
targetIdx = i
break
}
acc += dur
}
acc += dur
}
if (targetIdx === -1) targetIdx = metas.length - 1
for (
let i = Math.max(0, targetIdx - 1);
i <= Math.min(metas.length - 1, targetIdx + 1);
i++
) {
// seek 已作废当前解码任务
if (decodeGenerationRef.current !== gen) return
if (decodedSegmentsRef.current.has(i)) continue
const meta = metas[i]
const buffer = segmentDataRef.current.get(meta.assetId)
if (!buffer) continue
// 先标记为解码中,防止下一帧渲染时重复发起解码
decodedSegmentsRef.current.add(i)
try {
await decodeSegment(buffer, meta, 300)
} catch (e) {
// 解码失败则移除标记,允许后续重试
decodedSegmentsRef.current.delete(i)
console.warn(`[useCanvasPlayer] 按需解码片段 ${i} 失败:`, e)
// 依次补充:当前片段 → 下一个片段 → 再下一个
for (let offset = 0; offset <= 2; offset++) {
const idx = targetIdx + offset
if (idx >= metas.length) break
if (frameQueueRef.current.size >= 180) break
await decodeSegmentBatch(idx, 60)
}
// await 后再次检查代数,seek 期间不更新标记
if (decodeGenerationRef.current !== gen) return
} finally {
isFeedingRef.current = false
}
},
[decodeSegment],
[decodeSegmentBatch],
)
// ── 标题绘制 ──
@@ -636,7 +667,6 @@ export function useCanvasPlayer(
// 按 "/" 分割为多行("/" 作为手动换行符)
const lines = title.text.split(/[//⁄∕]/)
console.log("[drawTitle] 原始标题:", JSON.stringify(title.text), "分割后:", lines)
const lineHeight = fontSize * 1.3
const totalHeight = lines.length * lineHeight
@@ -748,8 +778,10 @@ export function useCanvasPlayer(
}
return s
})
// 按需解码当前 ±1 片段
decodeAroundPosition(currentTime)
// 后台补充帧:队列不足时自动续解码
if (frameQueueRef.current.size < 80) {
void feedFrames(currentTime)
}
}
if (currentTime >= totalDuration) {
@@ -758,29 +790,46 @@ export function useCanvasPlayer(
}
rafRef.current = requestAnimationFrame(renderFrame)
}, [canvasRef, totalDuration, titleSettings, drawTitle, computeDrawRect, decodeAroundPosition])
}, [canvasRef, totalDuration, titleSettings, drawTitle, computeDrawRect, feedFrames])
// ── 播放控制 ──
const play = useCallback(async () => {
if (!state.hasSupport || isDestroyedRef.current) return
// 重播场景:currentTime 已回到起点但 decodedSegmentsRef 仍有旧标记
// 此时 FrameQueue 中旧帧已被淘汰,需清空标记让 decodeAroundPosition 重新解码
if (state.currentTime <= 0.1 && decodedSegmentsRef.current.size > 0) {
// 重播:必须关闭旧解码器、清空队列、重置游标,从头重新解码
if (state.currentTime >= totalDuration - 0.1 || state.currentTime <= 0.1) {
decodeGenerationRef.current++
decodedSegmentsRef.current.clear()
// 同步清空帧缓冲,避免旧帧残留导致 getCurrentFrame 返回 null
// 关闭所有持久化解码器
for (const d of segmentDecodersRef.current.values()) {
try {
if (d.state !== "closed") d.close()
} catch {
/* noop */
}
}
segmentDecodersRef.current.clear()
segmentSampleCursorRef.current.clear()
frameQueueRef.current.clear()
playStartOffsetRef.current = 0
setState((s) => ({ ...s, currentTime: 0 }))
// 重新初始化解码
const metas = segmentMetaRef.current
const initialDecodeCount = Math.min(metas.length, 2)
for (let i = 0; i < initialDecodeCount; i++) {
await decodeSegmentBatch(i, 60)
}
}
setState((s) => ({ ...s, isPlaying: true }))
playStartRef.current = performance.now()
playStartOffsetRef.current = state.currentTime
if (state.currentTime < 0.1) {
playStartOffsetRef.current = 0
} else {
playStartOffsetRef.current = state.currentTime
}
lastProgressUpdateRef.current = 0
rafRef.current = requestAnimationFrame(renderFrame)
// 立即触发一次按需解码,不等渲染循环 200ms 节流
decodeAroundPosition(state.currentTime)
}, [state.hasSupport, state.currentTime, renderFrame, decodeAroundPosition])
}, [state.hasSupport, state.currentTime, totalDuration, renderFrame, decodeSegmentBatch])
const pause = useCallback(() => {
setState((s) => ({ ...s, isPlaying: false }))
@@ -790,33 +839,61 @@ export function useCanvasPlayer(
const seek = useCallback(
async (time: number) => {
const clampedTime = Math.max(0, Math.min(time, totalDuration))
decodeGenerationRef.current++
// 关闭所有解码器、清空队列、重置游标
for (const d of segmentDecodersRef.current.values()) {
try {
if (d.state !== "closed") d.close()
} catch {
/* noop */
}
}
segmentDecodersRef.current.clear()
segmentSampleCursorRef.current.clear()
frameQueueRef.current.clear()
setState((s) => ({ ...s, currentTime: clampedTime }))
playStartOffsetRef.current = clampedTime
playStartRef.current = performance.now()
// seek 时递增解码代数,作废正在进行的异步解码
decodeGenerationRef.current++
// 清空帧队列(clear 内部会 close 所有帧)+ 清空已解码标记
frameQueueRef.current.clear()
decodedSegmentsRef.current.clear()
await decodeAroundPosition(clampedTime)
// 找到 seek 目标片段,从该片段开始解码
const metas = segmentMetaRef.current
let targetIdx = 0,
acc = 0
for (let i = 0; i < metas.length; i++) {
const dur = metas[i].globalEndTime - metas[i].globalStartTime
if (clampedTime < acc + dur) {
targetIdx = i
break
}
acc += dur
}
await decodeSegmentBatch(targetIdx, 60)
await decodeSegmentBatch(Math.min(targetIdx + 1, metas.length - 1), 60)
},
[totalDuration, decodeAroundPosition],
[totalDuration, decodeSegmentBatch],
)
const destroy = useCallback(() => {
isDestroyedRef.current = true
cancelAnimationFrame(rafRef.current)
// 关闭所有持久化解码器
for (const d of segmentDecodersRef.current.values()) {
try {
if (d.state !== "closed") d.close()
} catch {
/* noop */
}
}
segmentDecodersRef.current.clear()
segmentSampleCursorRef.current.clear()
if (decoderRef.current && decoderRef.current.state !== "closed") {
decoderRef.current.close()
}
// 递增代数中止进行中的异步解码,清空帧队列(clear 内部 close 所有帧)
decodeGenerationRef.current++
frameQueueRef.current.clear()
segmentDataRef.current.clear()
segmentMetaRef.current = []
decodedSegmentsRef.current.clear()
}, [])
// ── 预加载下一个片段的数据 ──
@@ -833,6 +910,7 @@ export function useCanvasPlayer(
// ── 初始化:加载并解码所有片段 ──
useEffect(() => {
if (!enabled) return
if (!state.hasSupport || segments.length === 0) {
console.log("[useCanvasPlayer] Skip init:", {
hasSupport: state.hasSupport,
@@ -842,10 +920,24 @@ export function useCanvasPlayer(
}
let cancelled = false
console.log("[useCanvasPlayer] Init start, segments:", segments.length)
const init = async () => {
setState((s) => ({ ...s, isBuffering: true }))
// ✅ 关键修复:重置销毁标记,允许新的 init 周期正常工作
// destroy() 在 useEffect cleanup 中被调用,将 isDestroyedRef 设为 true
// 如果不重置,后续的 loadSegment / decodeSegment 会立即 return
isDestroyedRef.current = false
// ✅ Strict Mode 修复:init 不再递增 generation
// seek() 和 play() 仍保留 generation 递增用于中止异步解码
// 重置错误状态,避免上一轮的解码错误影响新的 init 周期
setState((s) => ({
...s,
isBuffering: true,
hasDecodeError: false,
errorMessage: "",
isReady: false,
}))
console.log("[useCanvasPlayer] Init start v2_DIAG, segments:", segments.length)
// 1. 加载所有片段数据
for (const seg of segments) {
@@ -887,32 +979,44 @@ export function useCanvasPlayer(
segmentMetaRef.current = metas
// 3. 按需解码:初始只解码3 个片段,后续通过 decodeAroundPosition 动态加载
// 避免一次性全量解码导致 frameQueue 环形缓冲区旧帧被丢弃引发黑屏
decodedSegmentsRef.current.clear()
const initGen = decodeGenerationRef.current
const initialDecodeCount = Math.min(metas.length, 3)
for (let i = 0; i < initialDecodeCount; i++) {
if (cancelled) break
// seek 或 destroy 已作废当前初始化
if (decodeGenerationRef.current !== initGen) break
const meta = metas[i]
const buffer = segmentDataRef.current.get(meta.assetId)
if (!buffer) continue
// 先标记为解码中,防止重复解码
decodedSegmentsRef.current.add(i)
// 3. 初始化解码:关闭旧解码器,2 个片段各解 60 帧
// 后续由 feedFrames 后台补充
for (const d of segmentDecodersRef.current.values()) {
try {
await decodeSegment(buffer, meta, MAX_INIT_FRAMES)
} catch (e) {
// 解码失败则移除标记,允许后续重试
decodedSegmentsRef.current.delete(i)
console.warn(`[useCanvasPlayer] 初始化解码片段 ${i} 失败:`, e)
if (d.state !== "closed") d.close()
} catch {
/* noop */
}
}
segmentDecodersRef.current.clear()
segmentSampleCursorRef.current.clear()
frameQueueRef.current.clear()
const initGen = decodeGenerationRef.current
const initialDecodeCount = Math.min(metas.length, 2)
console.log(
`[useCanvasPlayer] Starting init decode: ${initialDecodeCount} segments, metas: ${metas.length}`,
)
for (let i = 0; i < initialDecodeCount; i++) {
if (cancelled) break
if (decodeGenerationRef.current !== initGen) break
console.log(`[DIAG_v2] Init decode segment ${i}...`)
try {
await decodeSegmentBatch(i, 60)
console.log(`[DIAG_v2] Init decode segment ${i} done`)
} catch (e) {
console.warn(`[useCanvasPlayer] 初始化解码片段 ${i} 失败:`, e)
}
if (cancelled) break
}
console.log(`[useCanvasPlayer] Init decode finished, cancelled:`, cancelled)
if (!cancelled) {
console.log("[useCanvasPlayer] Init complete, isReady = true")
console.log("[useCanvasPlayer] Init complete, isReady = true, duration:", totalDuration)
setState((s) => ({ ...s, duration: totalDuration, isReady: true, isBuffering: false }))
} else {
console.warn("[useCanvasPlayer] Init was cancelled before completion")
}
}
@@ -0,0 +1,124 @@
/**
* 草稿自动保存工具 Hook
*
* 背景:后端 PUT /templates/{id}/editor 的 config 是「整体替换」语义,
* 直接发送 { config: { asset_ids } } 会把 title 等其他字段覆盖掉。
* 本 Hook 统一执行「GET 当前 config → 浅合并新字段 → PUT 回去」,
* 并用串行队列 + AbortController 保证:
* - 同一时刻只有一个保存请求在飞
* - 快速连续变化时只提交最后一次
* - 组件卸载时取消未完成请求
* - 保存失败时保留补丁,自动重试(指数退避,最多 5 次)
*
* 保存失败只 console.warn,不弹窗、不阻塞。
*/
import { useCallback, useEffect, useRef } from "react"
import { getEditPlan, updateEditPlan } from "@/api/template-editor"
type ConfigPatch = Record<string, unknown>
/** 最大自动重试次数 */
const MAX_RETRIES = 5
/** 初始重试延迟(ms),每次翻倍 */
const BASE_RETRY_DELAY = 1000
export function useDraftAutoSave(templateId?: string) {
const timerRef = useRef<ReturnType<typeof setTimeout>>()
const abortRef = useRef<AbortController | null>(null)
// 待合并的补丁队列(解决「保存进行中又来了新变化」)
const pendingPatchRef = useRef<ConfigPatch | null>(null)
const savingRef = useRef(false)
const templateIdRef = useRef(templateId)
templateIdRef.current = templateId
const flush = useCallback(async (retryCount = 0) => {
const tid = templateIdRef.current
if (!tid) return
// 已有保存在飞:把新补丁暂存,等当前请求结束后再合并一次
if (savingRef.current) return
// 快照当前补丁,但先不清空 —— 成功后才清除,失败时保留以便重试
const patchToSave = pendingPatchRef.current
if (!patchToSave) {
savingRef.current = false
return
}
savingRef.current = true
const controller = new AbortController()
abortRef.current = controller
try {
// 1. 读当前 config(拿最新,避免覆盖别人/别的步骤写入的字段)
const current = await getEditPlan(tid)
if (controller.signal.aborted) return
const merged = { ...(current.config || {}), ...patchToSave }
// 2. 写回完整合并后的 config
await updateEditPlan(tid, { config: merged }, controller.signal)
// 3. 保存成功才清除已保存的补丁
// (保存期间可能有新补丁进来,只清除我们已经保存的部分)
pendingPatchRef.current = null
} catch (err) {
const name = (err as { name?: string })?.name
if (name === "CanceledError" || name === "AbortError") {
// 组件卸载或新请求取消,不重试
return
}
console.warn("[useDraftAutoSave] 自动保存草稿失败:", err)
// 保存失败:把本次尝试保存的补丁合并回 pendingPatchRef
// (保存期间可能有新补丁,新补丁优先)
pendingPatchRef.current = {
...patchToSave,
...(pendingPatchRef.current || {}),
}
// 指数退避重试
if (retryCount < MAX_RETRIES && !controller.signal.aborted) {
const delay = BASE_RETRY_DELAY * Math.pow(2, retryCount)
timerRef.current = setTimeout(() => {
void flush(retryCount + 1)
}, delay)
}
// 超过最大重试次数后,补丁仍保留在 pendingPatchRef 中,
// 下次 scheduleSave 触发时会一起带上
} finally {
savingRef.current = false
// 保存期间又积累了新变化(且不是在重试路径中),再触发一次
if (pendingPatchRef.current && !controller.signal.aborted && retryCount === 0) {
timerRef.current = setTimeout(() => {
void flush()
}, 50)
}
}
}, [])
/**
* 调度一次自动保存(防抖)
* @param patch 要合并进 config 的局部字段
* @param delay 防抖毫秒数
*/
const scheduleSave = useCallback(
(patch: ConfigPatch, delay = 500) => {
const tid = templateIdRef.current
if (!tid) return
if (timerRef.current) clearTimeout(timerRef.current)
// 累计补丁(同一周期内多次变化合并成一次写入)
pendingPatchRef.current = { ...(pendingPatchRef.current || {}), ...patch }
timerRef.current = setTimeout(() => {
void flush()
}, delay)
},
[flush],
)
useEffect(() => {
return () => {
if (timerRef.current) clearTimeout(timerRef.current)
if (abortRef.current) abortRef.current.abort()
}
}, [])
return { scheduleSave }
}
export default useDraftAutoSave
@@ -4,8 +4,8 @@
*/
import { useState } from "react"
import { useSearchParams } from "react-router-dom"
import type { GeneratedVideo } from "@/api/template-editor"
import type { EditingTemplate } from "@/api/editing-planner"
import type { EditPlanClip } from "@/api/template-editor"
import type { CoverConfig } from "../../types/cover"
import type { PresetVoiceItem } from "@/api/voices"
import { DEFAULT_COVER_SETTINGS } from "../../constants"
@@ -14,6 +14,7 @@ import { useTemplateSelection } from "./useTemplateSelection"
import { useTitleCoverSync } from "./useTitleCoverSync"
import { useVoiceState } from "./useVoiceState"
import { usePlanConfigLoader } from "./usePlanConfigLoader"
import { usePersistedState } from "../usePersistedState"
const DEFAULT_TITLE_SETTINGS: TitleSettings = {
aiAutoSelect: false,
@@ -46,6 +47,10 @@ export interface GenerateFormState {
smartSelectedIds: string[]
setSmartSelectedIds: (ids: string[]) => void
/* 服务端片段(/clips/from-assets 创建后获取) */
serverClips: EditPlanClip[]
setServerClips: (clips: EditPlanClip[]) => void
/* 标题 */
titleSettings: TitleSettings
setTitleSettings: (settings: TitleSettings | ((prev: TitleSettings) => TitleSettings)) => void
@@ -67,10 +72,6 @@ export interface GenerateFormState {
cloneModalOpen: boolean
setCloneModalOpen: (open: boolean) => void
/* 生成数量 */
generateCount: number
setGenerateCount: (n: number) => void
/* 高级设置 */
videoRatio: string
duration: number
@@ -82,11 +83,21 @@ export interface GenerateFormState {
editPlanId: string | null
planConfigStr: string | null
/* 预览弹窗 */
previewVideo: GeneratedVideo | null
setPreviewVideo: (v: GeneratedVideo | null) => void
previewModalOpen: boolean
setPreviewModalOpen: (open: boolean) => void
/**
* 传给 Worker 的 source_edit_plan_id。
* 仅使用 URL 中的 edit_plan_id(从剪辑模板编辑器跳转时携带)。
* URL 没有时传 null,后端正式生成 API 会通过 template_id+user_id 兜底查找正确的 plan。
* 注意:selectedTemplate 是模板 ID,不是 edit_plan_id,不能作为此值传递。
*/
sourceEditPlanId: string | null
/** 预览任务 ID(由 useStep6Cover 创建后写入,供 useGenerateVideo 复用) */
previewTaskId: string | null
setPreviewTaskId: (id: string | null) => void
/** 从预览响应中提取的 source_edit_plan_id(供 fallback 路径使用) */
storedSourceEditPlanId: string | null
setStoredSourceEditPlanId: (planId: string | null) => void
}
export const useGenerateFormState = (): GenerateFormState => {
@@ -100,11 +111,19 @@ export const useGenerateFormState = (): GenerateFormState => {
/* ── 模板选择 ── */
const { selectedTemplate, setSelectedTemplate, userTemplates } = useTemplateSelection()
/* ── source_edit_plan_id:仅取 URL 参数,无则 null 让后端兜底 ── */
// selectedTemplate 是模板 ID 而非 edit_plan_id,不能混淆;
// 后端正式生成 API 会在 source_edit_plan_id 为空时通过 template_id+user_id 自动关联。
const sourceEditPlanId = editPlanId || null
/* ── 素材 ── */
const [selectedMaterials, setSelectedMaterials] = useState<string[]>([])
const [materialMode, setMaterialMode] = useState<"manual" | "auto">("manual")
const [smartSelectedIds, setSmartSelectedIds] = useState<string[]>([])
/* ── 服务端片段(供预览播放器使用)── */
const [serverClips, setServerClips] = useState<EditPlanClip[]>([])
/* ── 标题设置 ── */
const [titleSettings, setTitleSettings] = useState<TitleSettings>(DEFAULT_TITLE_SETTINGS)
@@ -133,9 +152,6 @@ export const useGenerateFormState = (): GenerateFormState => {
/* ── 克隆声音弹窗 ── */
const [cloneModalOpen, setCloneModalOpen] = useState(false)
/* ── 生成数量 ── */
const [generateCount, setGenerateCount] = useState(1)
/* ── 高级设置(隐藏但保留) ── */
const [videoRatio] = useState("9:16")
const [duration] = useState(30)
@@ -143,9 +159,29 @@ export const useGenerateFormState = (): GenerateFormState => {
const [autoSubtitles] = useState(true)
const [bgm] = useState(true)
/* ── 预览弹窗 ── */
const [previewVideo, setPreviewVideo] = useState<GeneratedVideo | null>(null)
const [previewModalOpen, setPreviewModalOpen] = useState(false)
/* ── 预览任务 IDuseStep6Cover 创建预览时写入,useGenerateVideo 复用) ── */
// 持久化到 localStoragekey 按 editPlanId/templateId 区分,刷新页面后可恢复
const previewStorageKey = editPlanId
? `preview_task_id_${editPlanId}`
: selectedTemplate
? `preview_task_id_tpl_${selectedTemplate}`
: null
const [previewTaskId, setPreviewTaskId] = usePersistedState<string | null>(
previewStorageKey,
null,
)
/* ── 从预览响应中提取的 source_edit_plan_id(供 fallback 路径使用) ── */
// 持久化到 localStorage,刷新页面后 fallback 路径仍能正确传递 source_edit_plan_id
const planIdStorageKey = editPlanId
? `source_edit_plan_id_${editPlanId}`
: selectedTemplate
? `source_edit_plan_id_tpl_${selectedTemplate}`
: null
const [storedSourceEditPlanId, setStoredSourceEditPlanId] = usePersistedState<string | null>(
planIdStorageKey,
null,
)
/* ── 从 URL / 编辑计划加载配置 ── */
usePlanConfigLoader({
@@ -168,6 +204,8 @@ export const useGenerateFormState = (): GenerateFormState => {
setMaterialMode,
smartSelectedIds,
setSmartSelectedIds,
serverClips,
setServerClips,
titleSettings,
setTitleSettings,
coverSettings,
@@ -181,18 +219,17 @@ export const useGenerateFormState = (): GenerateFormState => {
presetVoices,
cloneModalOpen,
setCloneModalOpen,
generateCount,
setGenerateCount,
videoRatio,
duration,
style,
autoSubtitles,
bgm,
editPlanId,
sourceEditPlanId,
planConfigStr,
previewVideo,
setPreviewVideo,
previewModalOpen,
setPreviewModalOpen,
previewTaskId,
setPreviewTaskId,
storedSourceEditPlanId,
setStoredSourceEditPlanId,
}
}
@@ -4,16 +4,25 @@
*/
import { useState, useCallback } from "react"
import { message } from "antd"
import type { GeneratedVideo } from "@/api/template-editor"
import { type GeneratedVideo, getEditPlanClips } from "@/api/template-editor"
import { createGenerationTask } from "@/api/tasks/tasks"
import type { UseGenerateVideoProps } from "./generate-video/types"
import { getGenerationPhase } from "./generate-video/phase"
import { useGenerationPolling } from "./generate-video/useGenerationPolling"
import { validateGenerateInputs } from "./generate-video/buildPayload"
import { calculateResolution } from "../utils/calculateResolution"
import { extractBackendError, translateError } from "./generate-video/errorUtils"
/**
* 片段创建轮询:最多等 30 秒。
* useStep2Materials 在用户选素材时(debounce 800ms)已调用 from-assets
* 这里只做轻量校验,确认片段已落库就放行,不死等 ready。
*/
const CLIPS_CREATED_MAX_WAIT_MS = 30_000
const CLIPS_CREATED_POLL_INTERVAL_MS = 1_500
export function useGenerateVideo(props: UseGenerateVideoProps) {
const { selectedTemplate } = props
const { selectedTemplate, onGenerationSuccess } = props
/* ── 生成状态 ── */
const [generating, setGenerating] = useState(false)
@@ -23,23 +32,48 @@ export function useGenerateVideo(props: UseGenerateVideoProps) {
const [generatedVideos, setGeneratedVideos] = useState<GeneratedVideo[]>([])
const handleProgress = useCallback((p: number) => setProgress(p), [])
const handleComplete = useCallback((videos: unknown[]) => {
setGenerating(false)
setGenerated(true)
setGeneratedVideos(videos as GeneratedVideo[])
}, [])
const handleComplete = useCallback(
(videos: unknown[]) => {
setGenerating(false)
setGenerated(true)
setGeneratedVideos(videos as GeneratedVideo[])
onGenerationSuccess?.()
},
[onGenerationSuccess],
)
const handleFailed = useCallback((errorMsg: string) => {
setGenerating(false)
setGenerateError(errorMsg)
}, [])
const { startPolling, clearTimer } = useGenerationPolling({
templateId: selectedTemplate,
onProgress: handleProgress,
onComplete: handleComplete,
onFailed: handleFailed,
})
/**
* 轮询确认片段已被创建。
* useStep2Materials 在用户选素材时已调用 from-assets 创建片段,
* 这里只要该 plan 下存在任意 clips(无论 ready/pending),就立即放行 generate。
* 片段是否 ready 由后端生成流程自行等待/兜底,前端不死等 ready,避免:
* 1. MediaKit 失败时前端卡死无法生成
* 2. E2E/弱网环境下 generate 请求迟迟不发出
* 30s 仍查不到片段也放行,由后端返回明确错误。
*/
const waitForClipsCreated = useCallback(async (templateId: string): Promise<void> => {
const start = Date.now()
while (Date.now() - start < CLIPS_CREATED_MAX_WAIT_MS) {
try {
const clipList = await getEditPlanClips(templateId, { limit: 500 })
if (clipList.items.length > 0) return
} catch {
// 单次查询失败不终止,继续轮询
}
await new Promise((resolve) => setTimeout(resolve, CLIPS_CREATED_POLL_INTERVAL_MS))
}
}, [])
/* ── 生成视频 ── */
const generate = useCallback(async () => {
const errorMsg = validateGenerateInputs(props)
@@ -55,51 +89,48 @@ export function useGenerateVideo(props: UseGenerateVideoProps) {
clearTimer()
try {
// 解析分辨率
const ratio = props.videoRatio || "9:16"
let outputWidth: number
let outputHeight: number
if (ratio.includes(":")) {
const [rw, rh] = ratio.split(":").map(Number)
if (rw > 0 && rh > 0) {
const [longSide, shortSide] = rw < rh ? [rh, rw] : [rw, rh]
const baseLong = 1920
const baseShort = Math.round((baseLong * shortSide) / longSide)
const evenShort = baseShort - (baseShort % 2)
if (rw < rh) {
outputWidth = evenShort
outputHeight = baseLong
} else {
outputWidth = baseLong
outputHeight = evenShort
}
} else {
outputWidth = 1080
outputHeight = 1920
}
} else if (ratio.includes("x")) {
const [wStr, hStr] = ratio.split("x")
outputWidth = parseInt(wStr, 10) || 1080
outputHeight = parseInt(hStr, 10) || 1920
} else {
outputWidth = 1080
outputHeight = 1920
}
const { width: outputWidth, height: outputHeight } = calculateResolution(
props.videoRatio || "9:16",
)
const assetIds =
props.materialMode === "auto" ? props.smartSelectedIds : props.selectedMaterials
// 直接创建正式生成任务
await createGenerationTask({
// from-assets 已由 useStep2Materials 在用户选素材时(debounce 800ms)调用。
// 这里轻量确认片段已落库,再发 generate;最多等 30s,超时也放行。
// 片段 ready 状态由后端生成流程兜底,前端不死等。
if (assetIds.length > 0 && selectedTemplate) {
const hide = message.loading("正在准备素材片段...", 0)
try {
await waitForClipsCreated(selectedTemplate)
} finally {
hide()
}
}
const coverUrl = props.coverSettings?.thumbnail_url || props.coverSettings?.upload_url || ""
const voiceLibraryId =
props.voiceMode === "clone"
? props.selectedClonedVoice || props.selectedVoice || ""
: props.selectedVoice || ""
const taskResp = await createGenerationTask({
template_id: selectedTemplate,
asset_ids: assetIds,
output_width: outputWidth,
output_height: outputHeight,
cover_url: props.coverSettings?.upload_url || "",
cover_url: coverUrl,
custom_title: props.titleSettings?.title || "",
duration: props.duration || undefined,
video_ratio: props.videoRatio,
voice_library_id: voiceLibraryId,
...(props.selectedVoice && !voiceLibraryId ? { voice_ids: [props.selectedVoice] } : {}),
bgm_config: {
enabled: props.bgm !== false,
...(props.bgmConfig?.music_id ? { preset_id: props.bgmConfig.music_id } : {}),
},
...(props.sourceEditPlanId ? { source_edit_plan_id: props.sourceEditPlanId } : {}),
...(props.titleSettings?.title
? {
title_config: {
@@ -115,8 +146,12 @@ export function useGenerateVideo(props: UseGenerateVideoProps) {
}
: {}),
})
const taskId = taskResp.items?.[0]?.id
startPolling()
if (!taskId) {
throw new Error("创建任务成功但未返回任务 ID,请稍后在任务列表查看")
}
startPolling(taskId)
} catch (err: unknown) {
console.error("[handleGenerate] 生成失败:", err)
setGenerating(false)
@@ -126,20 +161,17 @@ export function useGenerateVideo(props: UseGenerateVideoProps) {
setGenerateError(finalMsg)
message.error(finalMsg)
}
}, [props, clearTimer, startPolling, selectedTemplate])
}, [props, clearTimer, startPolling, selectedTemplate, waitForClipsCreated])
/* 重新生成(失败后重试) */
const retry = useCallback(() => {
setGenerateError(null)
generate()
}, [generate])
/* 清除错误 */
const dismissError = useCallback(() => {
setGenerateError(null)
}, [])
/* ── 下载视频 ── */
const download = useCallback(async () => {
if (!generatedVideos.length) return
const video = generatedVideos[0]
@@ -160,7 +192,6 @@ export function useGenerateVideo(props: UseGenerateVideoProps) {
}
}, [generatedVideos])
/* ── 分享视频 ── */
const share = useCallback(async () => {
if (!generatedVideos.length) return
const video = generatedVideos[0]
@@ -174,19 +205,16 @@ export function useGenerateVideo(props: UseGenerateVideoProps) {
}, [generatedVideos])
return {
// 状态
generating,
progress,
generated,
generateError,
generatedVideos,
// 操作
generate,
retry,
dismissError,
download,
share,
// 工具
getGenerationPhase,
}
}
@@ -0,0 +1,63 @@
import { useState, useEffect, useCallback, useRef } from "react"
/**
* 持久化到 localStorage 的 state hook
*
* 用于在页面刷新后恢复 previewTaskId / sourceEditPlanId 等关键状态。
* 当 localStorage 不可用(SSR、隐私模式等)时自动降级为普通 useState。
* 当 key 变化时(例如切换模板),自动从新 key 重新读取并更新 state。
*/
export function usePersistedState<T>(
key: string | null | undefined,
defaultValue: T,
): [T, (value: T | ((prev: T) => T)) => void] {
const storageKey = key ? `xiaoxia_${key}` : null
// defaultValue 用 ref 持有,避免作为 useEffect 依赖导致频繁重跑
const defaultValueRef = useRef(defaultValue)
defaultValueRef.current = defaultValue
const readFromStorage = useCallback((k: string | null): T => {
if (!k) return defaultValueRef.current
try {
const stored = localStorage.getItem(k)
if (stored !== null) {
return JSON.parse(stored) as T
}
} catch (e) {
// localStorage 不可用或 JSON 解析失败,使用默认值
console.warn("[usePersistedState] 读取 localStorage 失败:", e)
}
return defaultValueRef.current
}, [])
const [state, setState] = useState<T>(() => readFromStorage(storageKey))
// key 变化时(如切换模板/草稿),从新 key 重新读取,避免状态与存储不同步
useEffect(() => {
setState(readFromStorage(storageKey))
}, [storageKey, readFromStorage])
const setPersistedState = useCallback(
(value: T | ((prev: T) => T)) => {
setState((prev) => {
const nextValue = typeof value === "function" ? (value as (prev: T) => T)(prev) : value
if (storageKey) {
try {
if (nextValue === null || nextValue === undefined || nextValue === "") {
localStorage.removeItem(storageKey)
} else {
localStorage.setItem(storageKey, JSON.stringify(nextValue))
}
} catch (e) {
// localStorage 写入失败(存储空间满/隐私模式),静默忽略
console.warn("[usePersistedState] 写入 localStorage 失败:", e)
}
}
return nextValue
})
},
[storageKey],
)
return [state, setPersistedState]
}
@@ -1,55 +1,37 @@
/**
* 素材片段调度器 Hook(多 video 元素方案 v2
* 每个片段对应一个独立 <video> 元素,全部预加载,通过 display 切换实现无缝播放
* 替代单 video + 切 src 方案,消除片段切换延迟
* 素材片段调度器 Hook(多 video 元素方案 v3
*
* v3 修复:
* - 所有动态状态存入 ref,tick 为稳定函数,彻底消除 RAF 闭包陷阱
* - 片段切换时先启动下一个 video 再切可见性,消除冻屏间隔
* - 进度更新 200ms 节流
*/
import { useState, useRef, useCallback, useEffect, useMemo } from "react"
/** 单个播放片段 */
export interface PlaybackSegment {
/** 素材 ID */
assetId: string
/** 素材视频 URL */
videoUrl: string
/** 片段在素材中的入点(秒) */
startTime: number
/** 片段在素材中的出点(秒) */
endTime: number
/** 片段在时间线中的顺序 */
order: number
}
/** 调度器返回 */
export interface SegmentSchedulerState {
/** 是否正在播放 */
isPlaying: boolean
/** 当前播放的全局时间(秒) */
currentTime: number
/** 总时长(秒) */
totalDuration: number
/** 当前片段索引 */
currentSegmentIndex: number
/** 当前片段的本地播放时间 */
segmentLocalTime: number
/** 是否已播完 */
isEnded: boolean
/** 是否可以播放(至少有 1 个片段) */
canPlay: boolean
/** 播放 */
play: () => void
/** 暂停 */
pause: () => void
/** 切换播放/暂停 */
togglePlayPause: () => void
/** 跳转到全局时间 */
seekTo: (time: number) => void
/** 每个片段对应的 video 元素 ref 数组 */
videoRefs: React.MutableRefObject<(HTMLVideoElement | null)[]>
}
/**
* 根据全局时间定位对应的片段和本地时间
*/
function findSegmentAtTime(
segments: PlaybackSegment[],
globalTime: number,
@@ -66,9 +48,6 @@ function findSegmentAtTime(
return { index: segments.length - 1, localTime: segments[segments.length - 1].endTime }
}
/**
* 计算每个片段的全局起始时间
*/
function buildTimeline(segments: PlaybackSegment[]): number[] {
const starts: number[] = []
let acc = 0
@@ -79,224 +58,242 @@ function buildTimeline(segments: PlaybackSegment[]): number[] {
return starts
}
/**
* useSegmentScheduler — 多 video 元素版素材片段调度器
*
* 核心改变:
* - 每个片段对应一个独立 <video> 元素(由组件渲染,ref 传入)
* - 所有 video 在挂载时即设置 src + preload="auto",浏览器自动预加载
* - 切换片段仅改 currentSegmentIndex + display,无需重新 load
* - 实现无缝切换,无加载延迟
*/
export function useSegmentScheduler(segments: PlaybackSegment[]): SegmentSchedulerState {
/** 每个片段对应的 video 元素 ref(由组件 JSX 渲染并绑定) */
const videoRefs = useRef<(HTMLVideoElement | null)[]>([])
const [isPlaying, setIsPlaying] = useState(false)
const [currentTime, setCurrentTime] = useState(0)
const [currentSegmentIndex, setCurrentSegmentIndex] = useState(0)
const [isEnded, setIsEnded] = useState(false)
const rafRef = useRef<number>(0)
const rafRef = useRef(0)
const isSeekingRef = useRef(false)
const lastTimeUpdateRef = useRef(0)
// 计算时间线
const timelineStarts = useMemo(() => buildTimeline(segments), [segments])
const totalDuration = useMemo(
// 所有动态值存入 ref,tick 始终读取最新值,不依赖闭包
const segIdxRef = useRef(0)
const segmentsRef = useRef(segments)
const timelineStartsData = useMemo(() => buildTimeline(segments), [segments])
const totalDurationData = useMemo(
() => segments.reduce((sum, seg) => sum + (seg.endTime - seg.startTime), 0),
[segments],
)
const timelineStartsRef = useRef(timelineStartsData)
const totalDurationRef = useRef(totalDurationData)
const isPlayingRef = useRef(false)
segmentsRef.current = segments
timelineStartsRef.current = timelineStartsData
totalDurationRef.current = totalDurationData
const canPlay = segments.length > 0
// 当前片段信息
const currentSegment = segments[currentSegmentIndex] || null
const segmentLocalTime = currentSegment
? currentTime - (timelineStarts[currentSegmentIndex] || 0) + currentSegment.startTime
: 0
useEffect(() => {
segIdxRef.current = currentSegmentIndex
}, [currentSegmentIndex])
useEffect(() => {
isPlayingRef.current = isPlaying
}, [isPlaying])
const waitForReady = useCallback((video: HTMLVideoElement, timeout = 3000): Promise<void> => {
if (video.readyState >= 3) return Promise.resolve()
return new Promise((resolve) => {
const onCanPlay = () => {
video.removeEventListener("canplay", onCanPlay)
clearTimeout(timer)
resolve()
}
const timer = setTimeout(() => {
video.removeEventListener("canplay", onCanPlay)
resolve()
}, timeout)
video.addEventListener("canplay", onCanPlay)
})
}, [])
/**
* 切换到指定片段
* 不改变 src(video 已在 JSX 中设置),仅 seek + 等待可播
*/
const switchToSegment = useCallback(
(index: number, seekToLocalTime?: number): Promise<void> => {
return new Promise((resolve) => {
// 暂停当前视频
const prevVideo = videoRefs.current[currentSegmentIndex]
if (prevVideo) prevVideo.pause()
async (index: number, seekToLocalTime?: number) => {
const segs = segmentsRef.current
const video = videoRefs.current[index]
if (!video || index >= segs.length) return
const video = videoRefs.current[index]
if (!video || index >= segments.length) {
resolve()
return
}
const seg = segs[index]
const localTime = seekToLocalTime ?? seg.startTime
const oldIdx = segIdxRef.current
const oldVideo = videoRefs.current[oldIdx]
const seg = segments[index]
const localTime = seekToLocalTime ?? seg.startTime
if (oldVideo && oldVideo !== video) oldVideo.pause()
// 设置播放位置
if (!video.src && seg.videoUrl) {
video.src = seg.videoUrl
video.load()
}
if (Math.abs(video.currentTime - localTime) > 0.05) {
video.currentTime = localTime
}
// 如果已有足够帧数据,直接 resolve
if (video.readyState >= 2) {
setCurrentSegmentIndex(index)
resolve()
return
}
segIdxRef.current = index
setCurrentSegmentIndex(index)
// 等待 canplay 事件
const onCanPlay = () => {
video.removeEventListener("canplay", onCanPlay)
clearTimeout(timeoutId)
setCurrentSegmentIndex(index)
resolve()
}
// 10 秒超时保护
const timeoutId = setTimeout(() => {
video.removeEventListener("canplay", onCanPlay)
console.warn(
`[useSegmentScheduler] 片段 ${index} 预加载超时 (10s), readyState=${video.readyState}`,
)
setCurrentSegmentIndex(index)
resolve()
}, 10000)
video.addEventListener("canplay", onCanPlay)
})
await waitForReady(video)
},
[segments, currentSegmentIndex],
[waitForReady],
)
/** 播放循环 — 检测片段边界并切换 */
// 稳定的 tick 函数,空依赖,所有值从 ref 读取
const tick = useCallback(() => {
const video = videoRefs.current[currentSegmentIndex]
const segs = segmentsRef.current
const idx = segIdxRef.current
const video = videoRefs.current[idx]
if (!video || isSeekingRef.current) {
rafRef.current = requestAnimationFrame(tick)
return
}
const seg = segments[currentSegmentIndex]
const seg = segs[idx]
if (!seg) return
// 检查是否到达出点(容差 0.15s
if (video.currentTime >= seg.endTime - 0.15) {
video.pause()
const nextIndex = currentSegmentIndex + 1
if (nextIndex < segments.length) {
switchToSegment(nextIndex).then(() => {
setIsPlaying(true)
rafRef.current = requestAnimationFrame(tick)
const nextVideo = videoRefs.current[nextIndex]
if (nextVideo) {
const canPlay = () => {
nextVideo
.play()
.catch((e) =>
console.warn("[useSegmentScheduler] auto-play next segment failed:", e),
)
}
if (nextVideo.readyState >= 3) {
canPlay()
} else {
const timeout = setTimeout(canPlay, 300)
nextVideo.addEventListener(
"canplay",
() => {
clearTimeout(timeout)
canPlay()
},
{ once: true },
)
}
// 预加载下一个片段
const nextIndex = idx + 1
if (nextIndex < segs.length) {
const nextVideo = videoRefs.current[nextIndex]
if (nextVideo) {
const timeToEnd = seg.endTime - video.currentTime
if (timeToEnd <= 2 && nextVideo.readyState < 3) {
const nextSeg = segs[nextIndex]
if (Math.abs(nextVideo.currentTime - nextSeg.startTime) > 0.5) {
nextVideo.currentTime = nextSeg.startTime
}
})
}
}
}
// 检测片段边界
if (video.currentTime >= seg.endTime - 0.1) {
if (nextIndex < segs.length) {
const nextVideo = videoRefs.current[nextIndex]
const nextSeg = segs[nextIndex]
const accumulatedTime =
(timelineStarts[currentSegmentIndex] || 0) + (seg.endTime - seg.startTime)
(timelineStartsRef.current[idx] || 0) + (seg.endTime - seg.startTime)
if (nextVideo) {
if (Math.abs(nextVideo.currentTime - nextSeg.startTime) > 0.1) {
nextVideo.currentTime = nextSeg.startTime
}
// 先启动下一个视频(muted,可安全同时播放)
nextVideo
.play()
.catch((e) => console.warn("[useSegmentScheduler] next segment play failed:", e))
}
// 立即切换可见性
segIdxRef.current = nextIndex
setCurrentSegmentIndex(nextIndex)
setCurrentTime(accumulatedTime)
lastTimeUpdateRef.current = 0
setIsPlaying(true)
// 下一帧暂停旧视频(让新视频先渲染,避免冻屏)
const oldVideo = video
requestAnimationFrame(() => {
oldVideo.pause()
})
rafRef.current = requestAnimationFrame(tick)
return
} else {
video.pause()
setIsPlaying(false)
setIsEnded(true)
setCurrentTime(totalDuration)
setCurrentTime(totalDurationRef.current)
return
}
} else {
const globalTime =
(timelineStarts[currentSegmentIndex] || 0) + (video.currentTime - seg.startTime)
setCurrentTime(Math.max(0, Math.min(globalTime, totalDuration)))
}
const globalTime = (timelineStartsRef.current[idx] || 0) + (video.currentTime - seg.startTime)
const now = performance.now()
if (now - lastTimeUpdateRef.current >= 200) {
lastTimeUpdateRef.current = now
setCurrentTime(Math.max(0, Math.min(globalTime, totalDurationRef.current)))
}
rafRef.current = requestAnimationFrame(tick)
}, [segments, currentSegmentIndex, timelineStarts, totalDuration, switchToSegment])
}, [])
/** 播放 */
const play = useCallback(async () => {
if (!canPlay) return
setIsEnded(false)
// 确保第一段可播放
const firstVideo = videoRefs.current[0]
if (firstVideo && currentSegmentIndex === 0 && firstVideo.readyState < 2) {
await switchToSegment(0)
}
const video = videoRefs.current[currentSegmentIndex]
const idx = segIdxRef.current
const video = videoRefs.current[idx]
if (!video) return
try {
const playPromise = video.play()
if (playPromise !== undefined) {
await playPromise
if (idx === 0 && video.readyState < 2) {
if (!video.src && segmentsRef.current[0]?.videoUrl) {
video.src = segmentsRef.current[0].videoUrl
video.load()
}
await waitForReady(video)
}
try {
await video.play()
setIsPlaying(true)
cancelAnimationFrame(rafRef.current)
rafRef.current = requestAnimationFrame(tick)
} catch (err) {
console.warn("[useSegmentScheduler] 播放失败:", err)
}
}, [canPlay, switchToSegment, tick, currentSegmentIndex])
}, [canPlay, waitForReady, tick])
/** 暂停 */
const pause = useCallback(() => {
const video = videoRefs.current[currentSegmentIndex]
const video = videoRefs.current[segIdxRef.current]
if (video) video.pause()
setIsPlaying(false)
cancelAnimationFrame(rafRef.current)
}, [currentSegmentIndex])
}, [])
/** 切换播放/暂停 */
const togglePlayPause = useCallback(() => {
if (isPlaying) {
if (isPlayingRef.current) {
pause()
} else {
if (isEnded) {
// 播放结束后再次播放,从头开始
setIsEnded(false)
switchToSegment(0, segments[0]?.startTime).then(() => {
const video = videoRefs.current[0]
if (video) {
video.play().catch((e) => console.warn("[useSegmentScheduler] restart play failed:", e))
setIsPlaying(true)
setCurrentTime(0)
rafRef.current = requestAnimationFrame(tick)
}
})
lastTimeUpdateRef.current = 0
const firstVideo = videoRefs.current[0]
if (firstVideo) {
videoRefs.current.forEach((v, i) => {
if (v && i !== 0) v.pause()
})
firstVideo.currentTime = segmentsRef.current[0]?.startTime || 0
segIdxRef.current = 0
setCurrentSegmentIndex(0)
setCurrentTime(0)
firstVideo
.play()
.then(() => {
setIsPlaying(true)
cancelAnimationFrame(rafRef.current)
rafRef.current = requestAnimationFrame(tick)
})
.catch((e) => console.warn("[useSegmentScheduler] restart failed:", e))
}
} else {
play()
}
}
}, [isPlaying, isEnded, pause, play, switchToSegment, segments, tick])
}, [isEnded, pause, play, tick])
/** 跳转到指定全局时间 */
const seekTo = useCallback(
async (time: number) => {
if (!canPlay) return
const clampedTime = Math.max(0, Math.min(time, totalDuration))
const { index, localTime } = findSegmentAtTime(segments, clampedTime)
const clampedTime = Math.max(0, Math.min(time, totalDurationRef.current))
const { index, localTime } = findSegmentAtTime(segmentsRef.current, clampedTime)
isSeekingRef.current = true
cancelAnimationFrame(rafRef.current)
if (index !== currentSegmentIndex) {
if (index !== segIdxRef.current) {
await switchToSegment(index, localTime)
} else {
const video = videoRefs.current[index]
@@ -305,48 +302,54 @@ export function useSegmentScheduler(segments: PlaybackSegment[]): SegmentSchedul
setCurrentTime(clampedTime)
setIsEnded(false)
lastTimeUpdateRef.current = 0
if (isPlayingRef.current) {
const video = videoRefs.current[index]
if (video) {
video.play().catch(() => {})
}
rafRef.current = requestAnimationFrame(tick)
}
setTimeout(() => {
isSeekingRef.current = false
}, 200)
},
[canPlay, totalDuration, segments, currentSegmentIndex, switchToSegment],
[canPlay, switchToSegment, tick],
)
// 确保 videoRefs 数组长度与 segments 一致 + 强制预加载
useEffect(() => {
videoRefs.current = videoRefs.current.slice(0, segments.length)
while (videoRefs.current.length < segments.length) {
videoRefs.current.push(null)
}
// 强制预加载:所有 video 元素挂载后,调用 load() 确保浏览器真正开始加载数据
videoRefs.current.forEach((video) => {
if (video) {
video.load()
}
})
}, [segments])
// 组件卸载时清理
useEffect(() => {
return () => {
cancelAnimationFrame(rafRef.current)
}
}, [])
// 片段列表变化时重置
useEffect(() => {
cancelAnimationFrame(rafRef.current)
segIdxRef.current = 0
setIsPlaying(false)
setCurrentTime(0)
setCurrentSegmentIndex(0)
setIsEnded(false)
}, [segments])
const currentSegment = segments[currentSegmentIndex] || null
const segmentLocalTime = currentSegment
? currentTime - (timelineStartsRef.current[currentSegmentIndex] || 0) + currentSegment.startTime
: 0
return {
isPlaying,
currentTime,
totalDuration,
totalDuration: totalDurationData,
currentSegmentIndex,
segmentLocalTime,
isEnded,
@@ -0,0 +1,294 @@
/**
* 服务器渲染预览 Hook
*
* 核心职责:
* 1. 调用 POST /generation/preview 创建服务器预览渲染任务
* 2. 轮询 GET /generation/preview/{task_id} 直到完成
* 3. 返回服务器渲染的真实视频 URL(供 <video> 标签播放)
* 4. 检测配置变更,标记预览失效(stale)或自动重新渲染
* 5. 网络错误自动重试 2 次
*
* 状态机:
* idle → loading → ready → stale (config changed)
* ↘ failed → idle (retry)
*/
import { useState, useCallback, useRef, useEffect } from "react"
import { createPreview, getPreviewStatus } from "@/api/generation/preview"
import type { CreatePreviewRequest } from "@/api/generation/types"
export type ServerPreviewStatus = "idle" | "loading" | "ready" | "stale" | "failed"
interface UseServerPreviewOptions {
/** 是否启用预览(Step4+ 且有素材和模板时) */
enabled: boolean
/** 构建预览请求参数(每次 render 调用,获取最新配置) */
buildRequest: () => CreatePreviewRequest
/** 预览任务创建成功回调 */
onPreviewTaskCreated?: (taskId: string, sourceEditPlanId?: string) => void
}
interface UseServerPreviewReturn {
status: ServerPreviewStatus
videoUrl: string | null
error: string | null
/** 进度 0-100 */
progress: number
/** 手动触发预览创建("重新预览"按钮或标题变更后手动刷新) */
triggerPreview: () => void
/** 当前预览任务 ID */
taskId: string | null
}
const POLL_INTERVAL = 2000
const POLL_TIMEOUT = 120_000
const MAX_NETWORK_RETRIES = 2
/**
* 对配置参数做指纹,用于检测配置是否变化
*/
function buildFingerprint(req: CreatePreviewRequest): string {
return JSON.stringify({
t: req.template_id,
a: [...req.asset_ids].sort(),
d: req.duration,
r: req.video_ratio,
v: req.voice_library_id,
b: req.bgm_config,
title: req.title_config,
})
}
export function useServerPreview({
enabled,
buildRequest,
onPreviewTaskCreated,
}: UseServerPreviewOptions): UseServerPreviewReturn {
const [status, setStatus] = useState<ServerPreviewStatus>("idle")
const [videoUrl, setVideoUrl] = useState<string | null>(null)
const [error, setError] = useState<string | null>(null)
const [progress, setProgress] = useState(0)
const [taskId, setTaskId] = useState<string | null>(null)
const pollTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)
const timeoutTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)
const requestSeqRef = useRef(0)
const renderedFingerprintRef = useRef<string>("")
const mountedRef = useRef(true)
const networkRetriesRef = useRef(0)
// 始终持有最新的 buildRequest 和回调
const buildRequestRef = useRef(buildRequest)
buildRequestRef.current = buildRequest
const onCreatedRef = useRef(onPreviewTaskCreated)
onCreatedRef.current = onPreviewTaskCreated
/* ── 清理 ── */
const clearTimers = useCallback(() => {
if (pollTimerRef.current) {
clearTimeout(pollTimerRef.current)
pollTimerRef.current = null
}
if (timeoutTimerRef.current) {
clearTimeout(timeoutTimerRef.current)
timeoutTimerRef.current = null
}
}, [])
useEffect(() => {
mountedRef.current = true
return () => {
mountedRef.current = false
clearTimers()
}
}, [clearTimers])
/* ── 创建预览 + 轮询 ── */
const createAndPoll = useCallback(
async (request: CreatePreviewRequest, seq: number) => {
setStatus("loading")
setProgress(0)
setError(null)
networkRetriesRef.current = 0
try {
const resp = await createPreview(request)
if (seq !== requestSeqRef.current || !mountedRef.current) return
setTaskId(resp.task_id)
onCreatedRef.current?.(resp.task_id, resp.source_edit_plan_id)
let completed = false
// 超时保护
timeoutTimerRef.current = setTimeout(() => {
if (completed || seq !== requestSeqRef.current || !mountedRef.current) return
completed = true
clearTimers()
setStatus("failed")
setError("预览渲染超时(120秒),请重试")
}, POLL_TIMEOUT)
const poll = async () => {
if (completed || seq !== requestSeqRef.current || !mountedRef.current) return
try {
const st = await getPreviewStatus(resp.task_id)
if (completed || seq !== requestSeqRef.current || !mountedRef.current) return
if (st.status === "completed" && st.video_url) {
completed = true
clearTimers()
renderedFingerprintRef.current = buildFingerprint(request)
setVideoUrl(st.video_url)
setProgress(100)
setStatus("ready")
setError(null)
return
}
if (st.status === "failed" || st.status === "cancelled") {
completed = true
clearTimers()
setStatus("failed")
setError(
st.status === "cancelled"
? "预览任务已取消"
: st.error_message || "预览渲染失败,请重试",
)
return
}
// pending / generating
if (typeof st.progress === "number") setProgress(st.progress)
pollTimerRef.current = setTimeout(poll, POLL_INTERVAL)
} catch (pollErr) {
if (completed || seq !== requestSeqRef.current || !mountedRef.current) return
if (networkRetriesRef.current < MAX_NETWORK_RETRIES) {
networkRetriesRef.current += 1
console.warn(
`[ServerPreview] 轮询网络错误,第 ${networkRetriesRef.current} 次重试`,
pollErr,
)
pollTimerRef.current = setTimeout(poll, POLL_INTERVAL * 2)
} else {
completed = true
clearTimers()
setStatus("failed")
setError("网络错误,无法获取预览状态,请重试")
}
}
}
poll()
} catch (createErr) {
if (seq !== requestSeqRef.current || !mountedRef.current) return
console.error("[ServerPreview] 创建预览任务失败:", createErr)
const isNetworkError =
!!(createErr as { request?: unknown })?.request ||
(createErr as { code?: string })?.code === "ERR_NETWORK"
if (isNetworkError && networkRetriesRef.current < MAX_NETWORK_RETRIES) {
networkRetriesRef.current += 1
console.warn(`[ServerPreview] 创建任务网络错误,第 ${networkRetriesRef.current} 次重试`)
setTimeout(() => {
if (seq === requestSeqRef.current && mountedRef.current) {
createAndPoll(request, seq)
}
}, POLL_INTERVAL * 2)
return
}
const errData = (
createErr as { response?: { data?: { detail?: string; message?: string } } }
)?.response?.data
setStatus("failed")
setError(errData?.detail || errData?.message || "预览任务创建失败,请重试")
}
},
[clearTimers],
)
/* ── 手动触发预览 ── */
const triggerPreview = useCallback(() => {
if (!enabled) return
const request = buildRequestRef.current()
if (!request.template_id || request.asset_ids.length === 0) return
clearTimers()
const seq = ++requestSeqRef.current
setVideoUrl(null)
setTaskId(null)
createAndPoll(request, seq)
}, [enabled, clearTimers, createAndPoll])
/* ── 自动触发 + 配置变更检测 ── */
// 每次 render 都检查最新配置 fingerprint,与已渲染的 fingerprint 比较
const request = enabled ? buildRequest() : null
const currentFingerprint = request
? request.template_id && request.asset_ids.length > 0
? buildFingerprint(request)
: ""
: ""
// 首次进入自动触发
const didInitRef = useRef(false)
useEffect(() => {
if (!enabled || !currentFingerprint) {
didInitRef.current = false
// 禁用时取消进行中的轮询,避免回到前序步骤后仍在后台轮询
requestSeqRef.current += 1
clearTimers()
return
}
if (!didInitRef.current) {
didInitRef.current = true
renderedFingerprintRef.current = currentFingerprint
triggerPreview()
}
}, [enabled, currentFingerprint, triggerPreview, clearTimers])
// 配置变更检测:素材/配音/BGM 等变化 → 自动重渲染;标题样式变化 → 标记 stale
const prevFingerprintRef = useRef(currentFingerprint)
useEffect(() => {
if (!enabled || !currentFingerprint) return
const prev = prevFingerprintRef.current
prevFingerprintRef.current = currentFingerprint
if (!prev || prev === currentFingerprint) return
if (currentFingerprint === renderedFingerprintRef.current) return
// 配置已变更
// 判断是标题样式变更还是素材/配音/BGM 变更
const prevParsed = JSON.parse(prev) as Record<string, unknown>
const currParsed = JSON.parse(currentFingerprint) as Record<string, unknown>
const nonTitleChanged =
prevParsed.t !== currParsed.t ||
prevParsed.a !== currParsed.a ||
prevParsed.d !== currParsed.d ||
prevParsed.r !== currParsed.r ||
prevParsed.v !== currParsed.v ||
JSON.stringify(prevParsed.b) !== JSON.stringify(currParsed.b)
if (nonTitleChanged) {
// 素材/配音/BGM/模板等变化 → 自动重新渲染
renderedFingerprintRef.current = currentFingerprint
triggerPreview()
} else {
// 仅标题文字/样式变化 → 标记 stale,不自动重渲染(避免频繁请求)
// 实时预览由 CSS TitleOverlay 提供
setStatus((s) => (s === "ready" ? "stale" : s))
}
}, [enabled, currentFingerprint, triggerPreview])
return {
status,
videoUrl,
error,
progress,
triggerPreview,
taskId,
}
}
export default useServerPreview
@@ -3,9 +3,14 @@
* 组合素材库加载 + 智能匹配两个子 Hook
*/
import { useCallback, useEffect, useRef } from "react"
import { message } from "antd"
import type { TemplateSegment } from "@/api/templates/types"
import type { EditPlanClip } from "@/api/template-editor"
import { updateEditPlanClips, createClipsFromAssets, getEditPlanClips } from "@/api/template-editor"
import { formatDuration } from "../utils/formatDuration"
import { useMaterialLibrary } from "./step2-materials/useMaterialLibrary"
import { useSmartMatch } from "./step2-materials/useSmartMatch"
import { useDraftAutoSave } from "./useDraftAutoSave"
interface UseStep2MaterialsProps {
materialMode: "manual" | "auto"
@@ -14,6 +19,12 @@ interface UseStep2MaterialsProps {
onSelectedMaterialsChange: (ids: string[]) => void
smartSelectedIds: string[]
onSmartSelectedIdsChange: (ids: string[]) => void
/** 当前选中的模板/草稿 ID,用于自动保存 */
selectedTemplate?: string
/** 当前模板的 segments(用于构建 clips duration */
templateSegments?: TemplateSegment[]
/** 服务端 clips 创建成功后的回调,用于通知预览播放器 */
onServerClipsChange?: (clips: EditPlanClip[]) => void
}
export function useStep2Materials({
@@ -23,6 +34,9 @@ export function useStep2Materials({
onSelectedMaterialsChange,
smartSelectedIds,
onSmartSelectedIdsChange,
selectedTemplate,
templateSegments,
onServerClipsChange,
}: UseStep2MaterialsProps) {
const { libraries, selectedLibraryId, setSelectedLibraryId, materials, materialsLoading } =
useMaterialLibrary()
@@ -53,6 +67,90 @@ export function useStep2Materials({
handleSmartMatch()
}, [selectedLibraryId, materialMode, materialsLoading, materials.items, handleSmartMatch])
/* ── Step2 选择素材后自动保存草稿 asset_ids(防抖 500ms,失败静默) ── */
const { scheduleSave } = useDraftAutoSave(selectedTemplate)
useEffect(() => {
if (!selectedTemplate) return
const ids = materialMode === "auto" ? smartSelectedIds : selectedMaterials
scheduleSave({ asset_ids: ids }, 500)
}, [selectedTemplate, materialMode, selectedMaterials, smartSelectedIds, scheduleSave])
/* ── Step2 选择素材后同步写入 edit_plan_clips(防抖 800ms,失败静默) ──
* 调用后端 POST /clips/from-assets,由后端处理:
* - 素材不够时同一素材切多个片段
* - 随机 start_time,不重复
* - required_clips_count 保证片段数与模板 segments 一致
* 先 PUT /clips(空数组)清空旧片段,再调用 from-assets 创建新片段
*/
const clipsTimerRef = useRef<ReturnType<typeof setTimeout>>()
const clipsAbortRef = useRef<AbortController | null>(null)
const templateSegmentsRef = useRef(templateSegments)
templateSegmentsRef.current = templateSegments
const selectedTemplateRef = useRef(selectedTemplate)
selectedTemplateRef.current = selectedTemplate
const onServerClipsChangeRef = useRef(onServerClipsChange)
onServerClipsChangeRef.current = onServerClipsChange
useEffect(() => {
const tid = selectedTemplateRef.current
if (!tid) return
const ids = materialMode === "auto" ? smartSelectedIds : selectedMaterials
if (!ids.length) {
onServerClipsChangeRef.current?.([])
return
}
if (clipsTimerRef.current) clearTimeout(clipsTimerRef.current)
clipsTimerRef.current = setTimeout(async () => {
// 取消上一次未完成的请求
if (clipsAbortRef.current) clipsAbortRef.current.abort()
const controller = new AbortController()
clipsAbortRef.current = controller
const segs = templateSegmentsRef.current || []
const requiredClipsCount = segs.length > 0 ? segs.length : undefined
try {
// 1. 清空旧片段
await updateEditPlanClips(tid, [], controller.signal)
// 2. 调用后端 from-assets 接口创建片段(60s 超时,与后端 MediaKit 一致)
await createClipsFromAssets(tid, ids, "main", requiredClipsCount, {
signal: controller.signal,
})
// 3. 获取服务端生成的 clips(含 start_time/duration),供预览播放器使用
const clipList = await getEditPlanClips(tid, { limit: 500 })
const readyClips = clipList.items
.filter((c) => c.status === "ready")
.sort((a, b) => a.order - b.order)
onServerClipsChangeRef.current?.(readyClips)
} catch (err) {
const name = (err as { name?: string })?.name
// 用户切换素材导致的主动取消,静默
if (name === "CanceledError" || name === "AbortError") return
// from-assets 60s 超时(MediaKit 智能选片未完成)
const code = (err as { code?: string })?.code
if (code === "ECONNABORTED" || /timeout/i.test((err as Error)?.message || "")) {
console.warn("[useStep2Materials] 智能选片超时:", err)
message.error("智能选片超时,请重试")
return
}
console.warn("[useStep2Materials] 写入 clips 失败:", err)
}
}, 800)
return () => {
if (clipsTimerRef.current) clearTimeout(clipsTimerRef.current)
}
}, [selectedTemplate, materialMode, selectedMaterials, smartSelectedIds, templateSegments])
// 组件卸载时取消未完成请求
useEffect(() => {
return () => {
if (clipsTimerRef.current) clearTimeout(clipsTimerRef.current)
if (clipsAbortRef.current) clipsAbortRef.current.abort()
}
}, [])
/* ── 手动选择素材 ── */
const handleToggleMaterial = useCallback(
(materialId: string) => {
@@ -4,17 +4,24 @@ import { getTitles } from "@/api/titles"
import type { TitleSettings } from "../../types"
import { useAiTitleGenerator } from "./useAiTitleGenerator"
import { useTitleStyleUpdaters } from "./useTitleStyleUpdaters"
import { useDraftAutoSave } from "../useDraftAutoSave"
interface UseStep4TitleProps {
titleSettings: TitleSettings
onTitleSettingsChange: (settings: TitleSettings) => void
/** 当前选中的模板/草稿 ID,用于自动保存 */
selectedTemplate?: string
}
/**
* Step 4 标题设置 Hook
* 封装 AI 标题生成、标题样式设置等逻辑
*/
export function useStep4Title({ titleSettings, onTitleSettingsChange }: UseStep4TitleProps) {
export function useStep4Title({
titleSettings,
onTitleSettingsChange,
selectedTemplate,
}: UseStep4TitleProps) {
// 标题库数据
const { data: userTitles = [] } = useQuery({
queryKey: ["titles"],
@@ -42,6 +49,38 @@ export function useStep4Title({ titleSettings, onTitleSettingsChange }: UseStep4
const prevAiAutoSelect = useRef(titleSettings.aiAutoSelect)
const isFirstMount = useRef(true)
/* ── Step4 标题内容/样式变化后自动保存草稿(防抖 800ms,失败静默) ── */
const { scheduleSave: scheduleTitleSave } = useDraftAutoSave(selectedTemplate)
useEffect(() => {
if (!selectedTemplate) return
scheduleTitleSave(
{
title: {
text: titleSettings.title,
font: titleSettings.font,
font_size: titleSettings.size,
color: titleSettings.color,
position: titleSettings.position,
bold: titleSettings.bold,
stroke: titleSettings.stroke,
shadow: titleSettings.shadow,
},
},
800,
)
}, [
selectedTemplate,
titleSettings.title,
titleSettings.font,
titleSettings.size,
titleSettings.color,
titleSettings.position,
titleSettings.bold,
titleSettings.stroke,
titleSettings.shadow,
scheduleTitleSave,
])
// 当 AI 自动选择开关打开时,自动生成/选择一个标题填入
// 首次挂载时如果开关已经是 true 且无标题,也需要触发
useEffect(() => {
@@ -2,11 +2,13 @@
* Step 6 封面设置 Hook
* 封装封面设置的交互逻辑,对接后端封面模板 CRUD API
*/
import { useCallback, useEffect, useState } from "react"
import { useCallback, useEffect, useRef, useState } from "react"
import { message } from "antd"
import type { CoverConfig, CoverTemplate } from "../types/cover"
import { generateCover } from "@/api/generation"
import { createPreview, getPreviewStatus } from "@/api/generation/preview"
import { updateEditPlan } from "@/api/template-editor"
import type { TitleSettings } from "../types"
import {
fetchCoverTemplates,
createCoverTemplate,
@@ -22,6 +24,22 @@ interface UseStep6CoverProps {
assetIds?: string[]
/** 当前选中的模板 ID */
selectedTemplate?: string
/** Step4 标题设置,用于预览视频烧录标题 & 封面叠加标题 */
titleSettings?: TitleSettings
/** 预览任务创建回调——将 task_id 暴露给父组件供 confirmGeneration 复用 */
onPreviewTaskCreated?: (taskId: string) => void
/** 从预览响应中提取到 source_edit_plan_id 时的回调 */
onSourceEditPlanIdExtracted?: (planId: string) => void
/** 配音模式 */
voiceMode?: "preset" | "custom" | "clone"
/** 选中的配音素材 ID(配音素材库 asset ID */
selectedVoice?: string
/** 选中的克隆音色 ID */
selectedClonedVoice?: string
/** BGM 开关 */
bgm?: boolean
/** BGM 配置(来自模板) */
bgmConfig?: { enabled: boolean; music_id?: string }
}
export function useStep6Cover({
@@ -30,8 +48,18 @@ export function useStep6Cover({
duration,
assetIds = [],
selectedTemplate = "",
titleSettings,
onPreviewTaskCreated,
onSourceEditPlanIdExtracted,
voiceMode,
selectedVoice,
selectedClonedVoice,
bgm,
bgmConfig,
}: UseStep6CoverProps) {
const [generating, setGenerating] = useState(false)
// 防竞态:记录当前预览生成的参数指纹,任务完成时校验一致性
const previewParamsRef = useRef<string>("")
// ── 封面设置弹窗状态 ──
const [showCoverSettings, setShowCoverSettings] = useState(false)
@@ -92,6 +120,20 @@ export function useStep6Cover({
const response = await generateCover(selectedTemplate, {
asset_ids: assetIds,
cover_type: "ai_frame",
...(titleSettings?.title
? {
title_config: {
text: titleSettings.title,
font: titleSettings.font,
font_size: titleSettings.size,
font_color: titleSettings.color,
position: titleSettings.position,
bold: titleSettings.bold,
stroke: titleSettings.stroke,
shadow: titleSettings.shadow,
},
}
: {}),
})
clearTimeout(timeoutId)
const thumbnailUrl = response.cover?.image_url || ""
@@ -132,11 +174,48 @@ export function useStep6Cover({
console.log("[Step6] 检测到预览缺失,尝试自动创建预览渲染任务...")
message.info("正在准备预览视频,请稍候...")
try {
// 记录当前参数指纹,用于任务完成时校验一致性(防竞态)
previewParamsRef.current = JSON.stringify({ selectedTemplate, assetIds, titleSettings })
// 解析配音参数:voiceMode=clone 时用 selectedClonedVoice,否则用 selectedVoice
const previewVoiceLibraryId =
voiceMode === "clone" ? selectedClonedVoice || selectedVoice || "" : selectedVoice || ""
const previewResp = await createPreview({
template_id: selectedTemplate,
asset_ids: assetIds,
duration: duration || 30,
// 配音:始终传递 voice_library_id,确保后端能正确接收
voice_library_id: previewVoiceLibraryId,
// 兜底:如果 voice_library_id 为空但 selectedVoice 有值,也传 voice_ids
...(selectedVoice && !previewVoiceLibraryId ? { voice_ids: [selectedVoice] } : {}),
// BGM 配置:受 bgm 开关控制
bgm_config: {
enabled: bgm !== false,
...(bgmConfig?.music_id ? { preset_id: bgmConfig.music_id } : {}),
},
...(titleSettings?.title
? {
title_config: {
text: titleSettings.title,
font: titleSettings.font,
font_size: titleSettings.size,
font_color: titleSettings.color,
position: titleSettings.position,
bold: titleSettings.bold,
stroke: titleSettings.stroke,
shadow: titleSettings.shadow,
},
}
: {}),
})
// 将预览任务 ID 暴露给父组件,供 Step7 确认生成时复用(confirmGeneration
const currentFingerprint = JSON.stringify({ selectedTemplate, assetIds, titleSettings })
if (previewResp.task_id && previewParamsRef.current === currentFingerprint) {
onPreviewTaskCreated?.(previewResp.task_id)
// 提取后端自动关联的 source_edit_plan_id,供 fallback 路径使用
if (previewResp.source_edit_plan_id) {
onSourceEditPlanIdExtracted?.(previewResp.source_edit_plan_id)
}
}
// 轮询等待预览渲染完成:递归 setTimeout 避免请求重叠 + 120s 超时兜底
await new Promise<void>((resolve, reject) => {
let finished = false
@@ -154,6 +233,21 @@ export function useStep6Cover({
try {
const status = await getPreviewStatus(previewResp.task_id)
if (status.status === "completed") {
// 保存预览视频地址到 plan.config.rendered_storage_key
// 供封面 API 的 E1 兜底路径定位渲染后的视频(含标题烧录)。
// video_url 可能是完整 http(s) URL 或 OSS storage_key,两种格式后端都能处理。
if (status.video_url) {
try {
await updateEditPlan(selectedTemplate, {
config: { rendered_storage_key: status.video_url },
})
} catch (saveErr) {
console.warn(
"[Step6] 保存 rendered_storage_key 失败(不阻塞封面重试):",
saveErr,
)
}
}
done(() => resolve())
} else if (status.status === "failed") {
done(() => reject(new Error(status.error_message || "预览渲染失败")))
@@ -171,6 +265,20 @@ export function useStep6Cover({
const retryResp = await generateCover(selectedTemplate, {
asset_ids: assetIds,
cover_type: "ai_frame",
...(titleSettings?.title
? {
title_config: {
text: titleSettings.title,
font: titleSettings.font,
font_size: titleSettings.size,
font_color: titleSettings.color,
position: titleSettings.position,
bold: titleSettings.bold,
stroke: titleSettings.stroke,
shadow: titleSettings.shadow,
},
}
: {}),
})
const retryUrl = retryResp.cover?.image_url || ""
if (retryUrl) {
@@ -212,7 +320,22 @@ export function useStep6Cover({
clearTimeout(timeoutId)
setGenerating(false)
}
}, [selectedTemplate, assetIds, coverSettings, onCoverSettingsChange, generating, duration])
}, [
selectedTemplate,
assetIds,
coverSettings,
onCoverSettingsChange,
generating,
duration,
titleSettings,
onPreviewTaskCreated,
onSourceEditPlanIdExtracted,
voiceMode,
selectedVoice,
selectedClonedVoice,
bgm,
bgmConfig,
])
// ── 模板操作方法 ──
const handleSelectTemplate = useCallback((id: string) => {
@@ -25,8 +25,6 @@ interface UseStep7GenerateProps {
presetVoices: PresetVoiceItem[]
clonedVoices: VoiceClone[]
coverSettings: CoverConfig
generateCount: number
onGenerateCountChange: (count: number) => void
generating: boolean
generated: boolean
generateError: string | null
@@ -47,8 +45,6 @@ export function useStep7Generate({
presetVoices: _presetVoices,
clonedVoices: _clonedVoices,
coverSettings,
generateCount,
onGenerateCountChange,
generating,
generated,
generateError,
@@ -90,14 +86,6 @@ export function useStep7Generate({
return { label: "即将完成", icon: "✨" }
}
const handleDecrement = () => {
onGenerateCountChange(Math.max(1, generateCount - 1))
}
const handleIncrement = () => {
onGenerateCountChange(Math.min(10, generateCount + 1))
}
const handleScrollToPreview = () => {
const el = document.querySelector(".xx-preview-section")
el?.scrollIntoView({ behavior: "smooth", block: "start" })
@@ -109,9 +97,6 @@ export function useStep7Generate({
title,
voiceName,
coverSummary,
generateCount,
handleDecrement,
handleIncrement,
generating,
generated,
generateError,
@@ -3,7 +3,7 @@
* 管理步骤切换与各步骤的前置校验
* 步骤顺序:模板(1) → 素材(2) → 配音(3) → 标题(4) → 预览(5) → 封面(6) → 确认(7)
*
* V24: previewReady 改为前端素材加载状态
* 前端实时预览架构:Step5 无需等待服务器渲染
*/
import { message } from "antd"
import type { TitleSettings } from "../types"
@@ -16,8 +16,6 @@ export interface UseStepNavigationOptions {
selectedMaterials: string[]
smartSelectedIds: string[]
titleSettings: TitleSettings
/** 预览是否就绪(前端素材已加载) */
previewReady: boolean
}
export interface UseStepNavigationReturn {
@@ -34,7 +32,6 @@ export const useStepNavigation = (options: UseStepNavigationOptions): UseStepNav
selectedMaterials,
smartSelectedIds,
titleSettings,
previewReady,
} = options
const goNext = () => {
@@ -50,15 +47,10 @@ export const useStepNavigation = (options: UseStepNavigationOptions): UseStepNav
message.warning("请先进行智能匹配并选择素材")
return
}
// Step3 配音:配音为可选项,不强制校验,用户可跳过
if (currentStep === 4 && !titleSettings.title.trim()) {
message.warning("请选择或输入标题")
return
}
if (currentStep === 5 && !previewReady) {
message.warning("请先选择素材以预览效果")
return
}
if (currentStep < 7) {
setCurrentStep((s) => s + 1)
}
@@ -0,0 +1,46 @@
/**
* 根据视频比例计算输出分辨率
*
* 规则:
* - 长边固定 1920
* - 短边按 1920 × (短/长) 计算,对齐到偶数
* - 9:16 → 1080×1920(竖屏)
* - 16:9 → 1920×1080(横屏)
* - 1:1 → 1920×1920
* - 无法解析时 fallback 到 1080×1920
*/
export interface Resolution {
width: number
height: number
}
export function calculateResolution(ratio: string): Resolution {
if (!ratio) return { width: 1080, height: 1920 }
if (ratio.includes(":")) {
const [rw, rh] = ratio.split(":").map(Number)
if (rw > 0 && rh > 0) {
const [longSide, shortSide] = rw < rh ? [rh, rw] : [rw, rh]
const baseLong = 1920
const baseShort = Math.round((baseLong * shortSide) / longSide)
const evenShort = baseShort - (baseShort % 2)
if (rw < rh) {
// 竖屏:短边是宽,长边是高
return { width: evenShort, height: baseLong }
} else {
// 横屏:长边是宽,短边是高
return { width: baseLong, height: evenShort }
}
}
return { width: 1080, height: 1920 }
}
if (ratio.includes("x")) {
const [wStr, hStr] = ratio.split("x")
const w = parseInt(wStr, 10) || 1080
const h = parseInt(hStr, 10) || 1920
return { width: w, height: h }
}
return { width: 1080, height: 1920 }
}
@@ -87,7 +87,7 @@ export const useTemplateLibrary = () => {
[copyMutation],
)
/* 操作:使用模板 → 跳转剪辑编辑器 */
/* 操作:使用模板 → 跳转剪辑模板 */
const handleUse = useCallback(
(template: TemplateItem) => {
navigate(`/app/editing-planner?templateId=${template.id}`)
+2 -2
View File
@@ -32,7 +32,7 @@ describe("bgm API", () => {
describe("getBgmPresets", () => {
it("should resolve successfully", async () => {
await expect(getBgmPresets("test-params?")).resolves.not.toThrow()
await expect(getBgmPresets("test-template", { category: "test" })).resolves.not.toThrow()
})
it("should reject on API error", async () => {
@@ -42,7 +42,7 @@ describe("bgm API", () => {
mockDelete.mockRejectedValue(new Error("Network error"))
mockPatch.mockRejectedValue(new Error("Network error"))
await expect(getBgmPresets("test-params?")).rejects.toThrow()
await expect(getBgmPresets("test-template", { category: "test" })).rejects.toThrow()
})
})
})
-136
View File
@@ -1,16 +1,9 @@
import { describe, expect, it, vi, beforeEach } from "vitest"
import {
getEditPlans,
getEditPlan,
createEditPlan,
updateEditPlan,
deleteEditPlan,
generateEditPlan,
getGenerationStatus,
aiRecommendClips,
getEditPlanGenerations,
getGenerationTaskResults,
cancelGeneration,
getEditPlanClips,
getEditPlanClip,
createEditPlanClip,
@@ -19,7 +12,6 @@ import {
reorderEditPlanClips,
batchDeleteEditPlanClips,
createClipsFromAssets,
copyEditPlan,
getMediaAssets,
getMediaAsset,
} from "@/api/template-editor"
@@ -53,22 +45,6 @@ describe("editPlans API", () => {
mockPatch.mockResolvedValue({ data: { success: true, items: [] } })
})
describe("getEditPlans", () => {
it("should resolve successfully", async () => {
await expect(getEditPlans("test-params?")).resolves.not.toThrow()
})
it("should reject on API error", async () => {
mockGet.mockRejectedValue(new Error("Network error"))
mockPost.mockRejectedValue(new Error("Network error"))
mockPut.mockRejectedValue(new Error("Network error"))
mockDelete.mockRejectedValue(new Error("Network error"))
mockPatch.mockRejectedValue(new Error("Network error"))
await expect(getEditPlans("test-params?")).rejects.toThrow()
})
})
describe("getEditPlan", () => {
it("should resolve successfully", async () => {
await expect(getEditPlan("test-planId")).resolves.not.toThrow()
@@ -85,22 +61,6 @@ describe("editPlans API", () => {
})
})
describe("createEditPlan", () => {
it("should resolve successfully", async () => {
await expect(createEditPlan({ name: "test-item" })).resolves.not.toThrow()
})
it("should reject on API error", async () => {
mockGet.mockRejectedValue(new Error("Network error"))
mockPost.mockRejectedValue(new Error("Network error"))
mockPut.mockRejectedValue(new Error("Network error"))
mockDelete.mockRejectedValue(new Error("Network error"))
mockPatch.mockRejectedValue(new Error("Network error"))
await expect(createEditPlan({ name: "test-item" })).rejects.toThrow()
})
})
describe("updateEditPlan", () => {
it("should resolve successfully", async () => {
await expect(updateEditPlan("test-planId")).resolves.not.toThrow()
@@ -117,54 +77,6 @@ describe("editPlans API", () => {
})
})
describe("deleteEditPlan", () => {
it("should resolve successfully", async () => {
await expect(deleteEditPlan("test-planId")).resolves.not.toThrow()
})
it("should reject on API error", async () => {
mockGet.mockRejectedValue(new Error("Network error"))
mockPost.mockRejectedValue(new Error("Network error"))
mockPut.mockRejectedValue(new Error("Network error"))
mockDelete.mockRejectedValue(new Error("Network error"))
mockPatch.mockRejectedValue(new Error("Network error"))
await expect(deleteEditPlan("test-planId")).rejects.toThrow()
})
})
describe("generateEditPlan", () => {
it("should resolve successfully", async () => {
await expect(generateEditPlan("test-planId")).resolves.not.toThrow()
})
it("should reject on API error", async () => {
mockGet.mockRejectedValue(new Error("Network error"))
mockPost.mockRejectedValue(new Error("Network error"))
mockPut.mockRejectedValue(new Error("Network error"))
mockDelete.mockRejectedValue(new Error("Network error"))
mockPatch.mockRejectedValue(new Error("Network error"))
await expect(generateEditPlan("test-planId")).rejects.toThrow()
})
})
describe("getGenerationStatus", () => {
it("should resolve successfully", async () => {
await expect(getGenerationStatus("test-planId")).resolves.not.toThrow()
})
it("should reject on API error", async () => {
mockGet.mockRejectedValue(new Error("Network error"))
mockPost.mockRejectedValue(new Error("Network error"))
mockPut.mockRejectedValue(new Error("Network error"))
mockDelete.mockRejectedValue(new Error("Network error"))
mockPatch.mockRejectedValue(new Error("Network error"))
await expect(getGenerationStatus("test-planId")).rejects.toThrow()
})
})
describe("aiRecommendClips", () => {
it("should resolve successfully", async () => {
await expect(aiRecommendClips("test-planId")).resolves.not.toThrow()
@@ -181,22 +93,6 @@ describe("editPlans API", () => {
})
})
describe("getEditPlanGenerations", () => {
it("should resolve successfully", async () => {
await expect(getEditPlanGenerations("test-planId")).resolves.not.toThrow()
})
it("should reject on API error", async () => {
mockGet.mockRejectedValue(new Error("Network error"))
mockPost.mockRejectedValue(new Error("Network error"))
mockPut.mockRejectedValue(new Error("Network error"))
mockDelete.mockRejectedValue(new Error("Network error"))
mockPatch.mockRejectedValue(new Error("Network error"))
await expect(getEditPlanGenerations("test-planId")).rejects.toThrow()
})
})
describe("getGenerationTaskResults", () => {
it("should resolve successfully", async () => {
await expect(getGenerationTaskResults("test-taskId")).resolves.not.toThrow()
@@ -213,22 +109,6 @@ describe("editPlans API", () => {
})
})
describe("cancelGeneration", () => {
it("should resolve successfully", async () => {
await expect(cancelGeneration("test-planId")).resolves.not.toThrow()
})
it("should reject on API error", async () => {
mockGet.mockRejectedValue(new Error("Network error"))
mockPost.mockRejectedValue(new Error("Network error"))
mockPut.mockRejectedValue(new Error("Network error"))
mockDelete.mockRejectedValue(new Error("Network error"))
mockPatch.mockRejectedValue(new Error("Network error"))
await expect(cancelGeneration("test-planId")).rejects.toThrow()
})
})
describe("getEditPlanClips", () => {
it("should resolve successfully", async () => {
await expect(getEditPlanClips("test-planId")).resolves.not.toThrow()
@@ -357,22 +237,6 @@ describe("editPlans API", () => {
})
})
describe("copyEditPlan", () => {
it("should resolve successfully", async () => {
await expect(copyEditPlan("test-planId")).resolves.not.toThrow()
})
it("should reject on API error", async () => {
mockGet.mockRejectedValue(new Error("Network error"))
mockPost.mockRejectedValue(new Error("Network error"))
mockPut.mockRejectedValue(new Error("Network error"))
mockDelete.mockRejectedValue(new Error("Network error"))
mockPatch.mockRejectedValue(new Error("Network error"))
await expect(copyEditPlan("test-planId")).rejects.toThrow()
})
})
describe("getMediaAssets", () => {
it("should resolve successfully", async () => {
await expect(getMediaAssets("test-libraryId?")).resolves.not.toThrow()
-17
View File
@@ -5,7 +5,6 @@ import {
getTemplate,
toggleFavoriteTemplate,
copyTemplate,
generateFromTemplate,
} from "@/api/templates"
const mockGet = vi.fn()
@@ -116,20 +115,4 @@ describe("templates API", () => {
await expect(copyTemplate("test-templateId")).rejects.toThrow()
})
})
describe("generateFromTemplate", () => {
it("should resolve successfully", async () => {
await expect(generateFromTemplate("test-templateId")).resolves.not.toThrow()
})
it("should reject on API error", async () => {
mockGet.mockRejectedValue(new Error("Network error"))
mockPost.mockRejectedValue(new Error("Network error"))
mockPut.mockRejectedValue(new Error("Network error"))
mockDelete.mockRejectedValue(new Error("Network error"))
mockPatch.mockRejectedValue(new Error("Network error"))
await expect(generateFromTemplate("test-templateId")).rejects.toThrow()
})
})
})
@@ -148,14 +148,9 @@ vi.mock("@/api/editing-planner", () => ({
vi.mock("@/api/template-editor", () => ({
getMediaAssets: vi.fn().mockResolvedValue({ items: [] }),
getEditPlanGenerations: vi.fn().mockResolvedValue({ items: [] }),
getEditPlan: vi.fn().mockResolvedValue({}),
createEditPlan: vi.fn().mockResolvedValue({ id: "test-plan" }),
updateEditPlan: vi.fn().mockResolvedValue({}),
generateEditPlan: vi.fn().mockResolvedValue({ task_id: "test-task" }),
getGenerationStatus: vi.fn().mockResolvedValue({ status: "completed" }),
getGenerationTaskResults: vi.fn().mockResolvedValue({ items: [] }),
cancelGeneration: vi.fn().mockResolvedValue({}),
getEditPlanClips: vi.fn().mockResolvedValue({ items: [] }),
createEditPlanClip: vi.fn().mockResolvedValue({}),
batchDeleteEditPlanClips: vi.fn().mockResolvedValue({}),
@@ -225,12 +220,6 @@ vi.mock("@/pages/editing-planner/components/StickerPanel", () => ({
vi.mock("@/pages/editing-planner/components/SaveModal", () => ({
default: () => React.createElement("div", { "data-testid": "SaveModal" }),
}))
vi.mock("@/pages/editing-planner/components/GenerationHistoryModal", () => ({
default: () => React.createElement("div", { "data-testid": "GenerationHistoryModal" }),
}))
vi.mock("@/pages/editing-planner/components/GenerationProgressModal", () => ({
default: () => React.createElement("div", { "data-testid": "GenerationProgressModal" }),
}))
// === useUndoRedo hook mock ===
vi.mock("@/pages/editing-planner/hooks/useUndoRedo", () => ({
@@ -214,12 +214,6 @@ vi.mock("@/api/titles", () => ({
}))
vi.mock("@/api/template-editor", () => ({
generateEditPlan: vi.fn().mockResolvedValue({
plan_id: "test-plan",
generation_task_id: "test-task",
plan_status: "processing",
clip_count: 5,
}),
updateEditPlan: vi.fn().mockResolvedValue({ plan_id: "test-plan", template_id: "test-template" }),
getEditPlan: vi.fn().mockResolvedValue({
plan_id: "test-plan",
@@ -228,9 +222,6 @@ vi.mock("@/api/template-editor", () => ({
config: {},
status: "draft",
}),
getGenerationStatus: vi
.fn()
.mockResolvedValue({ plan_status: "completed", generation_task_id: "test-task", clips: [] }),
getGenerationTaskResults: vi.fn().mockResolvedValue({ items: [] }),
}))
@@ -109,7 +109,6 @@ vi.mock("@/api/templates", () => ({
getTemplate: vi.fn().mockResolvedValue({ items: [], total: 0, success: true }),
toggleFavoriteTemplate: vi.fn().mockResolvedValue({ items: [], total: 0, success: true }),
copyTemplate: vi.fn().mockResolvedValue({ items: [], total: 0, success: true }),
generateFromTemplate: vi.fn().mockResolvedValue({ items: [], total: 0, success: true }),
}))
vi.mock("@/pages/templates/TemplateLibrary.css", () => ({}))
@@ -1,39 +0,0 @@
import { describe, expect, it, vi } from "vitest"
import { render } from "@testing-library/react"
import GenerationHistoryModal from "@/pages/editing-planner/components/GenerationHistoryModal"
const defaultProps = {
open: true,
loading: false,
history: [],
onClose: vi.fn(),
onCancel: vi.fn(),
cancelLoading: false,
}
describe("GenerationHistoryModal", () => {
it("should render without crashing", () => {
const { container } = render(<GenerationHistoryModal {...defaultProps} />)
expect(container).toBeTruthy()
})
it("should not render when open is false", () => {
const { container } = render(<GenerationHistoryModal {...defaultProps} open={false} />)
expect(container.firstChild).toBeNull()
})
it("should render with history items", () => {
const history = [
{
id: "1",
status: "completed",
created_at: "2024-01-01T00:00:00Z",
duration: 60,
},
]
const { container } = render(
<GenerationHistoryModal {...defaultProps} history={history as any} />,
)
expect(container).toBeTruthy()
})
})
@@ -1,102 +0,0 @@
import { describe, expect, it, vi } from "vitest"
import { render } from "@testing-library/react"
import GenerationProgressModal from "@/pages/editing-planner/components/GenerationProgressModal"
const baseProps = {
open: true,
voiceoverDuration: null,
estimatedDuration: 60,
onDurationChange: vi.fn(),
onGenerate: vi.fn(),
task: null,
submitting: false,
onCancel: vi.fn(),
onRetry: vi.fn(),
onClose: vi.fn(),
}
describe("GenerationProgressModal", () => {
it("should render setup phase", () => {
const { container } = render(<GenerationProgressModal {...baseProps} phase="setup" />)
expect(container).toBeTruthy()
})
it("should render progress phase without task", () => {
const { container } = render(<GenerationProgressModal {...baseProps} phase="progress" />)
expect(container).toBeTruthy()
})
it("should render progress phase with task data", () => {
const { container } = render(
<GenerationProgressModal
{...baseProps}
phase="progress"
task={
{
id: "task-123",
status: "generating_video",
progress: 50,
current_step: "generating_video",
user_message: "正在生成视频",
} as any
}
/>,
)
expect(container).toBeTruthy()
})
it("should render completed phase", () => {
const { container } = render(
<GenerationProgressModal
{...baseProps}
phase="completed"
task={{ id: "task-1", status: "completed", progress: 100 } as any}
/>,
)
expect(container).toBeTruthy()
})
it("should render failed phase with retry", () => {
const { container } = render(
<GenerationProgressModal
{...baseProps}
phase="failed"
task={
{
id: "task-1",
status: "failed",
progress: 30,
error_message: "生成失败",
retryable: true,
} as any
}
/>,
)
expect(container).toBeTruthy()
})
it("should render failed phase without retry", () => {
const { container } = render(
<GenerationProgressModal
{...baseProps}
phase="failed"
task={
{
id: "task-1",
status: "failed",
progress: 30,
retryable: false,
} as any
}
/>,
)
expect(container).toBeTruthy()
})
it("should not render when closed", () => {
const { container } = render(
<GenerationProgressModal {...baseProps} phase="setup" open={false} />,
)
expect(container).toBeTruthy()
})
})
@@ -31,8 +31,6 @@ import "@/pages/editing-planner/components/ClipPropertiesPanel"
import "@/pages/editing-planner/components/EditorClipList"
import "@/pages/editing-planner/components/EditingDrawers"
import "@/pages/editing-planner/components/FilterPanel"
import "@/pages/editing-planner/components/GenerationHistoryModal"
import "@/pages/editing-planner/components/GenerationProgressModal"
import "@/pages/editing-planner/components/GreenScreenPanel"
import "@/pages/editing-planner/components/IntroOutroPanel"
import "@/pages/editing-planner/components/MediaPanel"
+1 -1
View File
@@ -7,7 +7,7 @@ VideoProcessor 等)按需从子模块导入,避免 __init__ 阶段引入
packages / DB 等重依赖。
"""
# 共享工具模块(零外部依赖,供 editing_modes / generation / edit_plan_generation 等复用)
# 共享工具模块(零外部依赖,供 editing_modes / generation 等复用)
from . import dedup_helpers, ffmpeg_utils, oss_helpers, url_security
__all__ = [
@@ -1,6 +1,6 @@
"""查重辅助函数 — 从 generation.py 提取的 GeneratedVideo 记录 + 查重逻辑.
render_edit_plan 和 generate_video 共同复用,
供 generate_video 共同复用,
创建 GeneratedVideo 记录后计算指纹并执行项目级 + 批次内查重。
"""
+1 -1
View File
@@ -1,4 +1,4 @@
"""OSS 工具函数 — 从 generation.py / edit_plan_generation.py 提取的共享 OSS 操作.
"""OSS 工具函数 — 从 generation.py 提取的共享 OSS 操作.
提供 OSS 配置读取、Bucket 创建、素材上传/下载、asset_id → 本地路径解析
等能力,供 render_edit_plan 和 generate_video 共同复用。
+15 -9
View File
@@ -84,6 +84,7 @@ class RenderAdapterResult:
cover_candidates: list[dict] | None = (
None # 封面候选帧 [{"image_url": "...", "frame_time": 5.0, "storage_key": "..."}]
)
temp_dir: str | None = None # 渲染临时目录,成功时由调用方清理,失败时由 finally 清理
def __post_init__(self):
if self.rendered_clip_ids is None:
@@ -128,6 +129,7 @@ class RenderAdapter:
job_id: str = "",
work_dir: Path | None = None,
progress_cb: ProgressCallback | None = None,
voiceover_audio_path: str | None = None,
) -> RenderAdapterResult:
"""渲染一个 EditPlan。
@@ -142,6 +144,7 @@ class RenderAdapter:
job_id: 关联的 Job ID(用于结果存储路径)
work_dir: 工作目录,不传则使用临时目录
progress_cb: 进度回调函数
voiceover_audio_path: 配音音频本地路径(一键生成场景使用)
Returns:
RenderAdapterResult
@@ -198,7 +201,7 @@ class RenderAdapter:
self._report_progress(progress_cb, 35.0, "准备 BGM 音频")
# 3~6. 统一渲染核心流程(BGM + ASR + 渲染 + 缩略图 + 上传)
return self._do_render(
result = self._do_render(
plan=plan,
clips=ready_clips,
asset_path_map=asset_path_map,
@@ -208,7 +211,13 @@ class RenderAdapter:
progress_cb=progress_cb,
rendered_clip_ids=rendered_clip_ids,
failed_clip_ids=failed_clip_ids,
voiceover_audio_path=voiceover_audio_path,
)
# 成功时将临时目录所有权转移给调用方,阻止 finally 清理
if result.success and temp_dir:
result.temp_dir = temp_dir
temp_dir = None # 阻止 finally 块清理
return result
except subprocess.CalledProcessError as exc:
stderr_text = (exc.stderr or "").strip()
@@ -571,7 +580,7 @@ class RenderAdapter:
try:
from video_processing.thumbnail_generator import generate_and_upload_thumbnail
thumb_storage_key = f"rendered/{plan_id}/thumbnail.jpg"
thumb_storage_key = f"rendered/{plan_id}/thumbnails/{job_id}.jpg"
thumbnail_url = generate_and_upload_thumbnail(str(result.output_path), thumb_storage_key)
except Exception as thumb_err:
logger.warning(
@@ -585,14 +594,11 @@ class RenderAdapter:
try:
from video_processing.thumbnail_generator import extract_and_upload_cover_frames
# 从 plan config 提取标题文字,叠加到封面候选帧上
_title_cfg = (plan_config or {}).get("title", {}) or {}
if not isinstance(_title_cfg, dict):
_title_cfg = {}
_title_text = (_title_cfg.get("text", "") or "").strip() if _title_cfg.get("enabled", True) else ""
# 已渲染视频在统一渲染阶段已通过 ASS 字幕把标题烧录进画面,
# 抽帧天然带标题,因此这里传空字符串,避免 Pillow 二次叠加导致重影。
# Pillow 叠加仅用于 API 从源素材抽帧(源素材本身无标题)的兜底场景。
cover_candidates = extract_and_upload_cover_frames(
str(result.output_path), plan_id, num_frames=3, title_text=_title_text
str(result.output_path), plan_id, task_id=job_id, num_frames=3, title_text=""
)
if cover_candidates:
logger.info(
+97 -32
View File
@@ -67,6 +67,16 @@ def clip_has_audio(ctx: RenderContext, clip: ResolvedClip) -> bool:
return ctx._audio_cache[key]
def _clip_volume(clip: ResolvedClip) -> float:
"""读取 clip 的音量配置(0.0~1.0>1 放大)。缺省 1.0 原声。"""
cfg = getattr(clip, "config", None) or {}
try:
vol = float(cfg.get("volume", 1.0))
except (TypeError, ValueError):
return 1.0
return max(0.0, vol)
# ── 音频混音 ──────────────────────────────────────────────────────────────────
@@ -82,12 +92,13 @@ def mix_audio(
"""音频后处理混音.
处理逻辑:
1. 丢弃主图层(main/broll/overlay/corner_voice的原始音频,避免录入源视频杂音
2. 仅使用独立音频轨(audio role,TTS/配音)作为主音频
3. 如果提供了 bgm_path,则额外混入 BGM(支持淡入淡出、循环、人声闪避)
4. 如果配置了 audio_tracks,则混入多轨道音频(配音、音效等
5. 输出时长截断到 video_duration
6. 如果配置了降噪,最后应用降噪
1. 保留主图层(main/broll/overlay/corner_voice视频素材的原声,按顺序 concat 拼接
2. 每个 clip 按 config.volume 应用音量(volume=0 静音,=1 原声)
3. 独立音频轨(audio roleTTS/配音)通过 amix 混入
4. 如果提供了 bgm_path,则额外混入 BGM(支持淡入淡出、循环、人声闪避
5. 如果配置了 audio_tracks,则混入多轨道音频(配音、音效等)
6. 输出时长截断到 video_duration
7. 如果配置了降噪,最后应用降噪
Args:
ctx: 渲染上下文
@@ -123,10 +134,12 @@ def mix_audio(
if "audio" in layer_map:
audio_clips = layer_map["audio"].clips
# ── 丢弃源视频的原始音频(避免录入杂音),成片仅保留 TTS 配音 + BGM ──
main_clips = []
# ── 保留源视频原声:过滤掉无音频流的 main clip(图片/无声素材) ──
# 注意:volume=0 的 clip 不能移除——移除会导致后续 clip 音频时间轴前移、音画不同步。
# volume=0 通过滤镜链生成静音流,保持时间轴对齐。
main_clips = [c for c in main_clips if clip_has_audio(ctx, c)]
# ── 防御:过滤掉无音频流的 clip ──
# ── 防御:过滤掉无音频流的独立音频轨 ──
audio_clips = [c for c in audio_clips if clip_has_audio(ctx, c)]
if not main_clips and not audio_clips:
@@ -144,7 +157,7 @@ def mix_audio(
# 构建音频处理命令
output_path = ctx.work_dir / f"audio_{ctx.plan_id}.aac"
# 源视频原始音频已被丢弃(main_clips = []),最终音频完全由独立音频轨 + BGM + 多轨配置组成
# 主音频为视频素材原声 concat;独立音频轨(TTS/配音)通过 amix 混入
# 当无 main_clips 时,将独立音频轨作为主音频走 concat 拼接;当二者均有则走 amix 混音。
if main_clips:
effective_main = main_clips
@@ -266,28 +279,67 @@ def concat_main_audio(
has_speed = abs(speed - 1.0) >= 1e-6
if not has_speed and not has_reverse:
# 无调速无倒放:简单命令行,-ss 裁剪更高效
command = [
FFMPEG_BIN,
"-y",
"-i",
str(clip.local_path),
"-vn",
"-acodec",
"aac",
"-b:a",
"128k",
"-ar",
"48000",
"-ac",
"2",
]
if trim_start > 0:
command.extend(["-ss", f"{trim_start:.3f}"])
if final_duration > 0:
command.extend(["-t", f"{final_duration:.3f}"])
command.append(str(output_path))
run_ffmpeg(command)
# 无调速无倒放:根据是否需要裁剪/音量选择最高效的路径。
vol = _clip_volume(clip)
need_trim = trim_start > 0 or (effective_duration > 0 and final_duration < adjusted_duration)
need_volume = abs(vol - 1.0) >= 1e-6
if need_trim:
# 需要裁剪:用 atrim 滤镜在滤镜链中精确裁剪(采样点级精度,不浪费解码)。
# 滤镜顺序:atrim → asetpts → volume(先裁剪再调音量,避免处理被丢弃的数据)。
af_parts: list[str] = []
if trim_start > 0 and effective_duration > 0:
af_parts.append(f"atrim=start={trim_start:.3f}:duration={final_duration:.3f}")
elif trim_start > 0:
af_parts.append(f"atrim=start={trim_start:.3f}")
elif final_duration > 0:
af_parts.append(f"atrim=duration={final_duration:.3f}")
af_parts.append("asetpts=PTS-STARTPTS")
if need_volume:
af_parts.append(f"volume={vol:.4f}")
command = [
FFMPEG_BIN,
"-y",
"-i",
str(clip.local_path),
"-vn",
"-af",
",".join(af_parts),
"-acodec",
"aac",
"-b:a",
"128k",
"-ar",
"48000",
"-ac",
"2",
]
# atrim 已精确控制时长,无需额外 -t
command.append(str(output_path))
run_ffmpeg(command)
else:
# 无需裁剪:直接提取,最高效。音量用单个 -af(如有)。
command = [
FFMPEG_BIN,
"-y",
"-i",
str(clip.local_path),
"-vn",
"-acodec",
"aac",
"-b:a",
"128k",
"-ar",
"48000",
"-ac",
"2",
]
if need_volume:
command.extend(["-af", f"volume={vol:.4f}"])
if final_duration > 0:
command.extend(["-t", f"{final_duration:.3f}"])
command.append(str(output_path))
run_ffmpeg(command)
else:
# 有调速或倒放:用 filter_complex
speed_engine = SpeedEngine()
@@ -312,6 +364,11 @@ def concat_main_audio(
if reverse_filter:
audio_filters.append(reverse_filter)
# 音量
vol = _clip_volume(clip)
if abs(vol - 1.0) >= 1e-6:
audio_filters.append(f"volume={vol:.4f}")
# aformat 归一化:统一输出格式为 48000Hz + stereo + fltp
audio_filters.append("aformat=sample_rates=48000:channel_layouts=stereo:sample_fmts=fltp")
@@ -378,6 +435,11 @@ def concat_main_audio(
if reverse_filter:
audio_filters.append(reverse_filter)
# 音量(0=静音,1=原声)
vol = _clip_volume(clip)
if abs(vol - 1.0) >= 1e-6:
audio_filters.append(f"volume={vol:.4f}")
# aformat 归一化:统一采样率48000Hz + 双声道stereo + fltp采样格式
# concat filter 要求所有输入音频参数完全一致,否则 exit=234 失败
audio_filters.append("aformat=sample_rates=48000:channel_layouts=stereo:sample_fmts=fltp")
@@ -450,6 +512,9 @@ def mix_with_independent_audio(
clip_filters.append("asetpts=PTS-STARTPTS")
else:
clip_filters.append("asetpts=PTS-STARTPTS")
vol = _clip_volume(clip)
if abs(vol - 1.0) >= 1e-6:
clip_filters.append(f"volume={vol:.4f}")
# aformat 归一化:concat/amix 前统一音频参数,否则不同采样率/声道会失败
clip_filters.append(AFORMAT)
filter_parts.append(f"[{input_idx}:a]{','.join(clip_filters)}[ma{input_idx}]")
@@ -1,7 +1,8 @@
"""视频封面抽帧工具 — 从已渲染视频中抽取帧作为封面。
"""视频封面抽帧工具 — 从视频中抽取帧作为封面,支持标题文字叠加
统一封面管道:视频渲染时标题已通过 ASS 字幕烧进视频,
渲染完成后直接从此视频抽帧,封面天然带标题,无需额外叠加逻辑
统一封面管道:
- 从已渲染视频抽帧:标题已通过 ASS 字幕烧进视频,帧天然带标题,无需再叠加
- 从源素材抽帧(API E2 兜底):源素材无标题,通过 Pillow 在帧上绘制标题文字。
"""
from __future__ import annotations
@@ -12,6 +13,40 @@ from pathlib import Path
logger = logging.getLogger(__name__)
# ── 标题叠加(Pillow)──────────────────────────────────────────────────────
# 实现统一放在 packages/shared/title_overlay.pyAPI 和 Worker 共用。
def apply_title_overlay(
image_path: str,
title_text: str,
*,
color: str = "#ffffff",
position: str = "bottom",
font_size: int | None = None,
margin_ratio: float = 0.06,
stroke_width_ratio: float = 0.04,
) -> str:
"""在图片上绘制标题文字(指定颜色 + 黑色描边/阴影)。
委托给 packages.shared.title_overlay.apply_title_to_image
保持 Worker 内调用方式不变。title_text 为空时直接返回原路径。
"""
from packages.shared.title_overlay import apply_title_to_image
if not title_text or not title_text.strip():
return image_path
result = apply_title_to_image(
image_path,
title_text,
color=color,
position=position,
font_size=font_size,
margin_ratio=margin_ratio,
stroke_width_ratio=stroke_width_ratio,
)
return result or image_path
def extract_first_frame(
video_path: str,
@@ -169,24 +204,106 @@ def generate_and_upload_thumbnail(
Path(tmp.name).unlink(missing_ok=True)
def _extract_frames_via_mediakit(
video_path: str,
plan_id: str,
num_frames: int,
) -> list[dict] | None:
"""使用 MediaKit 智能抽帧 API 提取封面帧。
Args:
video_path: 本地视频文件路径
plan_id: 编辑计划 ID
num_frames: 需要的帧数
Returns:
帧列表 [{"image_url": str, "timestamp": float}, ...],失败返回 None
"""
import uuid
from video_processing.oss_helpers import upload_to_oss
from packages.shared.mediakit_client import get_mediakit_client
client = get_mediakit_client()
if not client.is_available:
logger.info("[thumbnail] MediaKit 未配置,跳过智能抽帧")
return None
# 1. 上传视频到 OSS 获取 URL
try:
video_storage_key = f"temp/{plan_id}/{uuid.uuid4().hex[:8]}_{Path(video_path).name}"
video_url = upload_to_oss(video_path, video_storage_key)
if not video_url:
logger.warning("[thumbnail] 视频上传 OSS 失败,无法使用 MediaKit")
return None
logger.info("[thumbnail] 视频已上传 OSS: %s", video_url[:80])
except Exception as e:
logger.warning("[thumbnail] 视频上传 OSS 异常: %s,降级到 ffmpeg", e)
return None
# 2. 调用 MediaKit 智能抽帧
try:
frames = client.extract_frames(
video_url=video_url,
strategy="SceneChange",
max_frames=num_frames * 2, # 多取一些帧供选择
)
if not frames:
logger.warning("[thumbnail] MediaKit 抽帧返回空,降级到 ffmpeg")
return None
# 选取最均匀的 num_frames 个帧
if len(frames) > num_frames:
step = len(frames) // num_frames
frames = [frames[i * step] for i in range(num_frames)]
logger.info("[thumbnail] MediaKit 抽帧成功: %d", len(frames))
return frames
except Exception as e:
logger.warning("[thumbnail] MediaKit 抽帧异常: %s,降级到 ffmpeg", e)
return None
finally:
# 清理临时视频文件
try:
from video_processing.oss_helpers import delete_from_oss
delete_from_oss(video_storage_key)
except Exception:
pass
def extract_and_upload_cover_frames(
video_path: str,
plan_id: str,
*,
task_id: str = "",
num_frames: int = 3,
title_text: str = "",
title_color: str = "#ffffff",
title_position: str = "bottom",
title_font_size: int | None = None,
) -> list[dict]:
"""从视频中抽取多帧作为封面候选,上传到 OSS。
优先使用 MediaKit 智能抽帧,失败时降级到 ffmpeg 直接抽帧。
Args:
video_path: 视频文件路径
plan_id: 编辑计划 ID(用于生成 storage key
task_id: 任务 ID(用于生成独立的 storage key,避免标题变更时封面冲突)
num_frames: 抽取帧数(默认 3
title_text: 标题文字(当前版本未叠加,预留参数)
title_text: 标题文字;非空时用 Pillow 叠加到每帧。
从已渲染视频抽帧时通常传空(标题已烧录);从源素材抽帧时传标题。
title_color: 标题字体颜色(#RRGGBB
title_position: 标题位置 top/center/bottom
title_font_size: 标题字号,None 时自动计算
Returns:
封面候选列表,每项包含 {"url": str, "position": float}
"""
import httpx
from video_processing.ffmpeg_utils import probe_duration
from video_processing.oss_helpers import upload_to_oss
@@ -196,6 +313,51 @@ def extract_and_upload_cover_frames(
duration = 0.0
candidates: list[dict] = []
# 优先尝试 MediaKit 智能抽帧
mediakit_frames = _extract_frames_via_mediakit(video_path, plan_id, num_frames)
if mediakit_frames:
for i, frame in enumerate(mediakit_frames):
frame_url = frame.get("image_url")
if not frame_url:
continue
tmp = tempfile.NamedTemporaryFile(suffix=".jpg", delete=False)
tmp.close()
try:
# 下载 MediaKit 返回的帧图
resp = httpx.get(frame_url, timeout=30, follow_redirects=True)
resp.raise_for_status()
with open(tmp.name, "wb") as f:
f.write(resp.content)
# 叠加标题文字(如需要)
if title_text and title_text.strip():
apply_title_overlay(
tmp.name,
title_text,
color=title_color,
position=title_position,
font_size=title_font_size,
)
storage_key = f"covers/{plan_id}/{task_id}/mediakit_frame_{i}.jpg"
url = upload_to_oss(tmp.name, storage_key)
if url:
seek_time = frame.get("timestamp", 0.0)
candidates.append({"url": url, "position": round(seek_time, 2)})
except Exception as e:
logger.warning("[thumbnail] MediaKit 帧 %d 处理失败: %s", i, e)
finally:
Path(tmp.name).unlink(missing_ok=True)
if len(candidates) >= num_frames:
logger.info("[thumbnail] MediaKit 智能抽帧完成: %d", len(candidates))
return candidates[:num_frames]
logger.warning("[thumbnail] MediaKit 抽帧不足 %d 帧,降级到 ffmpeg", num_frames)
# Fallback: ffmpeg 直接抽帧
logger.info("[thumbnail] 使用 ffmpeg 抽帧")
# 均匀分布抽帧点:从 10% 到 90%
for i in range(num_frames):
ratio = 0.1 + 0.8 * i / max(num_frames - 1, 1)
@@ -208,7 +370,16 @@ def extract_and_upload_cover_frames(
seek_ratio=ratio,
min_seek_seconds=0.5,
)
storage_key = f"covers/{plan_id}/frame_{i}.jpg"
# 从源素材抽帧时叠加标题文字;已渲染视频标题已烧录时传空字符串跳过
if title_text and title_text.strip():
apply_title_overlay(
frame_path,
title_text,
color=title_color,
position=title_position,
font_size=title_font_size,
)
storage_key = f"covers/{plan_id}/{task_id}/frame_{i}.jpg"
url = upload_to_oss(frame_path, storage_key)
if url:
seek_time = max(0.5, duration * ratio) if duration > 0 else 0.0
@@ -36,6 +36,7 @@ from video_processing.ffmpeg_utils import (
DEFAULT_TRANSITION_DURATION,
FFMPEG_BIN,
probe_duration,
probe_has_audio,
probe_video_info,
run_ffmpeg,
)
@@ -823,6 +824,17 @@ class UnifiedRenderService:
)
audio_layer.clips.append(vo_clip)
# replace 模式:静音原视频音轨(main + broll 图层)
if tts_config.overlap_mode == "replace":
for layer in layers:
if layer.role in ("main", "broll"):
for clip in layer.clips:
clip.config["volume"] = 0
logger.info(
"TTS replace 模式:已静音原视频音轨: plan_id=%s",
self.plan.id,
)
logger.info(
"TTS 配音已添加: plan_id=%s voice_id=%s segments=%d total_%.2fs",
self.plan.id,
@@ -888,6 +900,16 @@ class UnifiedRenderService:
)
audio_layer.clips.append(vo_clip)
# 配音素材库默认替换原音:静音原视频音轨(main + broll 图层)
for layer in layers:
if layer.role in ("main", "broll"):
for clip in layer.clips:
clip.config["volume"] = 0
logger.info(
"配音素材库:已静音原视频音轨: plan_id=%s",
self.plan.id,
)
logger.info(
"配音素材库音频已添加到 audio 图层: plan_id=%s duration=%.2fs",
self.plan.id,
@@ -1000,6 +1022,11 @@ class UnifiedRenderService:
if abs(speed - 1.0) >= 1e-6:
return False, f"有调速: speed={speed:.2f}x"
# 音量非默认(静音/放大)→ 需要音频滤镜重编码 → 不能 copy
vol = UnifiedRenderService._clip_volume(clip)
if abs(vol - 1.0) >= 1e-6:
return False, f"音量非默认: volume={vol:.2f}"
# 有倒放 → 需要重编码 → 不能 copy
reverse_config = ReverseConfig.from_dict(clip.config.get("reverse"))
if reverse_config.enabled and (reverse_config.reverse_video or reverse_config.reverse_audio):
@@ -1270,13 +1297,23 @@ class UnifiedRenderService:
"+faststart",
]
# 音频处理:background 通常是图片无音频,跳过;其他编码为 aac
# background 以外的视频素材,默认带音频
has_audio = role != "background"
# 音频处理:background 通常是图片无音频,跳过;其他角色先探测是否真有音频流。
# volume=0 不丢弃音频流,而是保留后通过 volume=0 滤镜静音,保持时间轴对齐。
clip_volume = UnifiedRenderService._clip_volume(clip)
if role != "background":
try:
has_audio = probe_has_audio(clip.local_path)
except Exception as e:
# probe_has_audio 内部已保守返回 True;只有极端错误才会到这里。
# 此时不静默丢音频,记录 error 并向上抛出,让任务失败而不是产出无声视频。
logger.error("[unified-render] 探测音频流发生致命错误,终止渲染: %s: %s", clip.local_path, e)
raise
else:
has_audio = False
if has_audio:
af_parts: list[str] = []
# 音频降噪
# 音频降噪(最先处理:在原始信号上降噪效果最好)
try:
from video_processing.noise_reduction_engine import NoiseReductionConfig, NoiseReductionEngine
@@ -1290,13 +1327,16 @@ class UnifiedRenderService:
except Exception as e:
logger.warning("[unified-render] 直通模式音频降噪应用失败,跳过: %s", e)
# 音频调速(与视频setpts对应,保持音画同步
# 音频调速(在降噪之后、音量之前,与 render_audio.py concat 路径保持一致
# SpeedEngine.build_audio_filter 内部已实现多级 atempo 串联,
# 自动处理超出 [0.5, 2.0] 范围的速度(如 0.25x → atempo=0.5,atempo=0.5)。
speed = UnifiedRenderService._clip_speed(clip)
if abs(speed - 1.0) >= 1e-6:
try:
from video_processing.speed_engine import SpeedConfig, SpeedEngine
speed_cfg = SpeedConfig(speed=speed)
speed_cfg.clamp()
speed_engine = SpeedEngine()
af_parts.append(speed_engine.build_audio_filter(speed_cfg))
except Exception as e:
@@ -1309,6 +1349,10 @@ class UnifiedRenderService:
if af_filter:
af_parts.append(af_filter)
# 片段音量(最后应用:确保调速/倒放后的最终输出音量准确,与 concat 路径一致)
if abs(clip_volume - 1.0) >= 1e-6:
af_parts.append(f"volume={clip_volume:.4f}")
if af_parts:
command.extend(["-af", ",".join(af_parts)])
@@ -1976,6 +2020,16 @@ class UnifiedRenderService:
"""
return _clip_playback_speed_pure(getattr(clip, "playback_speed", 1.0))
@staticmethod
def _clip_volume(clip: ResolvedClip) -> float:
"""获取 clip 的音量(config.volume)。缺省 1.0 原声,0.0 静音。"""
cfg = getattr(clip, "config", None) or {}
try:
vol = float(cfg.get("volume", 1.0))
except (TypeError, ValueError):
return 1.0
return max(0.0, vol)
@staticmethod
def _clip_adjusted_duration(clip: ResolvedClip) -> float:
"""计算调速后的 clip 实际时长(用于拼接计算)。
+10 -2
View File
@@ -14,9 +14,17 @@ celery_app.conf.imports = (
"worker_app.tasks.voice_extraction",
"worker_app.tasks.voice_clone",
"worker_app.tasks.tts_synthesis",
"worker_app.tasks.edit_plan_generation",
"worker_app.tasks.compose_video",
"worker_app.tasks.batch_download",
"worker_app.tasks._startup",
"apps.worker.video_processing.dedup",
"worker_app.tasks.cleanup",
)
# Celery Beat 定时任务调度
celery_app.conf.beat_schedule = {
"cleanup-stale-pending-tasks": {
"task": "worker.cleanup_stale_pending_tasks",
"schedule": 600.0, # 每 10 分钟(秒)
"options": {"expires": 300}, # 5 分钟过期,避免堆积
},
}
-5
View File
@@ -25,10 +25,6 @@ def __getattr__(name: str):
from .voice_extraction import extract_voice_task
return extract_voice_task
elif name == "compose_video":
from .compose_video import compose_video
return compose_video
elif name == "extract_background_task":
from .voice_extraction import extract_background_task
@@ -58,7 +54,6 @@ def __getattr__(name: str):
__all__ = [
"classify_asset",
"compose_video",
"generate_video",
"healthcheck",
"ingest_asset",
+40 -3
View File
@@ -10,6 +10,9 @@ logger = logging.getLogger(__name__)
# 孤儿任务超时阈值:渲染任务超过此时间未更新则视为卡死
ORPHAN_TASK_TIMEOUT_MINUTES = 10
# Pending 任务超时阈值:pending 任务在队列中等待超过此时间则自动清理
PENDING_TASK_TIMEOUT_MINUTES = 30
def cleanup_orphan_tasks(timeout_minutes: int = ORPHAN_TASK_TIMEOUT_MINUTES) -> int: # pragma: no cover
"""清理数据库中超时未更新的 running GenerationTask(孤儿任务)。
@@ -83,6 +86,38 @@ def cleanup_stale_jobs(timeout_minutes: int = ORPHAN_TASK_TIMEOUT_MINUTES) -> in
return 0
def cleanup_stale_pending_tasks(timeout_minutes: int = PENDING_TASK_TIMEOUT_MINUTES) -> int: # pragma: no cover
"""清理数据库中卡在 pending 状态超时的 GenerationTask。
全局任务队列有 pending 数量上限,长期卡在 pending 的任务会占满队列,
导致新用户无法创建任务。通过 created_at 超时判断并标记为 failed。
Args:
timeout_minutes: 超时时间(分钟),默认 PENDING_TASK_TIMEOUT_MINUTES
Returns:
清理的任务数量
"""
from packages.adapters.sqlalchemy_impl.generation_task_repository import (
SQLAlchemyGenerationTaskRepository,
)
session = SessionLocal()
try:
repo = SQLAlchemyGenerationTaskRepository(session)
count = repo.cleanup_stale_pending(timeout_minutes)
if count > 0:
logger.warning("清理了 %d 个超时的 pending GenerationTask(超过 %d 分钟未处理)", count, timeout_minutes)
else:
logger.info("无超时 pending GenerationTask 需要清理")
return count
except Exception as e:
logger.error("清理超时 pending GenerationTask 失败: %s", e, exc_info=True)
return 0
finally:
session.close()
def cleanup_all_stale_tasks(timeout_minutes: int = ORPHAN_TASK_TIMEOUT_MINUTES) -> dict: # pragma: no cover
"""统一清理所有超时的孤儿任务。
@@ -93,15 +128,17 @@ def cleanup_all_stale_tasks(timeout_minutes: int = ORPHAN_TASK_TIMEOUT_MINUTES)
"""
gen_count = cleanup_orphan_tasks(timeout_minutes)
job_count = cleanup_stale_jobs(timeout_minutes)
total = gen_count + job_count
pending_count = cleanup_stale_pending_tasks(PENDING_TASK_TIMEOUT_MINUTES)
total = gen_count + job_count + pending_count
if total > 0:
logger.warning(
"孤儿任务清理完成: GenerationTask=%d, Job=%d, 总计=%d",
"任务清理完成: 孤儿 GenerationTask=%d, 孤儿 Job=%d, 超时 pending=%d, 总计=%d",
gen_count,
job_count,
pending_count,
total,
)
return {"generation_tasks": gen_count, "jobs": job_count}
return {"generation_tasks": gen_count, "jobs": job_count, "pending": pending_count}
@worker_ready.connect
+35
View File
@@ -0,0 +1,35 @@
"""定期清理任务 — Celery Beat 调度。
包含:
- cleanup_stale_pending_tasks: 定期清理卡在 pending 超时的 generation_tasks
"""
import logging
from celery import shared_task
from worker_app.tasks._startup import (
PENDING_TASK_TIMEOUT_MINUTES,
cleanup_stale_pending_tasks,
)
logger = logging.getLogger(__name__)
@shared_task(name="worker.cleanup_stale_pending_tasks")
def scheduled_cleanup_stale_pending(timeout_minutes: int = PENDING_TASK_TIMEOUT_MINUTES) -> dict:
"""Celery Beat 调度的定期任务:清理超时的 pending 任务。
每 10 分钟执行一次(由 celery_app.py 的 beat_schedule 配置),
查找所有 status='pending' 且 created_at < NOW() - timeout_minutes
的 generation_tasks,批量更新为 failed。
Args:
timeout_minutes: 超时时间(分钟),默认 30 分钟
Returns:
{"cleaned": int}
"""
count = cleanup_stale_pending_tasks(timeout_minutes)
if count > 0:
logger.info("[Beat] 清理了 %d 个超时 pending 任务(超时阈值 %d 分钟)", count, timeout_minutes)
return {"cleaned": count}
@@ -1,198 +0,0 @@
"""视频合成 Celery 任务 — Phase 8 任务 2.10.
使用 JobService 管理任务生命周期,通过 RenderAdapter 调用 UnifiedRenderService 执行合成。
"""
from __future__ import annotations
import os
import subprocess # pragma: no cover
import tempfile
from pathlib import Path
from celery.exceptions import SoftTimeLimitExceeded # pragma: no cover
from celery.utils.log import get_task_logger
from worker_app.celery_app import celery_app
from worker_app.db import SessionLocal
logger = get_task_logger(__name__)
# 任务超时时间(秒):超过此时间 Celery 会抛出 SoftTimeLimitExceeded
RENDER_TASK_SOFT_TIME_LIMIT = 600 # pragma: no cover # 10 分钟
# 硬超时:超过此时间进程会被强制 kill
RENDER_TASK_TIME_LIMIT = 660 # pragma: no cover # 10 分钟 + 1 分钟清理缓冲
def _get_job_service():
"""延迟导入 JobService,避免循环依赖。"""
from apps.api.app.services.job_service import JobService
from packages.adapters.sqlalchemy_impl.job_repository import SQLAlchemyJobRepository
db = SessionLocal()
repo = SQLAlchemyJobRepository(db)
return JobService(repo), db
@celery_app.task(
name="worker.compose_video",
bind=True,
max_retries=3,
default_retry_delay=60,
soft_time_limit=RENDER_TASK_SOFT_TIME_LIMIT,
time_limit=RENDER_TASK_TIME_LIMIT,
)
def compose_video(self, job_id: str, **kwargs): # pragma: no cover
"""视频合成任务。
使用 UnifiedRenderService(图层架构)进行渲染。
Args:
job_id: JobService 中的任务 ID
**kwargs: 来自 Job.payload 的额外参数(plan_id, output_path 等)
"""
job_service, db = _get_job_service()
try:
job = job_service.get_job(job_id)
if job is None:
logger.error("Job not found: %s", job_id)
return {"status": "error", "message": f"Job {job_id} not found"}
plan_id = job.payload.get("plan_id", "")
if not plan_id:
job_service.fail_job(job_id, "Missing plan_id in job payload")
return {"status": "error", "message": "Missing plan_id"}
# 使用 unified 渲染引擎
return _compose_with_unified_engine(self, job_service, job, plan_id, db)
except SoftTimeLimitExceeded:
# Celery 软超时:任务执行超过 soft_time_limit
error_msg = f"渲染任务超时(超过 {RENDER_TASK_SOFT_TIME_LIMIT // 60} 分钟)"
logger.error("视频合成超时: job_id=%s", job_id)
try:
job_service.fail_job(job_id, error_msg)
except Exception:
logger.exception("更新 Job 超时失败状态时出错")
# 超时不重试
return {"status": "error", "message": error_msg, "error_type": "timeout"}
except subprocess.TimeoutExpired as exc:
# FFmpeg 子进程超时
error_msg = f"FFmpeg 渲染超时({exc.timeout}s"
logger.error("视频合成 FFmpeg 超时: job_id=%s timeout=%s", job_id, exc.timeout)
try:
job_service.fail_job(job_id, error_msg)
except Exception:
logger.exception("更新 Job 超时失败状态时出错")
# 超时不重试
return {"status": "error", "message": error_msg, "error_type": "ffmpeg_timeout"}
except self.retry_exc as exc:
logger.warning("视频合成重试中: job_id=%s, exc=%s", job_id, exc)
raise
except subprocess.CalledProcessError as exc:
# FFmpeg 执行失败,提取有意义的错误信息
from video_processing.video_validation import get_exit_code_message
exit_msg = get_exit_code_message(exc.returncode)
stderr_text = (exc.stderr or "").strip()
stderr_tail = stderr_text[-300:] if len(stderr_text) > 300 else stderr_text
error_msg = f"渲染失败: {exit_msg}"
if stderr_tail:
error_msg += f" | {stderr_tail[:200]}"
logger.error("视频合成 FFmpeg 失败: job_id=%s %s", job_id, exit_msg)
try:
job_service.fail_job(job_id, error_msg[:500])
except Exception:
logger.exception("更新 Job 失败状态时出错")
# FFmpeg 错误不重试(通常是素材或配置问题)
return {"status": "error", "message": error_msg, "error_type": "ffmpeg_error", "exit_code": exc.returncode}
except Exception as exc:
logger.exception("视频合成异常: job_id=%s", job_id)
try:
job_service.fail_job(job_id, str(exc)[:500])
except Exception:
logger.exception("更新 Job 失败状态时出错")
raise self.retry(exc=exc, countdown=60) from exc
finally:
db.close()
def _compose_with_unified_engine(task, job_service, job, plan_id: str, db) -> dict: # pragma: no cover
"""新引擎渲染路径(UnifiedRenderService + RenderAdapter)。"""
job_id = job.id
# 标记为 running
job_service.update_progress(job_id, progress=10.0, current_stage="初始化统一渲染引擎")
from video_processing.render_adapter import RenderAdapter
adapter = RenderAdapter(db)
# 校验合成条件
job_service.update_progress(job_id, progress=15.0, current_stage="校验合成条件")
valid, errors, warnings, ready_count, total_count = adapter.validate_plan(plan_id)
if not valid:
error_msg = "; ".join(errors)
job_service.fail_job(job_id, f"合成校验失败: {error_msg}")
return {"status": "error", "message": error_msg}
# 进度回调
def progress_cb(progress: float, stage: str) -> None:
try:
job_service.update_progress(job_id, progress=progress, current_stage=stage)
except Exception:
logger.exception("更新进度失败")
# 执行渲染
job_service.update_progress(job_id, progress=20.0, current_stage="开始渲染")
logger.info("统一渲染引擎开始: job_id=%s plan_id=%s", job_id, plan_id)
result = adapter.render_plan(
plan_id=plan_id,
job_id=job_id,
progress_cb=progress_cb,
)
if not result.success:
error_msg = f"渲染失败: {result.error_message}"
job_service.fail_job(job_id, error_msg[:500])
raise RuntimeError(result.error_message)
# 更新 Job 状态为完成
result_data = {
"plan_id": plan_id,
"output_path": str(result.output_path) if result.output_path else "",
"storage_key": f"rendered/{plan_id}/{job_id}.mp4",
"output_url": result.output_url,
"estimated_duration": result.duration,
"clip_count": result.clip_count,
"engine": "unified",
"width": result.width,
"height": result.height,
"file_size": result.file_size,
}
job_service.complete_job(job_id, result=result_data)
logger.info(
"视频合成完成(unified): job_id=%s plan_id=%s duration=%.2fs",
job_id,
plan_id,
result.duration,
)
return {"status": "completed", "job_id": job_id, "result": result_data}
def _cleanup_output(job_id: str) -> None:
"""清理临时输出文件。"""
try:
_output_dir = os.environ.get("VIDEO_OUTPUT_DIR", os.path.join(tempfile.gettempdir(), "video_output"))
output_path = os.path.join(_output_dir, f"{job_id}.mp4")
if Path(output_path).exists():
Path(output_path).unlink()
except Exception as e:
logger.warning(f"清理输出文件失败: {e}", exc_info=True)
@@ -1,452 +0,0 @@
"""剪辑计划渲染任务 — 使用 UnifiedRenderService 统一渲染引擎.
Celery 任务 worker.render_edit_plan:
1. 加载 EditPlan + EditPlanClips
2. 通过 RenderAdapter 调用 UnifiedRenderService 渲染
3. 下载各片段素材 + 渲染
4. 上传渲染结果到 OSS
5. 创建 GeneratedVideo 记录 + 查重
6. 更新 EditPlan / EditPlanClip 状态
7. 更新 GenerationTask 进度
"""
from __future__ import annotations
import logging
from datetime import datetime, timezone
from pathlib import Path
from worker_app.celery_app import celery_app
from worker_app.db import SessionLocal
logger = logging.getLogger(__name__)
OUTPUT_WIDTH = 1280
OUTPUT_HEIGHT = 720
OUTPUT_FPS = 25.0
# ── 共享工具模块导入 ──────────────────────────────────────────────────────────
from video_processing.dedup_helpers import create_video_record_and_dedup
# ── Repository imports (延迟导入避免循环依赖) ─────────────────────────────────
def _get_repos():
"""获取数据库仓储实例"""
from packages.adapters.sqlalchemy_impl import SQLAlchemyEditPlanRepository
from packages.adapters.sqlalchemy_impl.edit_plan_clip_repository import (
SQLAlchemyEditPlanClipRepository,
)
from packages.adapters.sqlalchemy_impl.generation_task_repository import (
SQLAlchemyGenerationTaskRepository,
)
db = SessionLocal()
try:
plan_repo = SQLAlchemyEditPlanRepository(db)
clip_repo = SQLAlchemyEditPlanClipRepository(db)
gen_task_repo = SQLAlchemyGenerationTaskRepository(db)
yield plan_repo, clip_repo, gen_task_repo, db
finally:
db.close()
# ── Celery Task ───────────────────────────────────────────────────────────────
def _mark_plan_failed(plan_repo, plan_id, gen_task_repo, generation_task_id, error_msg: str):
"""统一的计划失败标记工具。"""
plan = plan_repo.get(plan_id)
if plan and plan.status.value == "rendering":
plan.mark_failed()
plan_repo.update(plan)
if generation_task_id:
gen_task = gen_task_repo.get(generation_task_id)
if gen_task and gen_task.status.value != "failed":
gen_task.status = "failed"
gen_task.error_message = error_msg
gen_task.completed_at = datetime.now(timezone.utc)
try:
gen_task.append_log(
stage="render_failed",
message=error_msg[:500],
level="ERROR",
)
except Exception:
pass
gen_task_repo.update(gen_task)
def _finalize_render_success(
plan,
plan_repo,
clip_repo,
gen_task_repo,
db,
plan_id: str,
output_url: str,
storage_key: str,
duration: float,
file_size: int,
width: int,
height: int,
rendered_clip_ids: list[str],
failed_clip_ids: list[str],
generation_task_id: str,
output_path: Path,
engine: str,
thumbnail_url: str = "",
cover_candidates: list[dict] | None = None,
) -> dict:
"""渲染成功后的统一收尾:查重 + 更新状态 + 返回结果。"""
# 创建 GeneratedVideo 记录 + 查重
project_id = plan.project_id or ""
batch_id = plan.config.get("batch_id", "")
mode = plan.config.get("mode", "edit_plan")
# 从 plan.config.title.text 读取视频名称
plan_config = plan.config or {}
title_cfg = plan_config.get("title", {}) or {}
if not isinstance(title_cfg, dict):
title_cfg = {}
video_name = (title_cfg.get("text") or "").strip() or f"generated-{generation_task_id[:8]}.mp4"
if generation_task_id:
try:
create_video_record_and_dedup(
generation_task_id=generation_task_id,
project_id=project_id,
user_id=plan.created_by_user_id or "",
batch_id=batch_id,
file_url=output_url or "",
file_size=file_size,
duration=duration,
video_path=str(output_path),
mode=mode,
session=db,
width=width,
height=height,
fps=OUTPUT_FPS,
name=video_name,
thumbnail_url=thumbnail_url,
)
except Exception as dedup_err:
logger.warning("查重失败(不影响渲染结果): %s", dedup_err)
# 更新片段状态为 rendered
for clip_id in rendered_clip_ids:
clip = clip_repo.get(clip_id)
if clip and clip.status.value == "ready":
clip.mark_rendered()
clip_repo.update(clip)
# 更新 EditPlan 状态为 completed + 回写实际渲染时长 + 结果数
plan.config["rendered_url"] = output_url or ""
plan.config["rendered_storage_key"] = storage_key
if hasattr(plan, "total_duration") and duration > 0:
plan.total_duration = duration
plan.mark_completed()
plan_repo.update(plan)
# 更新 GenerationTask 状态为 completed
if generation_task_id:
gen_task = gen_task_repo.get(generation_task_id)
if gen_task:
gen_task.status = "completed"
gen_task.progress = 100.0
# 剪辑计划是多片段合成 1 个成片,result_count = 1
gen_task.result_count = 1
gen_task.append_log(
stage="render_complete",
message=f"渲染完成,输出时长 {duration:.1f}s",
level="INFO",
engine=engine,
clip_count=len(rendered_clip_ids),
)
gen_task.completed_at = datetime.now(timezone.utc)
# 回写封面 URL 到 GenerationTask,供封面生成接口读取
if cover_candidates:
first_cover = cover_candidates[0].get("image_url") or cover_candidates[0].get("url") or ""
if first_cover:
gen_task.cover_url = first_cover
logger.info(
"预览渲染完成,回写 cover_url: plan_id=%s task_id=%s url=%s",
plan_id,
generation_task_id,
first_cover[:80],
)
gen_task_repo.update(gen_task)
logger.info(
"剪辑计划渲染完成: plan_id=%s engine=%s rendered=%d failed=%d duration=%.1fs",
plan_id,
engine,
len(rendered_clip_ids),
len(failed_clip_ids),
duration,
)
return {
"status": "completed",
"plan_id": plan_id,
"rendered_count": len(rendered_clip_ids),
"failed_count": len(failed_clip_ids),
"output_url": output_url,
"duration": duration,
}
def _render_with_unified(
plan,
clips,
plan_id: str,
generation_task_id: str,
plan_repo,
clip_repo,
gen_task_repo,
db,
) -> dict:
"""统一渲染引擎路径(通过 RenderAdapter 调用 UnifiedRenderService)。
RenderAdapter 内部处理:素材下载、BGM 准备、ASR 自动字幕、渲染执行、OSS 上传。
本函数只负责:业务状态更新、查重、收尾。
"""
from video_processing.render_adapter import RenderAdapter
adapter = RenderAdapter(db)
# 进度回调:更新 GenerationTask 进度
def _progress_cb(progress: float, stage: str):
if not generation_task_id:
return
try:
gen_task = gen_task_repo.get(generation_task_id)
if gen_task:
# 映射到 30%~90% 区间(素材下载前已到 30%)
mapped_progress = 30.0 + progress * 0.6
gen_task.progress = min(mapped_progress, 95.0)
gen_task.append_log(
stage="render_progress",
message=stage,
level="INFO",
progress=mapped_progress,
)
gen_task_repo.update(gen_task)
except Exception:
pass
try:
result = adapter.render_plan(
plan_id=plan_id,
job_id=generation_task_id or plan_id,
progress_cb=_progress_cb,
)
except Exception as render_err:
logger.error("渲染失败(unified): %s%s", plan_id, render_err)
_mark_plan_failed(plan_repo, plan_id, gen_task_repo, generation_task_id, f"渲染失败: {render_err}")
return {"status": "error", "message": f"渲染失败: {render_err}"}
if not result.success:
full_error = result.error_message or "渲染失败"
if result.error_detail:
full_error = f"{full_error}\n--- stderr ---\n{result.error_detail}"
logger.error("渲染失败(unified): %s%s", plan_id, result.error_message)
_mark_plan_failed(plan_repo, plan_id, gen_task_repo, generation_task_id, full_error)
return {"status": "error", "message": result.error_message or "渲染失败"}
output_path = result.output_path or Path("")
output_url = result.output_url or ""
thumbnail_url = result.thumbnail_url or ""
# adapter 上传到 rendered/{plan_id}/{job_id}.mp4,从 URL 提取实际 key
# 不能用 output.mp4 硬编码,否则 cover 等下游通过 key 构造的 URL 指向不存在的文件
if output_url:
from packages.shared.storage import get_shared_storage_service
storage_key = get_shared_storage_service().normalize_storage_key(output_url)
else:
storage_key = f"rendered/{plan_id}/{generation_task_id or plan_id}.mp4"
# 用 adapter 返回的 clip 明细(以 adapter 的结果为准)
rendered_clip_ids = result.rendered_clip_ids or []
failed_clip_ids = result.failed_clip_ids or []
# 将封面候选帧写入 plan.config(供封面 API 直接使用,跳过 MediaKit 抽帧)
if result.cover_candidates:
plan_config = plan.config or {}
plan_config["cover_candidates"] = result.cover_candidates
plan.config = plan_config
logger.info(
"封面候选帧已写入 plan.config: plan_id=%s count=%d",
plan_id,
len(result.cover_candidates),
)
return _finalize_render_success(
plan=plan,
plan_repo=plan_repo,
clip_repo=clip_repo,
gen_task_repo=gen_task_repo,
db=db,
plan_id=plan_id,
output_url=output_url or "",
storage_key=storage_key,
duration=result.duration,
file_size=result.file_size,
width=result.width,
height=result.height,
rendered_clip_ids=rendered_clip_ids,
failed_clip_ids=failed_clip_ids,
generation_task_id=generation_task_id,
output_path=output_path,
engine="unified",
thumbnail_url=thumbnail_url,
cover_candidates=result.cover_candidates,
)
@celery_app.task(
name="worker.render_edit_plan",
bind=True,
max_retries=2,
soft_time_limit=600, # 10 分钟软超时
time_limit=660, # 11 分钟硬超时
)
def render_edit_plan(self, plan_id: str) -> dict: # pragma: no cover
"""渲染剪辑计划
流程:
1. 加载 EditPlan + EditPlanClips
2. 通过 RenderAdapter 调用 UnifiedRenderService 渲染
3. 下载素材 + 渲染
4. 上传渲染结果到 OSS
5. 创建 GeneratedVideo 记录 + 查重
6. 更新 EditPlan → completed, EditPlanClips → rendered
7. 更新 GenerationTask 进度
"""
logger.info("开始渲染剪辑计划: plan_id=%s", plan_id)
generation_task_id = ""
for repos in _get_repos():
plan_repo, clip_repo, gen_task_repo, db = repos
try:
# 1. 加载 EditPlan
plan = plan_repo.get(plan_id)
if plan is None:
logger.error("剪辑计划不存在: %s", plan_id)
return {"status": "error", "message": f"计划不存在: {plan_id}"}
# 获取 generation_task_id(提前读取,确保 except 块可用)
generation_task_id = plan.config.get("generation_task_id", "")
# 2. 准备渲染(使用 unified 渲染引擎)
# 3. 加载片段列表(按 order 排序)
clips = clip_repo.list_by_plan(plan_id, skip=0, limit=10000)
if not clips:
logger.warning("剪辑计划没有片段: %s", plan_id)
plan.mark_failed()
plan_repo.update(plan)
return {"status": "error", "message": "没有可渲染的片段"}
# 更新 GenerationTask 状态为 running
if generation_task_id:
gen_task = gen_task_repo.get(generation_task_id)
if gen_task:
gen_task.status = "running"
gen_task.started_at = datetime.now(timezone.utc)
gen_task.append_log(
stage="render_start",
message=f"开始渲染,片段数 {len(clips)}",
level="INFO",
engine="unified",
clip_count=len(clips),
)
gen_task_repo.update(gen_task)
# 3. 渲染前取消检查
if generation_task_id:
current_task = gen_task_repo.get(generation_task_id)
if current_task:
task_status = (
current_task.status.value if hasattr(current_task.status, "value") else str(current_task.status)
)
if task_status == "cancelled":
logger.info("任务已被取消,中止渲染: plan_id=%s task_id=%s", plan_id, generation_task_id)
if plan.status.value == "rendering":
try:
plan.resume_editing()
plan_repo.update(plan)
except ValueError:
pass
return {"status": "cancelled", "plan_id": plan_id, "message": "任务已取消"}
# 4. 渲染(unified 引擎:RenderAdapter 统一处理下载 + BGM + ASR + 渲染 + 上传)
result = _render_with_unified(
plan=plan,
clips=clips,
plan_id=plan_id,
generation_task_id=generation_task_id,
plan_repo=plan_repo,
clip_repo=clip_repo,
gen_task_repo=gen_task_repo,
db=db,
)
result["engine"] = "unified"
return result
except Exception as exc:
# 超时异常不重试,直接标记失败
from celery.exceptions import SoftTimeLimitExceeded
is_timeout = isinstance(exc, SoftTimeLimitExceeded)
if is_timeout:
logger.error("渲染剪辑计划超时: plan_id=%s", plan_id)
else:
logger.exception("渲染剪辑计划异常: %s", plan_id)
# 尝试标记计划和 GenerationTask 为失败
error_msg = "渲染任务超时(超过10分钟)" if is_timeout else f"渲染异常: {type(exc).__name__}: {exc}"
try:
plan = plan_repo.get(plan_id)
if plan and plan.status.value == "rendering":
plan.mark_failed()
plan_repo.update(plan)
except Exception as e:
logger.warning("标记计划失败时异常: plan_id=%s error=%s", plan_id, e, exc_info=True)
# 更新 GenerationTask 状态为 failed,前端轮询能看到失败状态
try:
if generation_task_id:
gen_task = gen_task_repo.get(generation_task_id)
if gen_task and gen_task.status.value != "failed":
gen_task.status = "failed"
gen_task.error_message = error_msg
gen_task.completed_at = datetime.now(timezone.utc)
try:
log_stage = "render_timeout" if is_timeout else "render_failed"
gen_task.append_log(
stage=log_stage,
message=error_msg[:500],
level="ERROR",
exception_type=type(exc).__name__,
)
except Exception:
pass
gen_task_repo.update(gen_task)
logger.info(
"GenerationTask 已标记为 failed: task_id=%s plan_id=%s",
generation_task_id,
plan_id,
)
except Exception as e:
logger.warning(
"更新 GenerationTask 失败状态时异常: task_id=%s error=%s", generation_task_id, e, exc_info=True
)
raise self.retry(exc=exc, countdown=60) from exc
return {"status": "error", "message": "数据库连接失败"}
File diff suppressed because it is too large Load Diff
+19875
View File
File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More