1- import React , { useRef , useEffect } from 'react' ;
1+ import React , { useRef , useEffect , useState } from 'react' ;
22import { getTelemetryEvents } from '../../services/TelemetryService' ;
33import { handleExitEvent } from '../utils/Helper' ;
44
@@ -16,16 +16,21 @@ const SunbirdVideoPlayer = ({
1616 configFunctionality,
1717} : PlayerConfigProps ) => {
1818 const sunbirdVideoPlayerRef = useRef < HTMLIFrameElement | null > ( null ) ;
19+ const [ iframeHeight , setIframeHeight ] = useState < string > ( '0vw' ) ; // Default 16:9 aspect ratio
20+ const [ iframeWidth , setIframeWidth ] = useState < string > ( '100%' ) ; // Dynamic width
1921
2022 useEffect ( ( ) => {
2123 const playerElement : any = sunbirdVideoPlayerRef . current ;
24+ let timeoutIds : NodeJS . Timeout [ ] = [ ] ;
25+ let observer : MutationObserver | null = null ;
26+
2227 if ( playerElement ) {
2328 const originalSrc = playerElement . src ;
2429 playerElement . src = '' ;
2530 playerElement . src = originalSrc ;
2631
2732 const handleLoad = ( ) => {
28- setTimeout ( ( ) => {
33+ const timeoutId = setTimeout ( ( ) => {
2934 if (
3035 playerElement . contentWindow &&
3136 playerElement . contentWindow . setData
@@ -64,28 +69,214 @@ const SunbirdVideoPlayer = ({
6469 if ( myPlayer ) {
6570 myPlayer . appendChild ( videoElement ) ;
6671 }
72+
73+ // Function to detect video and adjust iframe height
74+ const adjustIframeHeight = ( ) => {
75+ try {
76+ const iframeDoc = playerElement . contentDocument ;
77+ if ( ! iframeDoc ) {
78+ const retryTimeout = setTimeout ( adjustIframeHeight , 500 ) ;
79+ timeoutIds . push ( retryTimeout ) ;
80+ return ;
81+ }
82+
83+ // Find the video element
84+ let video : HTMLVideoElement | null = null ;
85+
86+ // Try shadow DOM first
87+ const sunbirdPlayer = iframeDoc . querySelector ( 'sunbird-video-player' ) ;
88+ if ( sunbirdPlayer ?. shadowRoot ) {
89+ video = sunbirdPlayer . shadowRoot . querySelector ( 'video' ) ;
90+ }
91+
92+ // Try direct query
93+ if ( ! video ) {
94+ video = iframeDoc . querySelector ( 'video' ) ||
95+ iframeDoc . querySelector ( '.video-js video' ) as HTMLVideoElement ;
96+ }
97+
98+ if ( video ) {
99+ const updateHeight = ( ) => {
100+ const videoWidth = video ! . videoWidth ;
101+ const videoHeight = video ! . videoHeight ;
102+ const containerElement = playerElement . parentElement ;
103+ const availableWidth = containerElement ?. offsetWidth || window . innerWidth ;
104+ const availableHeight = window . innerHeight ;
105+
106+ // Reserve space for padding/margins (approximately 40px top/bottom)
107+ const reservedSpace = 0 ;
108+ const maxAvailableHeight = availableHeight - reservedSpace ;
109+
110+ if ( videoWidth && videoHeight && videoWidth > 0 && videoHeight > 0 && availableWidth > 0 ) {
111+ // Calculate aspect ratio
112+ const aspectRatio = videoWidth / videoHeight ;
113+
114+ // Start with full available width
115+ let calculatedWidth = availableWidth ;
116+ let calculatedHeight = calculatedWidth / aspectRatio ;
117+
118+ // If calculated height exceeds viewport, adjust width to fit viewport
119+ if ( calculatedHeight > maxAvailableHeight ) {
120+ // Recalculate width based on available height to fit within viewport
121+ calculatedWidth = maxAvailableHeight * aspectRatio ;
122+ calculatedHeight = maxAvailableHeight ;
123+ }
124+
125+ // Ensure width doesn't exceed available width
126+ calculatedWidth = Math . min ( calculatedWidth , availableWidth ) ;
127+
128+ // Set both width and height in pixels
129+ setIframeWidth ( `${ calculatedWidth } px` ) ;
130+ setIframeHeight ( `${ calculatedHeight } px` ) ;
131+
132+ console . log ( 'Iframe dimensions adjusted:' , {
133+ videoWidth,
134+ videoHeight,
135+ aspectRatio,
136+ availableWidth,
137+ availableHeight,
138+ maxAvailableHeight,
139+ calculatedWidth,
140+ calculatedHeight,
141+ } ) ;
142+ }
143+ } ;
144+
145+ // If metadata already loaded
146+ if ( video . readyState >= 1 && video . videoWidth > 0 ) {
147+ updateHeight ( ) ;
148+ } else {
149+ // Wait for metadata
150+ const handleMetadata = ( ) => {
151+ if ( video ! . videoWidth > 0 && video ! . videoHeight > 0 ) {
152+ updateHeight ( ) ;
153+ }
154+ } ;
155+
156+ video . addEventListener ( 'loadedmetadata' , handleMetadata , { once : true } ) ;
157+ video . addEventListener ( 'loadeddata' , handleMetadata , { once : true } ) ;
158+ video . addEventListener ( 'canplay' , handleMetadata , { once : true } ) ;
159+ }
160+ } else {
161+ // Video not found, retry
162+ const retryTimeout = setTimeout ( adjustIframeHeight , 500 ) ;
163+ timeoutIds . push ( retryTimeout ) ;
164+ }
165+ } catch ( error ) {
166+ console . error ( 'Error adjusting iframe height:' , error ) ;
167+ const retryTimeout = setTimeout ( adjustIframeHeight , 1000 ) ;
168+ timeoutIds . push ( retryTimeout ) ;
169+ }
170+ } ;
171+
172+ // Use MutationObserver to watch for video element
173+ const startObserving = ( ) => {
174+ try {
175+ const iframeDoc = playerElement . contentDocument ;
176+ if ( ! iframeDoc ) {
177+ setTimeout ( startObserving , 500 ) ;
178+ return ;
179+ }
180+
181+ observer = new MutationObserver ( ( ) => {
182+ adjustIframeHeight ( ) ;
183+ } ) ;
184+
185+ observer . observe ( iframeDoc . body || iframeDoc . documentElement , {
186+ childList : true ,
187+ subtree : true ,
188+ } ) ;
189+
190+ // Try immediately
191+ adjustIframeHeight ( ) ;
192+
193+ // Cleanup observer after 15 seconds
194+ const cleanupTimeout = setTimeout ( ( ) => {
195+ if ( observer ) {
196+ observer . disconnect ( ) ;
197+ observer = null ;
198+ }
199+ } , 15000 ) ;
200+ timeoutIds . push ( cleanupTimeout ) ;
201+ } catch ( error ) {
202+ console . error ( 'Error starting observer:' , error ) ;
203+ }
204+ } ;
205+
206+ // Start observing after a delay to allow video element to be created
207+ const observeTimeout = setTimeout ( startObserving , 1000 ) ;
208+ timeoutIds . push ( observeTimeout ) ;
67209 }
68210 } , 200 ) ;
211+ timeoutIds . push ( timeoutId ) ;
69212 } ;
70213
71214 playerElement . addEventListener ( 'load' , handleLoad ) ;
72215
216+ // Also listen for window resize to recalculate dimensions
217+ const handleResize = ( ) => {
218+ const iframeDoc = playerElement . contentDocument ;
219+ if ( iframeDoc ) {
220+ const video = iframeDoc . querySelector ( 'video' ) as HTMLVideoElement ;
221+ if ( video && video . videoWidth > 0 && video . videoHeight > 0 ) {
222+ const aspectRatio = video . videoWidth / video . videoHeight ;
223+ const containerElement = playerElement . parentElement ;
224+ const availableWidth = containerElement ?. offsetWidth || window . innerWidth ;
225+ const availableHeight = window . innerHeight ;
226+ const reservedSpace = 80 ;
227+ const maxAvailableHeight = availableHeight - reservedSpace ;
228+
229+ if ( availableWidth > 0 ) {
230+ // Start with full available width
231+ let calculatedWidth = availableWidth ;
232+ let calculatedHeight = calculatedWidth / aspectRatio ;
233+
234+ // If calculated height exceeds viewport, adjust width to fit viewport
235+ if ( calculatedHeight > maxAvailableHeight ) {
236+ calculatedWidth = maxAvailableHeight * aspectRatio ;
237+ calculatedHeight = maxAvailableHeight ;
238+ }
239+
240+ // Ensure width doesn't exceed available width
241+ calculatedWidth = Math . min ( calculatedWidth , availableWidth ) ;
242+
243+ // Set both width and height
244+ setIframeWidth ( `${ calculatedWidth } px` ) ;
245+ setIframeHeight ( `${ calculatedHeight } px` ) ;
246+ }
247+ }
248+ }
249+ } ;
250+
251+ window . addEventListener ( 'resize' , handleResize ) ;
252+
73253 return ( ) => {
74254 playerElement . removeEventListener ( 'load' , handleLoad ) ;
255+ window . removeEventListener ( 'resize' , handleResize ) ;
256+ timeoutIds . forEach ( ( id ) => clearTimeout ( id ) ) ;
257+ if ( observer ) {
258+ observer . disconnect ( ) ;
259+ }
75260 } ;
76261 }
77- } , [ playerConfig ] ) ;
262+ } , [ playerConfig , courseId , unitId , userId , configFunctionality ] ) ;
78263
79264 return (
80- < iframe
81- ref = { sunbirdVideoPlayerRef }
82- id = "contentPlayer"
83- title = "Content Player"
84- src = { `${ basePath } /libs/sunbird-video-player/index.html` }
85- aria-label = "Content Player"
86- style = { { border : 'none' , aspectRatio : `16 / 9` } }
87- width = "100%"
88- > </ iframe >
265+ < iframe
266+ ref = { sunbirdVideoPlayerRef }
267+ id = "contentPlayer"
268+ title = "Content Player"
269+ src = { `${ basePath } /libs/sunbird-video-player/index.html` }
270+ aria-label = "Content Player"
271+ style = { {
272+ border : 'none' ,
273+ width : iframeWidth || '100%' ,
274+ maxWidth : '100%' ,
275+ height : iframeHeight || '56.25vw' ,
276+ display : 'block' ,
277+ margin : '0 auto' ,
278+ } }
279+ > </ iframe >
89280 ) ;
90281} ;
91282
0 commit comments