feat(swap-media): 实现 SwapMedia 编辑命令,支持替换 clip 媒体 (#101)#121
feat(swap-media): 实现 SwapMedia 编辑命令,支持替换 clip 媒体 (#101)#121cuic19053-hue wants to merge 7 commits into
Conversation
appergb
left a comment
There was a problem hiding this comment.
@cuic19053-hue 自动审核结论:请修改(REQUEST_CHANGES)。SwapMedia 命令端到端接线 OK、不碰 #91 区,但三处违背 1:1 上游(issue #101 明确『校验类型一致』):
- 缺类型一致校验(CRITICAL):
swap_media不校验新素材 kind,前端对所有非 text 候选传mediaType: item.type——视频 clip 可被换到音频素材并静默改类型(留在视频轨),完整性违规。上游isAssetCompatibleWithPendingSwap要求clip.mediaType == asset.type,不符则 toast + 保持 pending。请加严格类型一致校验。 - 自创 truncate-to-fit + trim_end clamp(HIGH):上游
replaceClipMediaRef默认resetTrim=false,只改 mediaRef,保留 trim/speed/keyframes/transform、不改时长。本 PR 的 steps 7-8(按新媒体长度截断 + clamp trim_end)无上游依据,会在换短素材时改变 clip 时序。请删除该逻辑。 - 缺链接组级联(HIGH):上游对『同链接组、共享同一旧 media』的 clip 一起换;Inspector 可用性条件应为『非 text 且单链组』(spec 5.10 frontend-UI-1to1-SPEC.md:665),当前只 gate 非 text。
请按上游 1:1 修正后 rebase 到含 #119 的 main。
appergb
left a comment
There was a problem hiding this comment.
@cuic19053-hue Sonnet 4.6 复审:仍需修改。CI 双绿,但有正确性/完整性阻塞:
- [CRITICAL] 缺类型一致校验。
crates/opentake-ops/src/command.rsswap_media()只读new_asset.duration,未校验new_asset.kind == clip.media_type→ 视频 clip 可被静默换成音频素材并留在视频轨。上游EditorViewModel+MediaSwap.swift:32有guard clip.mediaType == asset.type。前端Inspector.tsx候选过滤m.type !== 'text'应改为m.type === clip.mediaType。 - [HIGH] 自创 truncate/trim_end clamp 无上游依据。
swap_media()第 7、8 步按新媒体长度截断final_duration+ clamptrim_end——上游replaceClipMediaRef(resetTrim:false)(ClipMutations.swift:462)默认只改mediaRef,保留 trim/speed/keyframes/transform、不改时长。请删除这两步。 - [HIGH] 缺链接组级联。
transact闭包只更新单个clip_id;上游linkedClipIdsSharingMedia(anchor:)(ClipMutations.swift:467)批量替换同linkGroupId且共享旧 mediaRef 的整组。前端入口还缺singleLinkGroupgate(上游TimelineView.swift:741)。 - 触碰 #91 媒体重写区:
Inspector.tsx新增import useMediaStore读s.items,碰store/mediaStore*。请改用既有非媒体区入口或与 #91 协调。
把 1–3 按上游改对、4 避开媒体区后重提。
后端: - 新增 EditCommand::SwapMedia 变体,替换 clip 的 media_ref - 校验新媒体存在于 manifest,若时长不足自动截断 duration + 调整 trim_end - 保留所有编辑属性(transform/crop/keyframe tracks/grade/masks/effects/fade) - media_type 隐含 source_clip_type(spec "sync media_type" 场景) - 新增 EditRequest::SwapMedia DTO + into_command 映射 - 6 个单元测试:等长替换/较短截断/媒体不存在/同步 media_type/clip 不存在/undo 前端: - types.ts 新增 swapMedia EditRequest 变体 - editActions.ts 新增 swapMedia(clipId, mediaRef, options?) action - Inspector 新增「替换媒体」section + 内联媒体选择器 - i18n 中英文翻译 Closes appergb#101
92e8a54 to
a4d92d6
Compare
|
复审反馈已全部处理(2 个 commit:18a76e1 + 02d484e): 1. [CRITICAL] 类型一致性校验 — swap_media() 现在拒绝 clip.media_type != asset.kind(视频 clip 只能换视频素材)。前端候选过滤从 m.type !== 'text' 改为 m.type === clip.mediaType。 2. [HIGH] 删除自创 truncate/trim_end clamp — SwapMedia 命令缩减为 { clip_id, media_ref } 两字段,对齐上游 3. [HIGH] 链接组级联 + 前端 gate — 后端 ransact 批量替换同 linkGroupId 且共享旧 mediaRef 的整组。前端加 singleLinkGroup gate(SPEC §5.10, frontend-UI-1to1-SPEC.md:665「非 text 且单链组」):clip 属于多 clip 链接组时隐藏 Swap Media 入口(避免级联意外)。 4. 避开 mediaStore 区 — SwapMediaSection 提取到独立文件 web/src/components/inspector/SwapMediaSection.tsx,Inspector.tsx 不再 import useMediaStore。mediaStore 依赖隔离在单文件内,#91 重写时只需更新这一处。 8 个单元测试覆盖:类型不符拒绝、同 mediaRef no-op、短素材保留 duration/trim、链接组级联、不同 mediaRef 不级联、undo 恢复、未知 clip 拒绝、未知 mediaRef 拒绝。 请复审。 |
|
@appergb 请求重新审查。此前反馈已全部修复,CI 双绿(Rust ✅ Web ✅,commit \�4d92d6\):
请 re-review,谢谢! |
What
解决 #101:媒体替换(SwapMedia)
How
后端
EditCommand::SwapMedia变体,替换 clip 的 media_ref前端
swapMediaEditRequest 类型 + actionTesting
Limitation
issue #101 还提到 SaveAsMedia 和 ExtractAudio,这两项依赖 ffmpeg 编码管线(crates/opentake-encode/src/preset.rs 未完成),留作后续。
Closes #101