diff --git a/src/app/globals.css b/src/app/globals.css index 7db49485..18e46776 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -355,4 +355,20 @@ to { mask-size: 350vmax; } -} \ No newline at end of file +} + +/* 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%; +} diff --git a/src/components/VideoPlayer.tsx b/src/components/VideoPlayer.tsx new file mode 100644 index 00000000..25837374 --- /dev/null +++ b/src/components/VideoPlayer.tsx @@ -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>; + contentId: number; +}) => { + const searchParams = useSearchParams(); + + const videoRef = useRef(null); + const playerRef = useRef(null); + const [player, setPlayer] = useState(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 ; + } + + return ( +
+ +
+
+ ); +}; diff --git a/src/components/VideoPlayer2.tsx b/src/components/VideoPlayer2.tsx index 20521be9..23f0f28d 100644 --- a/src/components/VideoPlayer2.tsx +++ b/src/components/VideoPlayer2.tsx @@ -484,7 +484,7 @@ export const VideoPlayer: FunctionComponent = ({ return (
diff --git a/src/components/VideoPlayerSegment.tsx b/src/components/VideoPlayerSegment.tsx index f0df83aa..ba5d112b 100644 --- a/src/components/VideoPlayerSegment.tsx +++ b/src/components/VideoPlayerSegment.tsx @@ -106,6 +106,7 @@ export const VideoPlayerSegment: FunctionComponent = ({ appxVideoId={appxVideoId} onVideoEnd={onVideoEnd} onReady={handlePlayerReady} + className="w-full h-auto max-w-full max-h-full" />