Skip to content

feat(activity-feed-v2): sync sidebar timestamps with video time format#4636

Open
kduncanhsu wants to merge 1 commit into
box:masterfrom
kduncanhsu:kduncanhsu/sync-timestamp-to-comments
Open

feat(activity-feed-v2): sync sidebar timestamps with video time format#4636
kduncanhsu wants to merge 1 commit into
box:masterfrom
kduncanhsu:kduncanhsu/sync-timestamp-to-comments

Conversation

@kduncanhsu

@kduncanhsu kduncanhsu commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Sidebar comment timestamps (editor checkbox and posted comment badges) now respect the time format selected in the video player controls (standard, timecode, or frame numbers)
  • Adds useTimeFormat hook that observes data-time-format and data-fps attributes on .bp-media-container via MutationObserver
  • Adds convertMillisecondsToTimecode and convertMillisecondsToFrames to timestamp utils

Test plan

  • All existing tests pass (264 total across activity-feed-v2 + timestamp utils)
  • New useTimeFormat hook tests (11 tests) — initial read, reactive updates, late container, fallbacks, disable reset
  • New useVideoTimestamp format integration tests (4 tests) — timecode/frames formatting, live format switch
  • New FeedItemRow badge format tests (6 tests) — comment/annotation badges update per format
  • New timestamp utils tests (11 tests) — convertMillisecondsToTimecode and convertMillisecondsToFrames
  • Manual: open video with sidebar, change time format dropdown, verify checkbox timestamp and posted comment badges update

Summary by CodeRabbit

Release Notes

  • New Features
    • Activity feed timestamps for video now render in standard timestamp, timecode (HH:MM:SS:FF), or frame count based on the current video timing settings.
    • Comment and annotation entries now display timestamp details consistently for frame-based events (including correct handling for timecode vs. frames).
  • Tests
    • Added automated coverage for time-format integration and timestamp rendering across video settings.

@kduncanhsu kduncanhsu requested review from a team as code owners June 16, 2026 23:08
@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.


Duncan Hsu seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You have signed the CLA already but the status is still pending? Let us recheck it.

@coderabbitai

coderabbitai Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Adds video-aware timestamp formatting to the activity feed. New convertMillisecondsToTimecode and convertMillisecondsToFrames utilities are added to src/utils/timestamp.ts. A new useTimeFormat hook reads data-time-format and data-fps from .bp-media-container via MutationObserver. useVideoTimestamp and FeedItemRow consume this hook to render timecode or frame-count timestamps when isVideo is true.

Changes

Video Timestamp Formatting

Layer / File(s) Summary
New timestamp conversion utilities
src/utils/timestamp.ts, src/utils/__tests__/timestamp.test.js
convertMillisecondsToTimecode (HH:MM:SS:FF) and convertMillisecondsToFrames added to the timestamp utility module and covered with edge-case tests.
useTimeFormat hook and formatByTimeFormat utility
src/elements/content-sidebar/activity-feed-v2/useTimeFormat.ts, src/elements/content-sidebar/activity-feed-v2/__tests__/useTimeFormat.test.tsx
New hook reads data-time-format/data-fps from .bp-media-container using MutationObservers; formatByTimeFormat dispatches to the correct converter. Full unit tests including late-container and reset scenarios.
useVideoTimestamp updated to use useTimeFormat
src/elements/content-sidebar/activity-feed-v2/useVideoTimestamp.ts, src/elements/content-sidebar/activity-feed-v2/__tests__/useVideoTimestamp.test.tsx
Replaces convertMillisecondsToTimestamp with formatByTimeFormat driven by useTimeFormat(enabled). Integration tests verify timecode, frames, dynamic format switching, and default-format paths.
FeedItemRow and ActivityFeedV2 video timestamp integration
src/elements/content-sidebar/activity-feed-v2/FeedItemRow.tsx, src/elements/content-sidebar/activity-feed-v2/ActivityFeedV2.tsx, src/elements/content-sidebar/activity-feed-v2/__tests__/FeedItemRow.test.tsx
Adds optional isVideo prop to FeedItemRow; comment and frame-annotation rendering conditionally inject formatted timestamps via useTimeFormat. ActivityFeedV2 derives and passes the isVideo flag per row.

