Skip to content

Commit

Permalink
Fix video frame responsiveness issue
Browse files Browse the repository at this point in the history
Related to code100x#1577

Update video player to be fully responsive

* Modify `src/app/globals.css` to ensure the video player is fully responsive for different screen sizes and handle the video frame's width and height correctly.
* Change `src/components/VideoPlayer2.tsx` to remove the fixed maximum width of 850px and adjust the video player container to take full width and height.
* Update `src/components/VideoPlayerSegment.tsx` to include styles and configurations to make the video frame responsive.
* Add `src/components/VideoPlayer.tsx` to handle different screen sizes and ensure the video frame takes its full width and height.
  • Loading branch information
vishwamartur committed Nov 25, 2024
1 parent ec7c431 commit f6f4bc2
Show file tree
Hide file tree
Showing 4 changed files with 190 additions and 2 deletions.
18 changes: 17 additions & 1 deletion src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -355,4 +355,20 @@
to {
mask-size: 350vmax;
}
}
}

/* Ensure the video player is fully responsive for different screen sizes */
.video-js {
width: 100%;
height: auto;
max-width: 100%;
max-height: 100%;
}

/* Handle the video frame's width and height correctly */
.video-frame {
width: 100%;
height: auto;
max-width: 100%;
max-height: 100%;
}
171 changes: 171 additions & 0 deletions src/components/VideoPlayer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
'use client';
import React, { useEffect, useRef, useState } from 'react';
import VideoPlayerControls from './videoControls';
import videojs from 'video.js';
import { Segment, handleMarkAsCompleted } from '@/lib/utils';
import Player from 'video.js/dist/types/player';
import 'video.js/dist/video-js.css';
import { useSearchParams } from 'next/navigation';
import { YoutubeRenderer } from '../YoutubeRenderer';

export const VideoPlayer = ({
options,
subtitles,
onVideoEnd,
segments,
setQuality,
contentId,
}: {
options: any;
subtitles: string;
onVideoEnd: () => void;
segments: Segment[];
setQuality: React.Dispatch<React.SetStateAction<string>>;
contentId: number;
}) => {
const searchParams = useSearchParams();

const videoRef = useRef<HTMLDivElement>(null);
const playerRef = useRef<Player | null>(null);
const [player, setPlayer] = useState<any>(null);

useEffect(() => {
const t = searchParams.get('timestamp');
if (contentId && player && !t) {
fetch(`/api/course/videoProgress?contentId=${contentId}`).then(
async (res) => {
const json = await res.json();
player.currentTime(json.progress || 0);
},
);
}
}, [contentId, player]);

useEffect(() => {
if (!player) {
return;
}
let interval = 0;

const handleVideoProgress = () => {
if (!player) {
return;
}
interval = window.setInterval(
async () => {
if (!player) {
return;
}
if (player?.paused()) {
return;
}
const currentTime = player.currentTime();
if (currentTime <= 20) {
return;
}
await fetch('/api/course/videoProgress', {
body: JSON.stringify({
currentTimestamp: currentTime,
contentId,
}),
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
});
},
Math.ceil((100 * 1000) / player.playbackRate()),
);
};
const handleVideoEnded = (interval: number) => {
handleMarkAsCompleted(true, contentId);
window.clearInterval(interval);
onVideoEnd();
};

player.on('play', handleVideoProgress);
player.on('ended', () => handleVideoEnded(interval));
return () => {
window.clearInterval(interval);
};
}, [player, contentId]);

useEffect(() => {
if (!playerRef.current && videoRef.current) {
const videoElement = videoRef.current.appendChild(
document.createElement('video-js'),
);
videoElement.classList.add('vjs-big-play-centered');

const player: any = (playerRef.current = videojs(
videoElement,
options,
() => {
setPlayer(player);

player?.eme();

// @ts-ignore
this.on('keystatuschange', (event: any) => {
console.log('event: ', event);
});
},
));
}
}, [options]);

useEffect(() => {
if (player) {
const currentTime = player.currentTime();
player.src(options?.sources[0]);
player.currentTime(currentTime);
}
}, [options?.sources[0]]);

useEffect(() => {
const playerInstance = playerRef?.current;

return () => {
if (playerInstance) {
playerInstance.dispose();
playerRef.current = null;
}
};
}, []);

useEffect(() => {
const t = searchParams.get('timestamp');

if (player && t) {
player.currentTime(parseInt(t, 10));
}
}, [searchParams, player]);

const isYoutubeUrl = (url: string) => {
const regex = /^https:\/\/www\.youtube\.com\/embed\/[a-zA-Z0-9_-]+/;
return regex.test(url);
};

const vidUrl = options.sources[0].src;

if (isYoutubeUrl(vidUrl)) {
return <YoutubeRenderer url={vidUrl} />;
}

return (
<div
id="videoContainer"
data-vjs-player
className="group/v-container relative grid select-none overflow-hidden rounded-md md:max-w-[calc(100vw-3rem)] 2xl:max-w-[calc(100vw-17rem)]"
>
<VideoPlayerControls
player={player}
onVideoEnd={onVideoEnd}
segments={segments}
setQuality={setQuality}
subtitles={subtitles}
/>
<div ref={videoRef} className="self-center"></div>
</div>
);
};
2 changes: 1 addition & 1 deletion src/components/VideoPlayer2.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -484,7 +484,7 @@ export const VideoPlayer: FunctionComponent<VideoPlayerProps> = ({
return (
<div
data-vjs-player
style={{ maxWidth: '850px', margin: '0 auto', width: '100%' }}
style={{ width: '100%', height: 'auto' }}
>
<div ref={videoRef} style={{ width: '100%', height: 'auto' }} />
</div>
Expand Down
1 change: 1 addition & 0 deletions src/components/VideoPlayerSegment.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ export const VideoPlayerSegment: FunctionComponent<VideoProps> = ({
appxVideoId={appxVideoId}
onVideoEnd={onVideoEnd}
onReady={handlePlayerReady}
className="w-full h-auto max-w-full max-h-full"
/>
</div>
</div>
Expand Down

0 comments on commit f6f4bc2

Please sign in to comment.