From 1556231f1730e934a5419edf752755b9c41dbe1a Mon Sep 17 00:00:00 2001 From: rakadu1 Date: Tue, 17 Mar 2026 17:15:19 +0530 Subject: [PATCH] feat: robust date-time parsing and persistent overlay resilience IMPROVEMENTS: - **utils.js**: Enhanced [extractTimestampInfo](cci:1://file:///d:/Work/Repo/refactor/steps/src/utils.js:36:0-70:1) with a robust, prefix-agnostic regular expression. It now identifies `YYYYMMDD_HHMMSS` and `DDMMYYYY_HHMMSS` patterns anywhere in a filename, enabling support for generic camera names like `cam_20260312_163310` or raw recordings. - **dom.js**: Decoupled persistent overlays and debug diagnostics from mandatory video date-time metadata. The dashboard now remains fully functional even when loading generic video files (e.g., `output.mp4`). - **Standardized Epoch Fallback**: Implemented a unified time-anchoring logic. If a filename lacks date-time information, the system now defaults to **January 1, 1970 (Unix Epoch)**, ensuring the absolute time clocks and sync diagnostics proceed without error or disappearance. - **Bug Fixes**: Corrected syntax errors and structural scoping issues in the [updateDebugOverlay](cci:1://file:///d:/Work/Repo/refactor/steps/src/dom.js:200:0-291:1) function that were causing diagnostics to display inconsistently. --- steps/src/dom.js | 53 +++++++++++++++++++++++----------------------- steps/src/utils.js | 21 ++++++++++++------ 2 files changed, 40 insertions(+), 34 deletions(-) diff --git a/steps/src/dom.js b/steps/src/dom.js index afe226d..adee74f 100644 --- a/steps/src/dom.js +++ b/steps/src/dom.js @@ -217,9 +217,8 @@ export function updateDebugOverlay(currentMediaTime) { // --- Logic for the original debug overlay --- if (isDebug1Visible) { content.push(`--- Basic Info ---`); - if (appState.videoStartDate) { - const videoAbsoluteTimeMs = - appState.videoStartDate.getTime() + currentMediaTime * 1000; + const baseTimeMs = appState.videoStartDate ? appState.videoStartDate.getTime() : (appState.radarStartTimeMs || 0); + const videoAbsoluteTimeMs = baseTimeMs + currentMediaTime * 1000; let timeString = `Media Time (s): ${currentMediaTime.toFixed(2)}`; // Two decimal places if (videoPlayer && !isNaN(videoPlayer.duration) && videoPlayer.duration > 0) { @@ -234,32 +233,29 @@ export function updateDebugOverlay(currentMediaTime) { .split("T")[1] .replace("Z", "")}` ); // Format and display video absolute time - } else { - content.push("Video not loaded..."); // Indicate video not loaded. - } - if ( - appState.vizData && - appState.vizData.radarFrames[appState.currentFrame] - ) { - content.push(`Radar Frame: ${appState.currentFrame + 1}`); - const frameTime = - appState.vizData.radarFrames[appState.currentFrame].timestampMs; - content.push( - `Radar Abs Time: ${new Date( - appState.videoStartDate.getTime() + frameTime - ) - .toISOString() - .split("T")[1] - .replace("Z", "")}` - ); // Format and display radar absolute time + + if ( + appState.vizData && + appState.vizData.radarFrames[appState.currentFrame] + ) { + content.push(`Radar Frame: ${appState.currentFrame + 1}`); + const frameData = appState.vizData.radarFrames[appState.currentFrame]; + const frameTime = frameData.timestampMs; + const baseTimeMs = appState.videoStartDate ? appState.videoStartDate.getTime() : (appState.radarStartTimeMs || 0); + + content.push( + `Radar Abs Time: ${new Date(baseTimeMs + frameTime) + .toISOString() + .split("T")[1] + .replace("Z", "")}` + ); // Format and display radar absolute time + } } - } // --- Logic for the new advanced debug overlay --- if (isDebug2Visible) { content.push(`--- Sync Diagnostics ---`); if ( - appState.videoStartDate && appState.vizData && appState.vizData.radarFrames[appState.currentFrame] ) { @@ -275,8 +271,9 @@ export function updateDebugOverlay(currentMediaTime) { content.push(`Video Time (s): ${currentMediaTime.toFixed(3)}`); // Display current video time content.push(`Target Sync Time (s): ${currentRadarFrame.videoSyncedTime.toFixed(3)}`); content.push(`Drift (ms): ${driftMs.toFixed(0)}`); - content.push(`Video Start Time: ${appState.videoStartDate.toISOString()}`); - content.push(`Radar Start Time: ${new Date(appState.radarStartTimeMs).toISOString()}`); + const videoStart = appState.videoStartDate ? appState.videoStartDate.toISOString() : new Date(0).toISOString(); + content.push(`Video Start Time: ${videoStart}`); + content.push(`Radar Start Time: ${new Date(appState.radarStartTimeMs || 0).toISOString()}`); content.push(`Calculated Offset (ms): ${offsetInput.value}`); // Display calculated offset. const renderTime = appState.lastFrameRenderTime; // Color is green if render time is under 33ms (~30fps budget), otherwise red @@ -320,7 +317,7 @@ export function updatePersistentOverlays(currentMediaTime) { } // If we don't have the necessary data, hide the overlays and exit. - if (!appState.vizData || !appState.videoStartDate) { + if (!appState.vizData) { radarInfoOverlay.classList.add("hidden"); videoInfoOverlay.classList.add("hidden"); return; @@ -521,7 +518,9 @@ export function updatePersistentOverlays(currentMediaTime) { } // --- Update Video Persistent Overlay --- - const absVideoTime = new Date(appState.videoStartDate.getTime() + currentMediaTime * 1000); + // Default to Unix Epoch (Jan 1, 1970) if no dates are available + const baseTimeMs = appState.videoStartDate ? appState.videoStartDate.getTime() : (appState.radarStartTimeMs || 0); + const absVideoTime = new Date(baseTimeMs + currentMediaTime * 1000); const videoFrame = Math.floor(currentMediaTime * VIDEO_FPS); let timeDisplay = `Elapsed Time: ${currentMediaTime.toFixed(2)}s`; diff --git a/steps/src/utils.js b/steps/src/utils.js index be1345e..b0b3eb7 100644 --- a/steps/src/utils.js +++ b/steps/src/utils.js @@ -52,13 +52,20 @@ export function extractTimestampInfo(filename) { const timestamp = `${match[1]}_${match[2]}${match[3]}${match[4]}`; return { timestampStr: timestamp, format: "video" }; } - // Try to match another common video filename pattern: "video_YYYYMMDD_HHMMSS" - match = filename.match(/video_(\d{8}_\d{6})/); - if (match) - return { - timestampStr: match[1], - format: "video", - }; + // Try to match generic YYYYMMDD_HHMMSS or similar patterns anywhere in the name + // Examples: video_20231027_103000, cam_20260312_163310, 20260312163310 + match = filename.match(/((?:19|20)\d{2})(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])[-_]?([01]\d|2[0-3])([0-5]\d)([0-5]\d)/); + if (match) { + const timestamp = `${match[1]}${match[2]}${match[3]}_${match[4]}${match[5]}${match[6]}`; + return { timestampStr: timestamp, format: "video" }; + } + + // Try generic DDMMYYYY_HHMMSS pattern just in case + match = filename.match(/(0[1-9]|[12]\d|3[01])(0[1-9]|1[0-2])((?:19|20)\d{2})[-_]?([01]\d|2[0-3])([0-5]\d)([0-5]\d)/); + if (match) { + const timestamp = `${match[3]}${match[2]}${match[1]}_${match[4]}${match[5]}${match[6]}`; + return { timestampStr: timestamp, format: "video" }; + } // If no pattern matches, return null return null; }