Sequence Diagram(s)

sequenceDiagram
  participant ActivityFeedV2
  participant FeedItemRow
  participant useTimeFormat
  participant bp-media-container
  participant formatByTimeFormat

  ActivityFeedV2->>FeedItemRow: isVideo={file.extension in FILE_EXTENSIONS.video}
  FeedItemRow->>useTimeFormat: useTimeFormat(isVideo)
  useTimeFormat->>bp-media-container: read data-time-format, data-fps
  bp-media-container-->>useTimeFormat: timeFormat, fps
  useTimeFormat-->>FeedItemRow: { timeFormat, fps }
  FeedItemRow->>formatByTimeFormat: formatByTimeFormat(annotationTimestampMs, timeFormat, fps)
  formatByTimeFormat-->>FeedItemRow: formatted timestamp string
  FeedItemRow-->>ActivityFeedV2: renders ThreadedAnnotation with formatted timestamp
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • box/box-ui-elements#4409: Changed the media container selector from .bp-media-dash to .bp-media-container, which is the exact DOM element this PR's useTimeFormat hook queries for data-time-format and data-fps.
  • box/box-ui-elements#4575: Added frame-aware annotationTargetToBadge timestamp formatting using convertMillisecondsToTimestamp; this PR extends that pattern by replacing the formatter with useTimeFormat-driven formatByTimeFormat.
  • box/box-ui-elements#4620: Both PRs modify FeedItemRow's comment/annotation badge logic around annotationTimestampMs — the retrieved PR wires badge clicks to video seek, while this PR formats the displayed timestamp using isVideo/useTimeFormat.

Suggested labels

ready-to-merge

Suggested reviewers

  • ahorowitz123
  • JChan106

Poem

🐇 Hop hop, the timestamps now sing,
In timecode and frames, a video thing!
The media container whispers its fps,
The MutationObserver does all the rest.
No more plain seconds — we're frame-perfect today,
This bunny approves of the video-aware way! 🎬

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: synchronizing sidebar timestamps with video time format in the activity-feed-v2 component.
Description check ✅ Passed The pull request description is well-structured with a clear summary, comprehensive test plan, and manual testing instructions. However, it does not follow the repository's description template, which focuses on CLA and merge queue instructions.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
src/utils/__tests__/timestamp.test.js (1)

93-155: ⚡ Quick win

Add fractional-FPS coverage for timecode/frame conversions.

Current cases are integer-FPS only. Since data-fps is parsed as a number upstream, add at least one 29.97 case to lock expected behavior and prevent player/sidebar drift regressions.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/utils/__tests__/timestamp.test.js` around lines 93 - 155, The test suite
for convertMillisecondsToTimecode and convertMillisecondsToFrames lacks coverage
for fractional FPS values (such as 29.97), which can be passed as numbers from
upstream data-fps parsing. Add at least one test case within each describe block
that tests a fractional FPS value like 29.97 to ensure the conversion functions
handle non-integer frame rates correctly and prevent player/sidebar drift
regressions. Include test cases with typical fractional FPS values (29.97,
23.976) and verify that the timecode and frame calculations remain accurate.
src/elements/content-sidebar/activity-feed-v2/__tests__/FeedItemRow.test.tsx (1)

60-64: ⚡ Quick win

Reset mockTimeFormat in beforeEach to avoid cross-test state leakage.

mockTimeFormat is mutated in multiple tests but never reset. Add a deterministic reset in beforeEach so tests remain order-independent.

Suggested fix
 beforeEach(() => {
     lastThreadedAnnotationProps = {};
     lastTaskProps = {};
     lastVersionProps = {};
+    mockTimeFormat.timeFormat = 'standard';
+    mockTimeFormat.fps = 24;
     mockedSerializeEditorContent.mockReturnValue({ hasMention: false, text: 'serialized-text' });
 });

Also applies to: 213-218

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/elements/content-sidebar/activity-feed-v2/__tests__/FeedItemRow.test.tsx`
around lines 60 - 64, The mockTimeFormat object is being mutated across multiple
tests but never reset between test runs, causing state leakage and making test
execution order-dependent. Add a beforeEach block that resets mockTimeFormat
back to its initial values (timeFormat: 'standard', fps: 24) before each test
runs to ensure consistent and isolated test behavior. This ensures the mock
object starts with known values for every test regardless of what previous tests
may have modified.
src/elements/content-sidebar/activity-feed-v2/useTimeFormat.ts (1)

