Skip to content

Fix/videoplayer bugs#1339

Open
MayankSharma-ops wants to merge 6 commits into
AOSSIE-Org:mainfrom
MayankSharma-ops:fix/videoplayer-bugs
Open

Fix/videoplayer bugs#1339
MayankSharma-ops wants to merge 6 commits into
AOSSIE-Org:mainfrom
MayankSharma-ops:fix/videoplayer-bugs

Conversation

@MayankSharma-ops

@MayankSharma-ops MayankSharma-ops commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Addressed Issues:

Fixes #1329

Screenshots/Recordings:

No changes were made to the overall UI layout or styling. However, functional interface fixes are visible to the user:

  • Time display now correctly renders 0:00 / 0:00 (and updates on load) instead of NaN:NaN.
  • Play/Pause toggle now correctly resets to "Play" when the video ends.
  • Volume slider now correctly toggles the mute icon/state when dragging.
  • Fullscreen toggle now correctly updates between Maximize/Minimize icons when exiting.

Additional Notes:

This PR resolves all five desync/rendering bugs in the NetflixStylePlayer component:

  1. Local File Loading: Configured the video element's source to use convertFileSrc for Tauri compatibility.
  2. Fullscreen Desync: Listened to the fullscreenchange event on the document level, syncing isFullscreen status correctly when exited via Esc.
  3. NaN Display: Added state hooks for currentTime and duration and formatted the output using formatTime which falls back to 0:00 for non-finite values before video metadata loads. Added onLoadedMetadata and onDurationChange to update these states reactively.
  4. Muted State Desync: Adjusted handleVolumeChange to correctly unmute the video state and reference (videoRef.current.muted = false) when the volume slider is moved to a value greater than 0.
  5. Playback State Desync: Registered onEnded to automatically reset the playing state back to false when video playback ends.

Also added a complete Jest unit test suite covering all 5 scenarios to prevent regressions.

AI Usage Disclosure:

Check one of the checkboxes below:

  • This PR does not contain AI-generated code at all.
  • This PR contains AI-generated code. I have read the AI Usage Policy and this PR complies with this policy. I have tested the code locally and I am responsible for it.

I have used the following AI models and tools: Gemini 3.5 Flash (via Antigravity IDE)

Checklist

  • My PR addresses a single issue, fixes a single bug or makes a single improvement.
  • My code follows the project's code style and conventions
  • If applicable, I have made corresponding changes or additions to the documentation
  • If applicable, I have made corresponding changes or additions to tests
  • My changes generate no new warnings or errors
  • I have joined the Discord server and I will share a link to this PR with the project maintainers there
  • My read the Contribution Guidelines
  • Once I submit my PR, CodeRabbit AI will automatically review it and I will address CodeRabbit's comments.
  • I have filled this PR template completely and carefully, and I understand that my PR may be closed without review otherwise.

Summary by CodeRabbit

  • New Features

    • Video player now reliably tracks and displays elapsed time and total duration during playback and seeking
    • Volume controls now stay in sync with mute/unmute state for consistent behavior
    • Enhanced fullscreen handling for smoother, more accurate UI updates
  • Bug Fixes

    • Improved time formatting to safely handle edge cases (e.g., missing/invalid duration)
  • Tests

    • Added a comprehensive test suite for the Netflix-style video player (play/pause, fullscreen, time, volume, and seek behavior)
  • Security

    • Updated Content Security Policy media source formatting

@github-actions github-actions Bot added bug Something isn't working frontend labels Jun 22, 2026
@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b1e728ba-1fd4-4d87-ac3b-b6d5e9a8ce38

📥 Commits

Reviewing files that changed from the base of the PR and between 51d457e and b1584de.

📒 Files selected for processing (1)
  • frontend/src/components/VideoPlayer/__tests__/NetflixStylePlayer.test.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/src/components/VideoPlayer/tests/NetflixStylePlayer.test.tsx

Walkthrough

NetflixStylePlayer is updated to track currentTime and duration via React state, convert videoSrc through convertFileSrc for Tauri, guard formatTime against NaN/non-finite inputs, listen for fullscreenchange events, and sync muted state with the volume slider. A new Jest test suite covering all five fixes is added. A CSP syntax correction is made separately.

Changes

NetflixStylePlayer Bug Fixes and Tests

