8.3 KiB
8.3 KiB
🔧 鉴权到期治理 + 多素材时间轴稳定性修复 (Day 24)
概述
本日主要完成两条主线:
- 账号与鉴权治理:会员到期改为请求时自动失效(登录/鉴权接口触发),并统一返回续费提示。
- 视频生成稳定性:围绕多素材时间轴、截取语义、拼接边界冻结、画面比例与字幕标题适配进行一轮端到端修复。
🔐 会员到期请求时失效 — 第一阶段 (Day 24)
目标
避免依赖定时任务,用户在触发登录或访问受保护接口时即可完成到期判定与账号停用。
行为调整
- 到期判断基于
users.expires_at。 - 判定到期后:
- 将
is_active自动置为false - 删除该用户全部 session
- 返回
403,提示:会员已到期,请续费
- 将
实现点
users.py新增deactivate_user_if_expired(),并补充_parse_expires_at()统一时区解析。deps.py在get_current_user/get_current_user_optional中统一接入到期检查。auth/router.py在登录路径增加到期停用逻辑;/api/auth/me统一走Depends(get_current_user)。
🖼️ 画面比例控制 + 字幕标题适配 — 第二阶段 (Day 24)
2.1 输出画面比例可配置
- 时间轴顶部新增“画面比例”下拉:
9:16/16:9。 - 默认值
9:16,并持久化到 localStorage。 - 生成请求携带
output_aspect_ratio,后端在单素材与多素材流程中统一按目标分辨率处理。
2.2 标题/字幕在窄屏画布防溢出
为减少“预览正常、成片溢出”的差异,统一了预览与渲染策略:
- 根据 composition 宽度进行响应式缩放。
- 开启可换行:
white-space: normal+word-break+overflow-wrap。 - 描边、字距、上下边距同步按比例缩放。
2.3 片头标题显示模式(短暂/常驻)
- 在“标题与字幕”面板的“片头标题”行尾新增下拉,支持:
短暂显示/常驻显示。 - 默认模式为
短暂显示,短暂模式默认时长为 4 秒。 - 用户选择会持久化到 localStorage,刷新后保持上次配置。
- 生成请求新增
title_display_mode,短暂模式透传title_duration=4.0。 - Remotion 端到端支持该参数:
short:标题在设定时长后淡出并结束渲染;persistent:标题全程常驻(保留淡入动画,不执行淡出)。
🎥 方向归一化 + 多素材拼接稳定性 — 第三阶段 (Day 24)
3.1 MOV 旋转元数据导致横竖识别错误
问题场景:编码分辨率是横屏,但依赖 rotation side-data 才能正确显示为竖屏(常见于手机 MOV)。
修复方案:
get_video_metadata()扩展返回rotation/effective_width/effective_height。- 新增
normalize_orientation(),在流程前对带旋转元数据素材做物理方向归一化。 - 单素材和多素材下载后统一执行方向归一化,再做分辨率决策。
3.2 多素材“只看到第一段”与边界冻结
针对拼接可靠性补了两类保护:
- 分配保护:
custom_assignments与素材数量不一致时,后端回退自动分配,避免异常输入导致仅首段生效。 - 编码一致性:
- 片段准备阶段统一重编码;
- concat 阶段不再走拷贝;
- 进一步统一为
25fps + CFR,并在 concat 增加+genpts,降低段边界时间基不连续导致的“画面冻结口型还动”风险。
⏱️ 时间轴截取语义对齐修复 — 第四阶段 (Day 24)
背景
时间轴设计语义是:
- 每段可以设置
sourceStart/sourceEnd; - 总时长超出音频时,仅保留可见段,末段截齐音频;
- 总时长不足时,由最后可见段循环补齐。
本日将前后端对齐到这一语义。
4.1 source_end 全链路打通
此前仅传 source_start,导致后端无法准确知道“截到哪里”。
本次改动:
- 前端
toCustomAssignments()增加可选source_end。 - 后端
CustomAssignmentschema 增加source_end。 - workflow 将
source_end透传到prepare_segment()(单素材/多素材均支持)。 prepare_segment()增加source_end参数,按[source_start, source_end)计算可用片段,并在需要循环时先裁剪再循环,避免循环范围错位。
4.2 时间轴有效时长计算修复
修复 sourceStart > 0 且 sourceEnd = 0 时的有效时长错误:
- 旧逻辑会按整段素材时长计算;
- 新逻辑改为
materialDuration - sourceStart。
该修复同时用于:
recalcPositions()的段时长计算;- TimelineEditor 中“循环补足”可视化比例计算。
4.3 可见段分配优先级修复
修复“可见段数 < 已选素材数时,custom_assignments 被丢弃回退自动分配”的问题:
- 生成请求优先以时间轴可见段的
assignments为准; - 超出时间轴的素材不参与本次生成。
4.4 单素材截取触发条件补齐
单素材模式下,若只改了终点(sourceEnd > 0)也会发送 custom_assignments,确保截取生效。
🧭 页面交互与体验细节 — 第五阶段 (Day 24)
- 页面刷新后自动回到顶部,避免从历史滚动位置进入页面。
- 素材列表与历史视频列表滚动增加“跳过首次自动滚动”保护,减少恢复状态时页面跳动。
- 时间轴比例区移除多余文案,保持信息简洁。
涉及文件汇总
后端修改
| 文件 | 变更 |
|---|---|
backend/app/repositories/users.py |
新增 deactivate_user_if_expired() 与 _parse_expires_at() |
backend/app/core/deps.py |
get_current_user / get_current_user_optional 接入到期失效检查 |
backend/app/modules/auth/router.py |
登录时到期停用 + /api/auth/me 统一鉴权依赖 |
backend/app/modules/videos/schemas.py |
CustomAssignment 新增 source_end;保留 output_aspect_ratio |
backend/app/modules/videos/workflow.py |
多素材/单素材透传 source_end;多素材 prepare/concat 统一 25fps;标题显示模式参数透传 Remotion |
backend/app/services/video_service.py |
旋转元数据解析与方向归一化;prepare_segment 支持 source_end/target_fps;concat 强制 CFR + +genpts |
backend/app/services/remotion_service.py |
render 支持 title_display_mode/title_duration 并传递到 render.ts |
前端修改
| 文件 | 变更 |
|---|---|
frontend/src/features/home/model/useTimelineEditor.ts |
CustomAssignment 新增 source_end;修复 sourceStart 开放终点时长计算 |
frontend/src/features/home/model/useHomeController.ts |
多素材以可见 assignments 为准发送;单素材截取触发条件补齐 |
frontend/src/features/home/ui/TimelineEditor.tsx |
画面比例下拉;循环比例按截取后有效时长计算 |
frontend/src/features/home/model/useHomePersistence.ts |
outputAspectRatio 与 titleDisplayMode 持久化 |
frontend/src/features/home/ui/HomePage.tsx |
页面进入滚动到顶部;ClipTrimmer/Timeline 交互保持一致 |
frontend/src/features/home/ui/FloatingStylePreview.tsx |
标题/字幕样式预览与成片渲染策略对齐 |
frontend/src/features/home/ui/TitleSubtitlePanel.tsx |
标题行新增“短暂显示/常驻显示”下拉 |
Remotion 修改
| 文件 | 变更 |
|---|---|
remotion/src/components/Title.tsx |
标题响应式缩放与自动换行;新增短暂/常驻显示模式控制 |
remotion/src/components/Subtitles.tsx |
字幕响应式缩放与自动换行,减少预览/成片差异 |
remotion/src/Video.tsx |
新增 titleDisplayMode 透传到标题组件 |
remotion/src/Root.tsx |
默认 props 增加 titleDisplayMode='short' 与 titleDuration=4 |
remotion/render.ts |
CLI 参数新增 --titleDisplayMode,inputProps 增加 titleDisplayMode |
验证记录
- 后端语法检查:
python -m py_compile backend/app/modules/videos/schemas.py backend/app/modules/videos/workflow.py backend/app/services/video_service.py backend/app/services/remotion_service.py - 前端类型检查:
npx tsc --noEmit - 前端 ESLint:
npx eslint src/features/home/model/useHomeController.ts src/features/home/model/useHomePersistence.ts src/features/home/ui/HomePage.tsx src/features/home/ui/TitleSubtitlePanel.tsx - Remotion 渲染脚本构建:
npm run build:render