50-55: 💤 Low value

Consider validating the attribute value before casting.

The type assertion as TimeFormat on line 51 bypasses TypeScript's type checking. If the DOM attribute contains an invalid value like "invalid", the cast will succeed but the runtime value won't match the TimeFormat union. While formatByTimeFormat has a default case that safely handles this, explicit validation would be more type-safe:

♻️ Suggested type-safe validation
 const readAttributes = (container: Element): void => {
-    const format = (container.getAttribute('data-time-format') as TimeFormat) || 'standard';
+    const formatAttr = container.getAttribute('data-time-format');
+    const format: TimeFormat =
+        formatAttr === 'timecode' || formatAttr === 'frames' || formatAttr === 'standard'
+            ? formatAttr
+            : 'standard';
     const fpsAttr = Number(container.getAttribute('data-fps'));
     setTimeFormat(format);
     setFps(fpsAttr > 0 ? fpsAttr : DEFAULT_FPS);
 };
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/elements/content-sidebar/activity-feed-v2/useTimeFormat.ts` around lines
50 - 55, In the readAttributes function, the getAttribute call for
'data-time-format' uses a direct type assertion with `as TimeFormat` which
bypasses TypeScript type checking. Replace this unsafe cast by validating that
the retrieved attribute value is actually a valid TimeFormat value before using
it. Create a type guard or validation check that confirms the attribute value
matches one of the valid TimeFormat union values, and only apply the type
assertion after validation passes. This ensures type safety at runtime rather
than relying solely on the default case handling in downstream code.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/utils/timestamp.ts`:
- Around line 73-77: The frames calculation on line 76 uses Math.round(fps)
while the hours, minutes, and seconds calculations on lines 73-75 use the raw
fps value, creating an inconsistency that produces incorrect timecode output for
fractional frame rates like 29.97. Replace Math.round(fps) with fps in the
frames calculation to ensure all time components use the same FPS basis
throughout the timecode conversion logic.

---

Nitpick comments:
In
`@src/elements/content-sidebar/activity-feed-v2/__tests__/FeedItemRow.test.tsx`:
- Around line 60-64: The mockTimeFormat object is being mutated across multiple
tests but never reset between test runs, causing state leakage and making test
execution order-dependent. Add a beforeEach block that resets mockTimeFormat
back to its initial values (timeFormat: 'standard', fps: 24) before each test
runs to ensure consistent and isolated test behavior. This ensures the mock
object starts with known values for every test regardless of what previous tests
may have modified.

In `@src/elements/content-sidebar/activity-feed-v2/useTimeFormat.ts`:
- Around line 50-55: In the readAttributes function, the getAttribute call for
'data-time-format' uses a direct type assertion with `as TimeFormat` which
bypasses TypeScript type checking. Replace this unsafe cast by validating that
the retrieved attribute value is actually a valid TimeFormat value before using
it. Create a type guard or validation check that confirms the attribute value
matches one of the valid TimeFormat union values, and only apply the type
assertion after validation passes. This ensures type safety at runtime rather
than relying solely on the default case handling in downstream code.

In `@src/utils/__tests__/timestamp.test.js`:
- Around line 93-155: The test suite for convertMillisecondsToTimecode and
convertMillisecondsToFrames lacks coverage for fractional FPS values (such as
29.97), which can be passed as numbers from upstream data-fps parsing. Add at
least one test case within each describe block that tests a fractional FPS value
like 29.97 to ensure the conversion functions handle non-integer frame rates
correctly and prevent player/sidebar drift regressions. Include test cases with
typical fractional FPS values (29.97, 23.976) and verify that the timecode and
frame calculations remain accurate.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: af5d97fb-998e-4283-8020-8511d4ce4996

📥 Commits

Reviewing files that changed from the base of the PR and between 943e820 and 23e2093.