Layer / File(s) Summary
State setup, imports, and src memoization
frontend/src/components/VideoPlayer/NetflixStylePlayer.tsx
Imports useMemo and convertFileSrc from Tauri. Introduces currentTime and duration state, and creates a memoized resolvedSrc that wraps videoSrc with convertFileSrc for file loading in Tauri.
Event handlers and state synchronization
frontend/src/components/VideoPlayer/NetflixStylePlayer.tsx
Adds fullscreenchange event listener with proper cleanup. Extends formatTime to return 0:00 for NaN/non-finite inputs. Introduces handleLoadedMetadata and handleDurationChange to update duration state. Updates handleProgress to set currentTime. Reworks progress-bar click to clamp seek time using finite duration. Updates skipTime and volume handlers to sync video element's muted property with React state.
Video element wiring and time display
frontend/src/components/VideoPlayer/NetflixStylePlayer.tsx
Switches <video src> from raw videoSrc to memoized resolvedSrc. Wires additional media event handlers (onLoadedMetadata, onDurationChange, onPlay, onPause, onEnded) to synchronize playback state. Updates time display to render from React state (currentTime/duration) instead of video element properties.
Jest test suite
frontend/src/components/VideoPlayer/__tests__/NetflixStylePlayer.test.tsx
Complete test file mocking Tauri convertFileSrc, Slider, and lucide-react icons. Stubs HTMLMediaElement play/pause and fullscreen APIs with proper cleanup. Verifies: (1) src is converted via convertFileSrc, (2) fullscreenchange toggles fullscreen icon states, (3) time display initializes as 0:00 / 0:00 and updates after loadedmetadata, (4) volume slider unmutes video and toggles muted icon, (5) play click shows pause icon and ended event restores play icon, and (6) CSP media-src directive whitelists asset: and http://asset.localhost.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested labels

TypeScript/JavaScript

🐇 Five little bugs went hopping away,
NaN:NaN no longer ruins the day!
convertFileSrc lights the Tauri path,
fullscreenchange spares us all the math.
State and tests guard every flow—
a carrot for fixes made just so! 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR addresses all five bugs from issue #1329: convertFileSrc for Tauri [1], fullscreenchange listener [2], currentTime/duration state for NaN fix [3], volume unmute logic [4], and onEnded callback [5]. However, the critical CSP directive update in tauri.conf.json is incomplete per reviewer feedback. Complete the CSP media-src directive update in tauri.conf.json to include 'asset: http://asset.localhost' as required by reviewer VanshajPoonia to unblock local file loading in the actual Tauri application.
Title check ❓ Inconclusive The title is vague and generic, using 'Fix/videoplayer bugs' which describes the action without specifying which bugs or the primary change. Use a more specific title like 'Fix NetflixStylePlayer state sync issues' or list the primary bug being addressed to make the changeset clear.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Out of Scope Changes check ✅ Passed All changes are directly scoped to issue #1329: component refactoring for the five bugs, comprehensive test coverage, and CSP configuration updates are all within scope.

✏️ 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.

@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 `@frontend/src/components/VideoPlayer/__tests__/NetflixStylePlayer.test.tsx`:
- Around line 11-21: The Slider mock component in the test file has its props
parameter typed as `any`, which weakens type safety. Replace the `any` type
annotation in the Slider function signature with an explicit interface or type
that properly defines all the props being used: onValueChange (function
accepting an array of numbers), value (array of numbers), min (number), max
(number), and step (number). This will ensure proper contract checking and align
with the coding guidelines requiring explicit types instead of `any`.

In `@frontend/src/components/VideoPlayer/NetflixStylePlayer.tsx`:
- Around line 109-117: The newTime value calculated in the
handleProgressBarClick function is not being validated or clamped to valid media
bounds before being assigned to videoRef.current.currentTime. This can result in
out-of-range seek values (negative or exceeding duration). Before assigning the
newTime to videoRef.current.currentTime, clamp it to a valid range between 0 and
videoRef.current.duration using a Math.min and Math.max approach. Apply the same
clamping logic to the other seek function mentioned in the comment (around lines
129-134) to ensure all seek operations produce valid, bounded time values.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 1d9ef488-f1bc-4490-b0d9-6aaa60d29715

📥 Commits

Reviewing files that changed from the base of the PR and between b3eee2c and 4649a86.

📒 Files selected for processing (2)
  • frontend/src/components/VideoPlayer/NetflixStylePlayer.tsx
  • frontend/src/components/VideoPlayer/__tests__/NetflixStylePlayer.test.tsx

Comment thread frontend/src/components/VideoPlayer/__tests__/NetflixStylePlayer.test.tsx Outdated
Comment thread frontend/src/components/VideoPlayer/NetflixStylePlayer.tsx
@VanshajPoonia

VanshajPoonia commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Hey, thanks for picking this up. I went through the diff and tested the asset protocol behavior locally. Most of it looks good, but I think there's one blocking issue with the local file fix, plus a few smaller suggestions.

