From d3bcceda9da2b05a74cb17bf6270d8f55d973a5a Mon Sep 17 00:00:00 2001 From: kang Date: Sun, 17 May 2026 22:30:29 +0800 Subject: [PATCH] auto-save 2026-05-17 22:30 (~2) --- .memory/worklog.json | 27 +++++---- web/components/ad-recreation-board.tsx | 79 ++++++++++++-------------- 2 files changed, 49 insertions(+), 57 deletions(-) diff --git a/.memory/worklog.json b/.memory/worklog.json index 9fcaf1e..b64972b 100644 --- a/.memory/worklog.json +++ b/.memory/worklog.json @@ -1,19 +1,5 @@ { "entries": [ - { - "files_changed": 1, - "hash": "9f1b0bd", - "message": "auto-save 2026-05-15 13:45 (~1)", - "ts": "2026-05-15T13:45:59+08:00", - "type": "commit" - }, - { - "files_changed": 1, - "hash": "b9ab6d3", - "message": "auto-save 2026-05-15 13:51 (~1)", - "ts": "2026-05-15T13:51:32+08:00", - "type": "commit" - }, { "files_changed": 1, "message": "Codex 会话活跃 · 最近命令:codex · 1 项未提交变更 · 最近提交:auto-save 2026-05-15 13:51 (~1)", @@ -3260,6 +3246,19 @@ "type": "session-heartbeat", "message": "Codex 会话活跃 · 最近命令:codex · 分支 main · 1 项未提交变更 · 最近提交:auto-save 2026-05-17 22:14 (~3)", "files_changed": 1 + }, + { + "ts": "2026-05-17T22:25:07+08:00", + "type": "commit", + "message": "auto-save 2026-05-17 22:25 (~3)", + "hash": "e5cffe9", + "files_changed": 3 + }, + { + "ts": "2026-05-17T14:28:30Z", + "type": "session-heartbeat", + "message": "Codex 会话活跃 · 最近命令:codex · 分支 main · 1 项未提交变更 · 最近提交:auto-save 2026-05-17 22:25 (~3)", + "files_changed": 1 } ] } diff --git a/web/components/ad-recreation-board.tsx b/web/components/ad-recreation-board.tsx index b3521b2..3fc86cb 100644 --- a/web/components/ad-recreation-board.tsx +++ b/web/components/ad-recreation-board.tsx @@ -1006,6 +1006,7 @@ function AudioIntakePanel({ const [mediaDuration, setMediaDuration] = useState(0) const [audioFeatures, setAudioFeatures] = useState([]) const [audioFeatureStatus, setAudioFeatureStatus] = useState("idle") + const [manualBusy, setManualBusy] = useState(false) const videoRef = useRef(null) const rowRefs = useRef>({}) const syncFrameRef = useRef(null) @@ -1094,6 +1095,17 @@ function AudioIntakePanel({ setCurrentTime(next) } + const addFrameAtCurrentTime = async () => { + if (!job || !onAddFrame) return + const next = clampNumber(currentTime, 0, timelineDuration) + setManualBusy(true) + try { + await onAddFrame(job.id, next) + } finally { + setManualBusy(false) + } + } + if (!job) { return } @@ -1132,11 +1144,23 @@ function AudioIntakePanel({ /> -
+
} title="原版视频" /> - {currentTime.toFixed(1)}s / {formatSeconds(timelineDuration)} +
+ {currentTime.toFixed(1)}s / {formatSeconds(timelineDuration)} + +
{job.video_url ? ( @@ -1144,7 +1168,7 @@ function AudioIntakePanel({ ref={videoRef} controls playsInline - className="h-[270px] w-full bg-black object-contain 2xl:h-[300px]" + className="h-[320px] w-full bg-black object-contain 2xl:h-[380px]" src={videoSrcUrl} onTimeUpdate={(event) => setCurrentTime(event.currentTarget.currentTime)} onSeeked={(event) => setCurrentTime(event.currentTarget.currentTime)} @@ -1158,7 +1182,7 @@ function AudioIntakePanel({ }} /> ) : ( -
等待原视频
+
等待原视频
)}
@@ -1168,9 +1192,6 @@ function AudioIntakePanel({ selectedFrames={selectedFrames} onToggleFrame={onToggleFrame} onJobUpdate={onJobUpdate} - currentTime={currentTime} - duration={timelineDuration} - onAddFrame={onAddFrame} onDeleteFrame={onDeleteFrame} /> @@ -1186,7 +1207,7 @@ function AudioIntakePanel({
原文
中文
-
+
{job.transcript.map((segment) => { const active = activeSegment?.index === segment.index return ( @@ -1223,22 +1244,15 @@ function SourceReferenceBuildPanel({ selectedFrames, onToggleFrame, onJobUpdate, - currentTime, - duration, - onAddFrame, onDeleteFrame, }: { job: Job selectedFrames: Set onToggleFrame: (idx: number) => void onJobUpdate: (job: Job) => void - currentTime: number - duration: number - onAddFrame?: (jobId: string, t: number) => Promise | void onDeleteFrame?: (jobId: string, idx: number) => Promise | void }) { const [extracting, setExtracting] = useState(false) - const [manualBusy, setManualBusy] = useState(false) const [subjectBusy, setSubjectBusy] = useState(false) const [deletingFrame, setDeletingFrame] = useState(null) const frames = useMemo(() => [...job.frames].sort((a, b) => a.timestamp - b.timestamp), [job.frames]) @@ -1259,7 +1273,6 @@ function SourceReferenceBuildPanel({ return null }, [frames, selectedReferenceFrames]) const actorAssets = actorSource?.element.subject_assets ?? [] - const manualFrameTime = clampNumber(currentTime, 0, Math.max(duration, 1)) const extractKeyframes = async () => { setExtracting(true) @@ -1322,16 +1335,6 @@ function SourceReferenceBuildPanel({ } } - const addFrameAtCurrentTime = async () => { - if (!onAddFrame) return - setManualBusy(true) - try { - await onAddFrame(job.id, manualFrameTime) - } finally { - setManualBusy(false) - } - } - const deleteReferenceFrame = async (idx: number) => { if (!onDeleteFrame) return setDeletingFrame(idx) @@ -1350,8 +1353,8 @@ function SourceReferenceBuildPanel({ {frames.length ? `${frames.length} 张` : "待抽帧"} · 已选 {selectedReferenceFrames.length}
-
-
+
+
-
-
+
{frames.map((frame, index) => { const selected = selectedFrames.has(frame.index) return (
onToggleFrame(frame.index)} className="absolute inset-0 cursor-pointer overflow-hidden focus:outline-none focus:ring-1 focus:ring-cyan-200/70" > - + {String(index + 1).padStart(2, "0")} @@ -1424,8 +1417,8 @@ function SourceReferenceBuildPanel({ ) })} {!frames.length && ( -
- 点击“抽参考 12 帧”,或播放到指定时间后用“当前点抽帧”补充人物参考。 +
+ 点击“抽参考 12 帧”,或在原版视频播放器右上角用“当前点抽帧”补充人物参考。
)}