📒 Files selected for processing (9)
  • src/elements/content-sidebar/activity-feed-v2/ActivityFeedV2.tsx
  • src/elements/content-sidebar/activity-feed-v2/FeedItemRow.tsx
  • src/elements/content-sidebar/activity-feed-v2/__tests__/FeedItemRow.test.tsx
  • src/elements/content-sidebar/activity-feed-v2/__tests__/useTimeFormat.test.tsx
  • src/elements/content-sidebar/activity-feed-v2/__tests__/useVideoTimestamp.test.tsx
  • src/elements/content-sidebar/activity-feed-v2/useTimeFormat.ts
  • src/elements/content-sidebar/activity-feed-v2/useVideoTimestamp.ts
  • src/utils/__tests__/timestamp.test.js
  • src/utils/timestamp.ts

Comment thread src/utils/timestamp.ts
Comment on lines +73 to +77
const hours = Math.floor(totalFrames / (fps * 3600));
const minutes = Math.floor((totalFrames % (fps * 3600)) / (fps * 60));
const secs = Math.floor((totalFrames % (fps * 60)) / fps);
const frames = totalFrames % Math.round(fps);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Inconsistent FPS basis causes incorrect timecode for fractional frame rates.

Line 73-75 decomposes time using raw fps, but Line 76 computes frames using Math.round(fps). With fractional FPS (e.g., 29.97 from data-fps), this produces drift and mismatched HH:MM:SS:FF output relative to the player format.