The main thing is that bug 1 (local file loading) needs a CSP change too, not just convertFileSrc.

convertFileSrc returns an asset protocol URL (asset://localhost/... on macOS and Linux, or http://asset.localhost/... on Windows). Whether the video element is allowed to load from that URL is controlled by the media-src directive in the CSP. Right now in frontend/src-tauri/tauri.conf.json the policy is:

default-src 'self'; img-src 'self' data: asset: http://asset.localhost; media-src 'self' blob: data:; connect-src 'self' ipc: ...

img-src already lists asset: http://asset.localhost, but media-src only has 'self' blob: data:. So the asset protocol is allowed for images but not for media, and the webview blocks the video with something like:

Refused to load media from 'asset://localhost/...' because it violates the following Content Security Policy directive: "media-src 'self' blob: data:".

That is why images load through convertFileSrc today but a video won't. In Tauri each CSP directive has to whitelist the asset protocol separately, and media-src never got it because there was no video feature before.

The fix is a one line change in tauri.conf.json, mirroring img-src:

media-src 'self' blob: data: asset: http://asset.localhost;

One thing worth checking: this is the part the unit tests can't catch, since jsdom doesn't enforce CSP or implement the asset protocol, so a green test suite won't prove the video actually loads. The other four fixes are visible in a normal browser, but bug 1 only shows up in the real webview. Could you run npm run tauri dev, load an actual local video file, and confirm it plays with no media-src error in the devtools console? Right now the code looks right but the video would be blocked at runtime.

A few smaller, non blocking things:

  1. togglePlay has a redundant state update now. It still does setIsPlaying(!isPlaying) manually, but onPlay and onPause also update isPlaying. They usually agree, but video.play() returns a promise that can reject (autoplay policy, or "play() interrupted by pause()" on fast toggling). If it rejects, onPlay never fires but the manual setIsPlaying(true) already ran, so the icon would show playing while the video isn't. Since the events are already wired, it would be cleaner to let them own the state:
const togglePlay = () => {
  const video = videoRef.current;
  if (!video) return;
  if (video.paused) {
    video.play().catch(() => {});
  } else {
    video.pause();
  }
};
  1. convertFileSrc(videoSrc) is called inline in render, so it runs on every re-render, and there are a lot of those during playback because onTimeUpdate updates state continuously. Wrapping it in useMemo avoids the repeated work:
const resolvedSrc = useMemo(() => convertFileSrc(videoSrc), [videoSrc]);
  1. In formatTime, the guard uses the global isNaN and isFinite, which coerce their argument. Number.isFinite is safer, doesn't coerce, and already returns false for NaN, so you can drop the separate isNaN check:
if (!Number.isFinite(timeInSeconds)) {
  return '0:00';
}
  1. Small structural thing: the fullscreenchange listener is registered inside the controls visibility useEffect along with the mousemove handlers. It works fine since the deps are empty, but a separate effect for fullscreenchange would keep the two concerns apart and read a bit cleaner. Purely optional.

The only thing I would actually block on is the media-src CSP change. Without it bug 1 isn't really fixed in the running app even though the component code is correct. Everything else is optional polish. Once that line is added and a local file plays in tauri dev, this looks good.

@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

🤖 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 `@frontend/src-tauri/tauri.conf.json`:
- Line 69: Add an automated test that reads the tauri.conf.json file and
validates the Content Security Policy configuration. The test should extract the
security.csp value and assert that the media-src directive contains both asset:
and http://asset.localhost to prevent regressions in Tauri media loading
functionality. This test should be included in the Jest test suite alongside
other configuration validation tests to ensure the CSP contract for media
playback remains protected against future changes.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 4e6f5bd4-0fe5-40d6-8f48-0ca2c0809261

📥 Commits

Reviewing files that changed from the base of the PR and between 4649a86 and 51d457e.

📒 Files selected for processing (3)
  • frontend/src-tauri/tauri.conf.json
  • frontend/src/components/VideoPlayer/NetflixStylePlayer.tsx
  • frontend/src/components/VideoPlayer/__tests__/NetflixStylePlayer.test.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • frontend/src/components/VideoPlayer/NetflixStylePlayer.tsx
  • frontend/src/components/VideoPlayer/tests/NetflixStylePlayer.test.tsx

Comment thread frontend/src-tauri/tauri.conf.json

@rohan-pandeyy rohan-pandeyy left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM!

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

Labels

bug Something isn't working frontend

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: NetflixStylePlayer control, volume, and fullscreen desync issues

3 participants