refactor: simplify director video sync paths

This commit is contained in:
OpenClaw Agent
2026-07-09 15:17:24 +00:00
parent b9d68aea62
commit 7e569d5deb

View File

@@ -2122,6 +2122,41 @@ class TimelineEditor {
};
}
_syncActiveVideoSegments(segments, currentFrame, frameRate, activeType, dragSelectionType = null) {
const activeList = (this._isDragging && this._previewSegments && dragSelectionType === this.selectionType)
? this._previewSegments
: segments;
const activeSeg = activeList.find(s => s.type === activeType && currentFrame >= s.start && currentFrame < s.start + s.length);
const activeVideoEl = activeSeg ? activeSeg.videoEl : null;
for (const seg of activeList) {
if (seg.type !== activeType || !seg.videoEl) continue;
if (seg === activeSeg) {
const expectedSec = (seg.trimStart + (currentFrame - seg.start)) / frameRate;
if (seg.videoEl.paused && !seg.videoEl.seeking) {
seg.videoEl.currentTime = expectedSec;
seg.videoEl.play().catch(e => console.warn("Video play prevented", e));
} else if (!seg.videoEl.paused && Math.abs(seg.videoEl.currentTime - expectedSec) > 0.5) {
seg.videoEl.currentTime = expectedSec;
}
} else if (seg.videoEl !== activeVideoEl && !seg.videoEl.paused) {
seg.videoEl.pause();
}
}
}
_pauseAndSeekSegments(segments, currentFrame, frameRate, activeType) {
for (const seg of segments) {
if (seg.type !== activeType || !seg.videoEl) continue;
if (!seg.videoEl.paused) {
seg.videoEl.pause();
}
if (currentFrame >= seg.start && currentFrame < seg.start + seg.length) {
seg.videoEl.currentTime = (seg.trimStart + (currentFrame - seg.start)) / frameRate;
}
}
}
async _preloadAudioSegment(seg) {
if (seg._audioBuffer || seg._decoding) return;
if (!seg.audioFile && !seg._blobUrl) return;
@@ -11582,11 +11617,11 @@ class TimelineEditor {
}
// Sync video playback
if (this.retakeMode) {
if (this.timeline.retakeVideo) {
const retakeVid = this.timeline.retakeVideo;
this._ensureVideoEl(retakeVid);
if (retakeVid.videoEl) {
if (this.retakeMode) {
if (this.timeline.retakeVideo) {
const retakeVid = this.timeline.retakeVideo;
this._ensureVideoEl(retakeVid);
if (retakeVid.videoEl) {
const expectedSec = this.currentFrame / frameRate;
if (retakeVid.videoEl.paused && !retakeVid.videoEl.seeking) {
retakeVid.videoEl.currentTime = expectedSec;
@@ -11600,66 +11635,18 @@ class TimelineEditor {
// Pause all other video elements
const allSegments = [...(this.timeline.segments || []), ...(this.timeline.motionSegments || [])];
for (const seg of allSegments) {
if (seg.videoEl && !seg.videoEl.paused) {
seg.videoEl.pause();
}
}
} else {
const activeSegments = (this._isDragging && this._previewSegments && this.selectionType !== "audio") ? this._previewSegments : this.timeline.segments;
const activeSeg = activeSegments.find(s => s.type === "video" && this.currentFrame >= s.start && this.currentFrame < s.start + s.length);
const activeVideoEl = activeSeg ? activeSeg.videoEl : null;
for (const seg of activeSegments) {
if (seg.type === "video" && seg.videoEl) {
if (seg === activeSeg) {
const expectedSec = (seg.trimStart + (this.currentFrame - seg.start)) / frameRate;
if (seg.videoEl.paused && !seg.videoEl.seeking) {
// Not playing and no seek in flight — start a fresh seek+play
seg.videoEl.currentTime = expectedSec;
seg.videoEl.play().catch(e => console.warn("Video play prevented", e));
} else if (!seg.videoEl.paused && Math.abs(seg.videoEl.currentTime - expectedSec) > 0.5) {
// Already playing but drifted — resync
seg.videoEl.currentTime = expectedSec;
}
// If paused && seeking: a seek+play is already in flight, let it finish
} else {
// Only pause if this segment's video element is NOT shared with the currently active segment
if (seg.videoEl !== activeVideoEl && !seg.videoEl.paused) {
seg.videoEl.pause();
}
}
}
}
}
// Sync motion playback
if (!this.retakeMode) {
const activeMotionSegments = (this._isDragging && this._previewSegments && this.selectionType === "motion") ? this._previewSegments : this.timeline.motionSegments;
const activeMotionSeg = activeMotionSegments.find(s => s.type === "motion_video" && this.currentFrame >= s.start && this.currentFrame < s.start + s.length);
const activeMotionVideoEl = activeMotionSeg ? activeMotionSeg.videoEl : null;
for (const seg of activeMotionSegments) {
if (seg.type === "motion_video" && seg.videoEl) {
if (seg === activeMotionSeg) {
const expectedSec = (seg.trimStart + (this.currentFrame - seg.start)) / frameRate;
if (seg.videoEl.paused && !seg.videoEl.seeking) {
// Not playing and no seek in flight — start a fresh seek+play
seg.videoEl.currentTime = expectedSec;
seg.videoEl.play().catch(e => console.warn("Video play prevented", e));
} else if (!seg.videoEl.paused && Math.abs(seg.videoEl.currentTime - expectedSec) > 0.5) {
// Already playing but drifted — resync
seg.videoEl.currentTime = expectedSec;
}
// If paused && seeking: a seek+play is already in flight, let it finish
} else {
// Only pause if this segment's video element is NOT shared with the currently active motion segment
if (seg.videoEl !== activeMotionVideoEl && !seg.videoEl.paused) {
seg.videoEl.pause();
}
}
}
}
}
if (seg.videoEl && !seg.videoEl.paused) {
seg.videoEl.pause();
}
}
} else {
this._syncActiveVideoSegments(this.timeline.segments, this.currentFrame, frameRate, "video", "image");
}
// Sync motion playback
if (!this.retakeMode) {
this._syncActiveVideoSegments(this.timeline.motionSegments, this.currentFrame, frameRate, "motion_video", "motion");
}
this.render();
this._playLoopId = requestAnimationFrame(loop);
@@ -11676,40 +11663,20 @@ class TimelineEditor {
try { this.audioContext.suspend(); } catch (e) { }
}
if (this.retakeMode && this.timeline.retakeVideo) {
const retakeVid = this.timeline.retakeVideo;
if (retakeVid.videoEl) {
if (!retakeVid.videoEl.paused) {
if (this.retakeMode && this.timeline.retakeVideo) {
const retakeVid = this.timeline.retakeVideo;
if (retakeVid.videoEl) {
if (!retakeVid.videoEl.paused) {
retakeVid.videoEl.pause();
}
retakeVid.videoEl.muted = true; // Mute again on pause/stop to prevent transient audio bursts
retakeVid.videoEl.currentTime = this.currentFrame / this.getFrameRate();
}
} else {
// Sync video segments on pause
for (const seg of this.timeline.segments) {
if (seg.type === "video" && seg.videoEl) {
if (!seg.videoEl.paused) {
seg.videoEl.pause();
}
if (this.currentFrame >= seg.start && this.currentFrame < seg.start + seg.length) {
seg.videoEl.currentTime = (seg.trimStart + (this.currentFrame - seg.start)) / this.getFrameRate();
}
}
}
// Sync motion segments on pause
for (const seg of this.timeline.motionSegments) {
if (seg.type === "motion_video" && seg.videoEl) {
if (!seg.videoEl.paused) {
seg.videoEl.pause();
}
if (this.currentFrame >= seg.start && this.currentFrame < seg.start + seg.length) {
seg.videoEl.currentTime = (seg.trimStart + (this.currentFrame - seg.start)) / this.getFrameRate();
}
}
}
}
retakeVid.videoEl.currentTime = this.currentFrame / this.getFrameRate();
}
} else {
const frameRate = this.getFrameRate();
this._pauseAndSeekSegments(this.timeline.segments, this.currentFrame, frameRate, "video");
this._pauseAndSeekSegments(this.timeline.motionSegments, this.currentFrame, frameRate, "motion_video");
}
for (let node of this.activeAudioNodes) {
try { node.stop(); } catch (e) { }