Suggested fix
 const convertMillisecondsToTimecode = (timestampInMilliseconds: number, fps: number): string => {
     const seconds = timestampInMilliseconds && timestampInMilliseconds > 0 ? timestampInMilliseconds / 1000 : 0;
     const val = Number.isFinite(seconds) ? seconds : 0;
-    const totalFrames = Math.floor(val * fps);
+    const frameBase = Number.isFinite(fps) && fps > 0 ? Math.round(fps) : 24;
+    const totalFrames = Math.floor(val * frameBase);

-    const hours = Math.floor(totalFrames / (fps * 3600));
-    const minutes = Math.floor((totalFrames % (fps * 3600)) / (fps * 60));
-    const secs = Math.floor((totalFrames % (fps * 60)) / fps);
-    const frames = totalFrames % Math.round(fps);
+    const hours = Math.floor(totalFrames / (frameBase * 3600));
+    const minutes = Math.floor((totalFrames % (frameBase * 3600)) / (frameBase * 60));
+    const secs = Math.floor((totalFrames % (frameBase * 60)) / frameBase);
+    const frames = totalFrames % frameBase;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/utils/timestamp.ts` around lines 73 - 77, The frames calculation on line
76 uses Math.round(fps) while the hours, minutes, and seconds calculations on
lines 73-75 use the raw fps value, creating an inconsistency that produces
incorrect timecode output for fractional frame rates like 29.97. Replace
Math.round(fps) with fps in the frames calculation to ensure all time components
use the same FPS basis throughout the timecode conversion logic.

Sidebar comment timestamps (both the editor checkbox and posted comment
badges) now respect the time format selected in the video player controls
(standard, timecode, or frame numbers). Communication uses data attributes
on .bp-media-container observed via MutationObserver.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@kduncanhsu kduncanhsu force-pushed the kduncanhsu/sync-timestamp-to-comments branch from 23e2093 to c4307d0 Compare June 16, 2026 23:38

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/utils/timestamp.ts`:
- Around line 86-91: The convertMillisecondsToFrames function currently
validates the timestampInMilliseconds parameter but does not validate the fps
parameter. Add validation to check if fps is a valid positive number (not zero,
negative, NaN, or Infinity) and return 0 if the fps value is invalid. This will
prevent the calculation on line 90 from producing NaN, Infinity, or other
incorrect frame counts when fps is provided with invalid values.
- Around line 68-84: The convertMillisecondsToTimecode function does not
validate the fps parameter, which can lead to incorrect timecode calculations if
fps is zero, negative, NaN, or Infinity. Add validation at the beginning of the
function to ensure fps is a valid positive finite number, and return a default
timecode (such as "00:00:00:00") if it is not. This validation will also resolve
the Math.round inconsistency where fps is rounded only in the frames calculation
but not in the hours, minutes, and seconds calculations.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c675e84b-5bad-45cd-8a15-a43d28d20e37

📥 Commits

Reviewing files that changed from the base of the PR and between 23e2093 and c4307d0.

📒 Files selected for processing (9)
  • src/elements/content-sidebar/activity-feed-v2/ActivityFeedV2.tsx
  • src/elements/content-sidebar/activity-feed-v2/FeedItemRow.tsx
  • src/elements/content-sidebar/activity-feed-v2/__tests__/FeedItemRow.test.tsx
  • src/elements/content-sidebar/activity-feed-v2/__tests__/useTimeFormat.test.tsx
  • src/elements/content-sidebar/activity-feed-v2/__tests__/useVideoTimestamp.test.tsx
  • src/elements/content-sidebar/activity-feed-v2/useTimeFormat.ts
  • src/elements/content-sidebar/activity-feed-v2/useVideoTimestamp.ts
  • src/utils/__tests__/timestamp.test.js
  • src/utils/timestamp.ts
🚧 Files skipped from review as they are similar to previous changes (7)
  • src/elements/content-sidebar/activity-feed-v2/ActivityFeedV2.tsx
  • src/elements/content-sidebar/activity-feed-v2/useVideoTimestamp.ts
  • src/utils/tests/timestamp.test.js
  • src/elements/content-sidebar/activity-feed-v2/useTimeFormat.ts
  • src/elements/content-sidebar/activity-feed-v2/tests/useVideoTimestamp.test.tsx
  • src/elements/content-sidebar/activity-feed-v2/tests/FeedItemRow.test.tsx
  • src/elements/content-sidebar/activity-feed-v2/FeedItemRow.tsx

Comment thread src/utils/timestamp.ts
Comment on lines +68 to +84
const convertMillisecondsToTimecode = (timestampInMilliseconds: number, fps: number): string => {
const seconds = timestampInMilliseconds && timestampInMilliseconds > 0 ? timestampInMilliseconds / 1000 : 0;
const val = Number.isFinite(seconds) ? seconds : 0;
const totalFrames = Math.floor(val * fps);

const hours = Math.floor(totalFrames / (fps * 3600));
const minutes = Math.floor((totalFrames % (fps * 3600)) / (fps * 60));
const secs = Math.floor((totalFrames % (fps * 60)) / fps);
const frames = totalFrames % Math.round(fps);

const hh = hours.toString().padStart(2, '0');
const mm = minutes.toString().padStart(2, '0');
const ss = secs.toString().padStart(2, '0');
const ff = frames.toString().padStart(2, '0');

return `${hh}:${mm}:${ss}:${ff}`;
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Validate fps parameter to prevent incorrect timecode output.

Both fps parameter validation and the Math.round inconsistency flagged below will cause incorrect timecode calculations. If fps is zero, negative, NaN, or Infinity, division operations on lines 73-75 will produce Infinity, NaN, or incorrect results.

🛡️ Proposed fix to add fps validation
 const convertMillisecondsToTimecode = (timestampInMilliseconds: number, fps: number): string => {
     const seconds = timestampInMilliseconds && timestampInMilliseconds > 0 ? timestampInMilliseconds / 1000 : 0;
     const val = Number.isFinite(seconds) ? seconds : 0;
+    const validFps = Number.isFinite(fps) && fps > 0 ? fps : 24;
-    const totalFrames = Math.floor(val * fps);
+    const totalFrames = Math.floor(val * validFps);

-    const hours = Math.floor(totalFrames / (fps * 3600));
-    const minutes = Math.floor((totalFrames % (fps * 3600)) / (fps * 60));
-    const secs = Math.floor((totalFrames % (fps * 60)) / fps);
-    const frames = totalFrames % Math.round(fps);
+    const hours = Math.floor(totalFrames / (validFps * 3600));
+    const minutes = Math.floor((totalFrames % (validFps * 3600)) / (validFps * 60));
+    const secs = Math.floor((totalFrames % (validFps * 60)) / validFps);
+    const frames = totalFrames % validFps;

Note: This fix also resolves the Math.round(fps) inconsistency flagged separately.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const convertMillisecondsToTimecode = (timestampInMilliseconds: number, fps: number): string => {
const seconds = timestampInMilliseconds && timestampInMilliseconds > 0 ? timestampInMilliseconds / 1000 : 0;
const val = Number.isFinite(seconds) ? seconds : 0;
const totalFrames = Math.floor(val * fps);
const hours = Math.floor(totalFrames / (fps * 3600));
const minutes = Math.floor((totalFrames % (fps * 3600)) / (fps * 60));
const secs = Math.floor((totalFrames % (fps * 60)) / fps);
const frames = totalFrames % Math.round(fps);
const hh = hours.toString().padStart(2, '0');
const mm = minutes.toString().padStart(2, '0');
const ss = secs.toString().padStart(2, '0');
const ff = frames.toString().padStart(2, '0');
return `${hh}:${mm}:${ss}:${ff}`;
};
const convertMillisecondsToTimecode = (timestampInMilliseconds: number, fps: number): string => {
const seconds = timestampInMilliseconds && timestampInMilliseconds > 0 ? timestampInMilliseconds / 1000 : 0;
const val = Number.isFinite(seconds) ? seconds : 0;
const validFps = Number.isFinite(fps) && fps > 0 ? fps : 24;
const totalFrames = Math.floor(val * validFps);
const hours = Math.floor(totalFrames / (validFps * 3600));
const minutes = Math.floor((totalFrames % (validFps * 3600)) / (validFps * 60));
const secs = Math.floor((totalFrames % (validFps * 60)) / validFps);
const frames = totalFrames % validFps;
const hh = hours.toString().padStart(2, '0');
const mm = minutes.toString().padStart(2, '0');
const ss = secs.toString().padStart(2, '0');
const ff = frames.toString().padStart(2, '0');
return `${hh}:${mm}:${ss}:${ff}`;
};
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/utils/timestamp.ts` around lines 68 - 84, The
convertMillisecondsToTimecode function does not validate the fps parameter,
which can lead to incorrect timecode calculations if fps is zero, negative, NaN,
or Infinity. Add validation at the beginning of the function to ensure fps is a
valid positive finite number, and return a default timecode (such as
"00:00:00:00") if it is not. This validation will also resolve the Math.round
inconsistency where fps is rounded only in the frames calculation but not in the
hours, minutes, and seconds calculations.

Comment thread src/utils/timestamp.ts
Comment on lines +86 to +91
const convertMillisecondsToFrames = (timestampInMilliseconds: number, fps: number): number => {
if (!timestampInMilliseconds || timestampInMilliseconds < 0) {
return 0;
}
return Math.floor((timestampInMilliseconds / 1000) * fps);
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Validate fps parameter to prevent incorrect frame counts.

If fps is zero, negative, NaN, or Infinity, line 90 will produce incorrect frame counts (NaN, Infinity, or negative values).

🛡️ Proposed fix to add fps validation
 const convertMillisecondsToFrames = (timestampInMilliseconds: number, fps: number): number => {
     if (!timestampInMilliseconds || timestampInMilliseconds < 0) {
         return 0;
     }
-    return Math.floor((timestampInMilliseconds / 1000) * fps);
+    const validFps = Number.isFinite(fps) && fps > 0 ? fps : 24;
+    return Math.floor((timestampInMilliseconds / 1000) * validFps);
 };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const convertMillisecondsToFrames = (timestampInMilliseconds: number, fps: number): number => {
if (!timestampInMilliseconds || timestampInMilliseconds < 0) {
return 0;
}
return Math.floor((timestampInMilliseconds / 1000) * fps);
};
const convertMillisecondsToFrames = (timestampInMilliseconds: number, fps: number): number => {
if (!timestampInMilliseconds || timestampInMilliseconds < 0) {
return 0;
}
const validFps = Number.isFinite(fps) && fps > 0 ? fps : 24;
return Math.floor((timestampInMilliseconds / 1000) * validFps);
};
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/utils/timestamp.ts` around lines 86 - 91, The convertMillisecondsToFrames
function currently validates the timestampInMilliseconds parameter but does not
validate the fps parameter. Add validation to check if fps is a valid positive
number (not zero, negative, NaN, or Infinity) and return 0 if the fps value is
invalid. This will prevent the calculation on line 90 from producing NaN,
Infinity, or other incorrect frame counts when fps is provided with invalid
values.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants