From 851fd342275ae477a62bb80c08635a3d0219be6a Mon Sep 17 00:00:00 2001 From: Rajgupta36 Date: Sun, 26 May 2024 16:42:31 +0530 Subject: [PATCH 1/3] added m3u8 and mpd video samples --- prisma/seed.ts | 192 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 161 insertions(+), 31 deletions(-) diff --git a/prisma/seed.ts b/prisma/seed.ts index 80e40cd92..2ba6b52fc 100644 --- a/prisma/seed.ts +++ b/prisma/seed.ts @@ -137,6 +137,26 @@ async function seedContent() { parentId: 1, commentsCount: 0, }, + { + id: 4, + type: 'video', + title: 'test video 2 for week 1', + hidden: false, + thumbnail: + 'https://appx-recordings.s3.ap-south-1.amazonaws.com/drm/100x/images/week-1-orientation.jpg', + parentId: 1, + commentsCount: 0, + }, + { + id: 5, + type: 'video', + title: 'test video-3 for week 1', + hidden: false, + thumbnail: + 'https://appx-recordings.s3.ap-south-1.amazonaws.com/drm/100x/images/week-1-orientation.jpg', + parentId: 1, + commentsCount: 0, + }, ]; try { await db.content.createMany({ data: content }); @@ -177,37 +197,147 @@ async function seedNotionMetadata() { async function seedVideoMetadata() { try { - await db.videoMetadata.create({ - data: { - id: 1, - contentId: 3, - video_1080p_mp4_1: 'https://www.w3schools.com/html/mov_bbb.mp4', - video_1080p_mp4_2: 'https://www.w3schools.com/html/mov_bbb.mp4', - video_1080p_mp4_3: 'https://www.w3schools.com/html/mov_bbb.mp4', - video_1080p_mp4_4: 'https://www.w3schools.com/html/mov_bbb.mp4', - video_1080p_1: 'https://www.w3schools.com/html/mov_bbb.mp4', - video_1080p_2: 'https://www.w3schools.com/html/mov_bbb.mp4', - video_1080p_3: 'https://www.w3schools.com/html/mov_bbb.mp4', - video_1080p_4: 'https://www.w3schools.com/html/mov_bbb.mp4', - video_720p_mp4_1: 'https://www.w3schools.com/html/mov_bbb.mp4', - video_720p_mp4_2: 'https://www.w3schools.com/html/mov_bbb.mp4', - video_720p_mp4_3: 'https://www.w3schools.com/html/mov_bbb.mp4', - video_720p_mp4_4: 'https://www.w3schools.com/html/mov_bbb.mp4', - video_720p_1: 'https://www.w3schools.com/html/mov_bbb.mp4', - video_720p_2: 'https://www.w3schools.com/html/mov_bbb.mp4', - video_720p_3: 'https://www.w3schools.com/html/mov_bbb.mp4', - video_720p_4: 'https://www.w3schools.com/html/mov_bbb.mp4', - video_360p_mp4_1: 'https://www.w3schools.com/html/mov_bbb.mp4', - video_360p_mp4_2: 'https://www.w3schools.com/html/mov_bbb.mp4', - video_360p_mp4_3: 'https://www.w3schools.com/html/mov_bbb.mp4', - video_360p_mp4_4: 'https://www.w3schools.com/html/mov_bbb.mp4', - video_360p_1: 'https://www.w3schools.com/html/mov_bbb.mp4', - video_360p_2: 'https://www.w3schools.com/html/mov_bbb.mp4', - video_360p_3: 'https://www.w3schools.com/html/mov_bbb.mp4', - video_360p_4: 'https://www.w3schools.com/html/mov_bbb.mp4', - slides: - 'https://appx-recordings.s3.ap-south-1.amazonaws.com/drm/100x/slides/Loops%2C+callbacks.pdf', - }, + await db.videoMetadata.createMany({ + data: [ + { + id: 1, + contentId: 3, + video_1080p_mp4_1: 'https://www.w3schools.com/html/mov_bbb.mp4', + video_1080p_mp4_2: 'https://www.w3schools.com/html/mov_bbb.mp4', + video_1080p_mp4_3: 'https://www.w3schools.com/html/mov_bbb.mp4', + video_1080p_mp4_4: 'https://www.w3schools.com/html/mov_bbb.mp4', + video_1080p_1: 'https://www.w3schools.com/html/mov_bbb.mp4', + video_1080p_2: 'https://www.w3schools.com/html/mov_bbb.mp4', + video_1080p_3: 'https://www.w3schools.com/html/mov_bbb.mp4', + video_1080p_4: 'https://www.w3schools.com/html/mov_bbb.mp4', + video_720p_mp4_1: 'https://www.w3schools.com/html/mov_bbb.mp4', + video_720p_mp4_2: 'https://www.w3schools.com/html/mov_bbb.mp4', + video_720p_mp4_3: 'https://www.w3schools.com/html/mov_bbb.mp4', + video_720p_mp4_4: 'https://www.w3schools.com/html/mov_bbb.mp4', + video_720p_1: 'https://www.w3schools.com/html/mov_bbb.mp4', + video_720p_2: 'https://www.w3schools.com/html/mov_bbb.mp4', + video_720p_3: 'https://www.w3schools.com/html/mov_bbb.mp4', + video_720p_4: 'https://www.w3schools.com/html/mov_bbb.mp4', + video_360p_mp4_1: 'https://www.w3schools.com/html/mov_bbb.mp4', + video_360p_mp4_2: 'https://www.w3schools.com/html/mov_bbb.mp4', + video_360p_mp4_3: 'https://www.w3schools.com/html/mov_bbb.mp4', + video_360p_mp4_4: 'https://www.w3schools.com/html/mov_bbb.mp4', + video_360p_1: 'https://www.w3schools.com/html/mov_bbb.mp4', + video_360p_2: 'https://www.w3schools.com/html/mov_bbb.mp4', + video_360p_3: 'https://www.w3schools.com/html/mov_bbb.mp4', + video_360p_4: 'https://www.w3schools.com/html/mov_bbb.mp4', + slides: + 'https://appx-recordings.s3.ap-south-1.amazonaws.com/drm/100x/slides/Loops%2C+callbacks.pdf', + }, + { + id: 2, + contentId: 4, + video_1080p_mp4_1: + 'https://live-par-2-cdn-alt.livepush.io/live/bigbuckbunnyclip/index.m3u8', + video_1080p_mp4_2: + 'https://live-par-2-cdn-alt.livepush.io/live/bigbuckbunnyclip/index.m3u8', + video_1080p_mp4_3: + 'https://live-par-2-cdn-alt.livepush.io/live/bigbuckbunnyclip/index.m3u8', + video_1080p_mp4_4: + 'https://live-par-2-cdn-alt.livepush.io/live/bigbuckbunnyclip/index.m3u8', + video_1080p_1: + 'https://live-par-2-cdn-alt.livepush.io/live/bigbuckbunnyclip/index.m3u8', + video_1080p_2: + 'https://live-par-2-cdn-alt.livepush.io/live/bigbuckbunnyclip/index.m3u8', + video_1080p_3: + 'https://live-par-2-cdn-alt.livepush.io/live/bigbuckbunnyclip/index.m3u8', + video_1080p_4: + 'https://live-par-2-cdn-alt.livepush.io/live/bigbuckbunnyclip/index.m3u8', + video_720p_mp4_1: + 'https://live-par-2-cdn-alt.livepush.io/live/bigbuckbunnyclip/index.m3u8', + video_720p_mp4_2: + 'https://live-par-2-cdn-alt.livepush.io/live/bigbuckbunnyclip/index.m3u8', + video_720p_mp4_3: + 'https://live-par-2-cdn-alt.livepush.io/live/bigbuckbunnyclip/index.m3u8', + video_720p_mp4_4: + 'https://live-par-2-cdn-alt.livepush.io/live/bigbuckbunnyclip/index.m3u8', + video_720p_1: + 'https://live-par-2-cdn-alt.livepush.io/live/bigbuckbunnyclip/index.m3u8', + video_720p_2: + 'https://live-par-2-cdn-alt.livepush.io/live/bigbuckbunnyclip/index.m3u8', + video_720p_3: + 'https://live-par-2-cdn-alt.livepush.io/live/bigbuckbunnyclip/index.m3u8', + video_720p_4: + 'https://live-par-2-cdn-alt.livepush.io/live/bigbuckbunnyclip/index.m3u8', + video_360p_mp4_1: + 'https://live-par-2-cdn-alt.livepush.io/live/bigbuckbunnyclip/index.m3u8', + video_360p_mp4_2: + 'https://live-par-2-cdn-alt.livepush.io/live/bigbuckbunnyclip/index.m3u8', + video_360p_mp4_3: + 'https://live-par-2-cdn-alt.livepush.io/live/bigbuckbunnyclip/index.m3u8', + video_360p_mp4_4: + 'https://live-par-2-cdn-alt.livepush.io/live/bigbuckbunnyclip/index.m3u8', + video_360p_1: + 'https://live-par-2-cdn-alt.livepush.io/live/bigbuckbunnyclip/index.m3u8', + video_360p_2: + 'https://live-par-2-cdn-alt.livepush.io/live/bigbuckbunnyclip/index.m3u8', + video_360p_3: + 'https://live-par-2-cdn-alt.livepush.io/live/bigbuckbunnyclip/index.m3u8', + video_360p_4: + 'https://live-par-2-cdn-alt.livepush.io/live/bigbuckbunnyclip/index.m3u8', + slides: + 'https://appx-recordings.s3.ap-south-1.amazonaws.com/drm/100x/slides/Loops%2C+callbacks.pdf', + }, + { + id: 3, + contentId: 5, + video_1080p_mp4_1: + 'https://bitmovin-a.akamaihd.net/content/MI201109210084_1/mpds/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.mpd', + video_1080p_mp4_2: + 'https://bitmovin-a.akamaihd.net/content/MI201109210084_1/mpds/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.mpd', + video_1080p_mp4_3: + 'https://bitmovin-a.akamaihd.net/content/MI201109210084_1/mpds/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.mpd', + video_1080p_mp4_4: + 'https://bitmovin-a.akamaihd.net/content/MI201109210084_1/mpds/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.mpd', + video_1080p_1: + 'https://bitmovin-a.akamaihd.net/content/MI201109210084_1/mpds/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.mpd', + video_1080p_2: + 'https://bitmovin-a.akamaihd.net/content/MI201109210084_1/mpds/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.mpd', + video_1080p_3: + 'https://bitmovin-a.akamaihd.net/content/MI201109210084_1/mpds/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.mpd', + video_1080p_4: + 'https://bitmovin-a.akamaihd.net/content/MI201109210084_1/mpds/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.mpd', + video_720p_mp4_1: + 'https://bitmovin-a.akamaihd.net/content/MI201109210084_1/mpds/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.mpd', + video_720p_mp4_2: + 'https://bitmovin-a.akamaihd.net/content/MI201109210084_1/mpds/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.mpd', + video_720p_mp4_3: + 'https://bitmovin-a.akamaihd.net/content/MI201109210084_1/mpds/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.mpd', + video_720p_mp4_4: + 'https://bitmovin-a.akamaihd.net/content/MI201109210084_1/mpds/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.mpd', + video_720p_1: + 'https://bitmovin-a.akamaihd.net/content/MI201109210084_1/mpds/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.mpd', + video_720p_2: + 'https://bitmovin-a.akamaihd.net/content/MI201109210084_1/mpds/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.mpd', + video_720p_3: + 'https://bitmovin-a.akamaihd.net/content/MI201109210084_1/mpds/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.mpd', + video_720p_4: + 'https://bitmovin-a.akamaihd.net/content/MI201109210084_1/mpds/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.mpd', + video_360p_mp4_1: + 'https://bitmovin-a.akamaihd.net/content/MI201109210084_1/mpds/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.mpd', + video_360p_mp4_2: + 'https://bitmovin-a.akamaihd.net/content/MI201109210084_1/mpds/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.mpd', + video_360p_mp4_3: + 'https://bitmovin-a.akamaihd.net/content/MI201109210084_1/mpds/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.mpd', + video_360p_mp4_4: + 'https://bitmovin-a.akamaihd.net/content/MI201109210084_1/mpds/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.mpd', + video_360p_1: + 'https://bitmovin-a.akamaihd.net/content/MI201109210084_1/mpds/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.mpd', + video_360p_2: + 'https://bitmovin-a.akamaihd.net/content/MI201109210084_1/mpds/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.mpd', + video_360p_3: + 'https://bitmovin-a.akamaihd.net/content/MI201109210084_1/mpds/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.mpd', + video_360p_4: + 'https://bitmovin-a.akamaihd.net/content/MI201109210084_1/mpds/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.mpd', + slides: + 'https://appx-recordings.s3.ap-south-1.amazonaws.com/drm/100x/slides/Loops%2C+callbacks.pdf', + }, + ], }); } catch (error) { console.error('Error seeding video metadata:', error); From 537be0da6ea6e03342274cd23e4e40ab602332c0 Mon Sep 17 00:00:00 2001 From: Rajgupta36 Date: Sun, 26 May 2024 17:13:08 +0530 Subject: [PATCH 2/3] Added video player supporting m3u8 and mpd videos --- src/actions/videopreview/videoPreview.tsx | 21 +++- src/components/ContentCard.tsx | 5 +- src/components/videothumbnail.tsx | 131 ++++++++++++++++++---- 3 files changed, 130 insertions(+), 27 deletions(-) diff --git a/src/actions/videopreview/videoPreview.tsx b/src/actions/videopreview/videoPreview.tsx index 3e0611227..86db32902 100644 --- a/src/actions/videopreview/videoPreview.tsx +++ b/src/actions/videopreview/videoPreview.tsx @@ -4,15 +4,24 @@ import db from '@/db'; export default async function VideoPreview({ contentId, }: { - contentId: number; + contentId: number | undefined; }) { + if (!contentId) return null; const videoMetadata = await db.videoMetadata.findFirst({ where: { contentId }, - select: { video_360p_1: true }, + select: { + video_360p_1: true, + video_360p_2: true, + video_360p_3: true, + video_360p_4: true, + }, }); + if (!videoMetadata) return null; + const videoUrl = + videoMetadata.video_360p_1 || + videoMetadata.video_360p_2 || + videoMetadata.video_360p_3 || + videoMetadata.video_360p_4; - if (videoMetadata) { - return videoMetadata.video_360p_1; - } - return null; + return videoUrl; } diff --git a/src/components/ContentCard.tsx b/src/components/ContentCard.tsx index 8e2ec2cd3..4e79cc622 100644 --- a/src/components/ContentCard.tsx +++ b/src/components/ContentCard.tsx @@ -50,7 +50,7 @@ export const ContentCard = ({ )} {type === 'video' && ( -
+
{contentDuration && formatTime(contentDuration)}
)} @@ -70,7 +70,8 @@ export const ContentCard = ({ {type === 'video' && (
{ + const videoRef = useRef(null); + const playerRef = useRef(null); + + useEffect(() => { + if (!playerRef.current && videoRef.current) { + const videoElement = document.createElement('video-js'); + videoElement.classList.add('vjs-big-play-centered'); + videoRef.current.appendChild(videoElement); + const player: any = (playerRef.current = videojs( + videoElement, + { + ...options, + }, + () => { + player.mobileUi(); // mobile ui #https://github.com/mister-ben/videojs-mobile-ui + player.eme(); // Initialize EME + player.on('loadedmetadata', () => { + if (onReady) { + onReady(player); + } + }); + }, + )); + } + }, [options, onReady]); + + useEffect(() => { + const player = playerRef.current; + return () => { + if (player && !player.isDisposed()) { + player.dispose(); + playerRef.current = null; + } + }; + }, []); + + return ( +
+
+
+ ); +}; const VideoThumbnail = ({ imageUrl, @@ -10,15 +62,42 @@ const VideoThumbnail = ({ contentId: number; }) => { const [videoUrl, setVideoUrl] = useState(null); + const [videoType, setVideoType] = useState(null); const [hover, setHover] = useState(false); - + const playerRef = useRef(null); useEffect(() => { - async function fetchVideoUrl() { - const url = await VideoPreview({ contentId }); - setVideoUrl(url); - } + let isMounted = true; + + const fetchVideoUrl = async () => { + if (contentId !== undefined) { + try { + const url = await VideoPreview({ contentId }); + if (isMounted && url) { + setVideoUrl(url); + if (url.endsWith('.mpd')) { + setVideoType('application/dash+xml'); + } else if (url.endsWith('.m3u8')) { + setVideoType('application/x-mpegURL'); + } else if (url.endsWith('.mp4')) { + setVideoType('video/mp4'); + } else { + setVideoType('application/dash+xml'); + } + } + } catch (error) { + console.error('Failed to fetch video URL', error); + } + } + }; + fetchVideoUrl(); + + return () => { + isMounted = false; + setVideoUrl(null); + }; }, [contentId]); + const handleMouseEnter = () => { setHover(true); }; @@ -26,24 +105,38 @@ const VideoThumbnail = ({ const handleMouseLeave = () => { setHover(false); }; + const handlePlayerReady = async (player: Player) => { + //@ts-ignore + playerRef.current = player; + }; + const videoJsOptions = { + sources: [ + { + src: videoUrl, + type: videoType, + }, + ], + muted: true, + autoplay: true, + controls: false, + preload: 'auto', + fluid: true, + }; + return ( -
-
+
+
{hover && videoUrl ? ( -
- -
+ ) : ( Video Thumbnail )}
From b83945b30ce071abbac64488d8f5d028f2a706ac Mon Sep 17 00:00:00 2001 From: Rajgupta36 Date: Sun, 26 May 2024 17:15:09 +0530 Subject: [PATCH 3/3] implement debouncing --- src/components/videothumbnail.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/components/videothumbnail.tsx b/src/components/videothumbnail.tsx index 0403dde6e..710196b81 100644 --- a/src/components/videothumbnail.tsx +++ b/src/components/videothumbnail.tsx @@ -97,12 +97,16 @@ const VideoThumbnail = ({ setVideoUrl(null); }; }, [contentId]); - + let hoverTimeout: any; const handleMouseEnter = () => { + hoverTimeout = setTimeout(() => { + setHover(true); + }, 500); setHover(true); }; const handleMouseLeave = () => { + clearTimeout(hoverTimeout); setHover(false); }; const handlePlayerReady = async (player: Player) => {