From 6a76d1fa3cdd2c749a1ae02165f80b78508f9044 Mon Sep 17 00:00:00 2001 From: webadderall <131426131+webadderall@users.noreply.github.com> Date: Fri, 27 Mar 2026 20:18:20 +1100 Subject: [PATCH] fix(recording): restore effective duration accounting --- src/hooks/useScreenRecorder.ts | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/src/hooks/useScreenRecorder.ts b/src/hooks/useScreenRecorder.ts index 5561b059..af3b0b93 100644 --- a/src/hooks/useScreenRecorder.ts +++ b/src/hooks/useScreenRecorder.ts @@ -79,6 +79,8 @@ export function useScreenRecorder(): UseScreenRecorderReturn { const chunks = useRef([]); const webcamChunks = useRef([]); const startTime = useRef(0); + const webcamStartTime = useRef(null); + const webcamTimeOffsetMs = useRef(0); const recordingSessionTimestamp = useRef(null); const nativeScreenRecording = useRef(false); const nativeWindowsRecording = useRef(false); @@ -109,10 +111,7 @@ export function useScreenRecorder(): UseScreenRecorderReturn { return; } - accumulatedPausedDurationMs.current += Math.max( - 0, - resumedAt - pauseStartedAtMs.current, - ); + accumulatedPausedDurationMs.current += Math.max(0, resumedAt - pauseStartedAtMs.current); pauseStartedAtMs.current = null; }, []); @@ -266,6 +265,7 @@ export function useScreenRecorder(): UseScreenRecorderReturn { await window.electronAPI.setCurrentRecordingSession({ videoPath, webcamPath, + timeOffsetMs: webcamTimeOffsetMs.current, }); } else { await window.electronAPI.setCurrentVideoPath(videoPath); @@ -294,6 +294,8 @@ export function useScreenRecorder(): UseScreenRecorderReturn { const startWebcamRecorder = useCallback(async () => { if (!webcamEnabled) { pendingWebcamPathPromise.current = Promise.resolve(null); + webcamStartTime.current = null; + webcamTimeOffsetMs.current = 0; return; } @@ -346,7 +348,10 @@ export function useScreenRecorder(): UseScreenRecorderReturn { return; } - const duration = getRecordingDurationMs(Date.now()); + const duration = Math.max( + 0, + getRecordingDurationMs(Date.now()) - webcamTimeOffsetMs.current, + ); const webcamBlob = new Blob(webcamChunks.current, { type: mimeType }); webcamChunks.current = []; const fixedBlob = await fixWebmDuration(webcamBlob, duration); @@ -359,6 +364,7 @@ export function useScreenRecorder(): UseScreenRecorderReturn { } finally { webcamStopResolver.current = null; webcamRecorder.current = null; + webcamStartTime.current = null; if (webcamStream.current) { webcamStream.current.getTracks().forEach((track) => track.stop()); webcamStream.current = null; @@ -366,12 +372,15 @@ export function useScreenRecorder(): UseScreenRecorderReturn { } }; + webcamStartTime.current = Date.now(); recorder.start(RECORDER_TIMESLICE_MS); } catch (error) { console.warn("Failed to start webcam recording; continuing without webcam layer:", error); pendingWebcamPathPromise.current = Promise.resolve(null); webcamStopPromise.current = Promise.resolve(null); webcamRecorder.current = null; + webcamStartTime.current = null; + webcamTimeOffsetMs.current = 0; if (webcamStream.current) { webcamStream.current.getTracks().forEach((track) => track.stop()); webcamStream.current = null; @@ -591,9 +600,13 @@ export function useScreenRecorder(): UseScreenRecorderReturn { } if (nativeResult.success) { + const mainStartedAt = Date.now(); nativeScreenRecording.current = true; nativeWindowsRecording.current = useNativeWindowsCapture; - resetRecordingClock(Date.now()); + resetRecordingClock(mainStartedAt); + webcamTimeOffsetMs.current = webcamStartTime.current === null + ? 0 + : webcamStartTime.current - mainStartedAt; setRecording(true); window.electronAPI?.setRecordingState(true); @@ -819,8 +832,12 @@ export function useScreenRecorder(): UseScreenRecorderReturn { recorder.onerror = () => { setRecording(false); }; + const mainStartedAt = Date.now(); + resetRecordingClock(mainStartedAt); + webcamTimeOffsetMs.current = webcamStartTime.current === null + ? 0 + : webcamStartTime.current - mainStartedAt; recorder.start(RECORDER_TIMESLICE_MS); - resetRecordingClock(Date.now()); setRecording(true); window.electronAPI?.setRecordingState(true); } catch (error) { @@ -902,6 +919,8 @@ export function useScreenRecorder(): UseScreenRecorderReturn { webcamRecorder.current.stop(); } webcamRecorder.current = null; + webcamStartTime.current = null; + webcamTimeOffsetMs.current = 0; webcamStream.current?.getTracks().forEach((t) => t.stop()); webcamStream.current = null; pendingWebcamPathPromise.current = null;