I have react component as follows:
import React, { Fragment, useEffect, useRef, useState } from 'react';import { hasWindow } from '../utils.js';import { Helmet } from 'react-helmet';const PLATFORMS = { YOUTUBE: 'platform', BUNNY: 'bunny', VIMEO: 'vimeo'};const VideoExternal = ({ video, isOnScreen, item, context }) => { const [isPlaying, setIsPlaying] = useState(video.autoplay); const [isPaused, setIsPaused] = useState(false); const [isMuted, setIsMuted] = useState(video.autoplay); const [isVideoLoaded, setIsVideoLoaded] = useState(false); const [isVideoHovered, setIsVideoHovered] = useState(false); const [showLastImage, setShowLastImage] = useState(false); const iframeId = `iframe-${video.url}-${video.externalUrl}`; const iframeRef = useRef(null); const playerRef = useRef(null); const getPlatform = (url) => { if (url.includes('youtube') || url.includes('youtu')) return PLATFORMS.YOUTUBE; if (url.includes('b-cdn') || url.includes('mediadelivery')) return PLATFORMS.BUNNY; if (url.includes('vimeo')) return PLATFORMS.VIMEO; return null; }; const getBaseUrl = (url) => { const urlObj = new URL(url); return `${urlObj.origin}${urlObj.pathname}`; }; const addQueryParams = (url, platform, autoplay, loop) => { const urlObj = new URL(url); switch (platform) { case PLATFORMS.YOUTUBE: if (autoplay) urlObj.searchParams.set('autoplay', '1'); if (loop) urlObj.searchParams.set('loop', '1'); isMuted ? urlObj.searchParams.set('mute', '1') : urlObj.searchParams.set('mute', '0'); urlObj.searchParams.set('controls', '0'); urlObj.searchParams.set('enablejsapi', '1'); break; case PLATFORMS.VIMEO: if (autoplay) urlObj.searchParams.set('autoplay', '1'); if (loop) urlObj.searchParams.set('loop', '1'); isMuted ? urlObj.searchParams.set('muted', '1') : urlObj.searchParams.set('muted', '0'); urlObj.searchParams.set('controls', '0'); break; case PLATFORMS.BUNNY: if (autoplay) urlObj.searchParams.set('autoplay', 'true'); if (loop) urlObj.searchParams.set('loop', 'true'); urlObj.searchParams.set('mute', `${isMuted} ? 'true' : 'false'`); urlObj.searchParams.set('controls', 'false'); break; default: break; } return urlObj.toString(); }; const platform = getPlatform(video.externalUrl); const baseUrl = getBaseUrl(video.externalUrl, platform); const iframeUrl = addQueryParams(baseUrl, platform, video.autoplay, video.loop); const initializePlayer = (iframe) => { if (!iframe) return null; if (platform === PLATFORMS.YOUTUBE) { playerRef.current = new YT.Player(iframeId, { events: { onReady: () => { console.log('onReady'); }, onStateChange: event => { if (!video.loop && event.data === YT.PlayerState.ENDED) { setIsPlaying(false); setIsMuted(true); setShowLastImage(true); console.log('Video ended.'); } } } }); } else if (platform === PLATFORMS.VIMEO) { playerRef.current = new Vimeo.Player(iframe); } }; useEffect(() => { if (isOnScreen && isVideoLoaded) { const iframe = iframeRef?.current; // Create new player instance initializePlayer(iframe); } }, [isVideoLoaded, isOnScreen]); // Effect to reset playing and showing the last image on slide change useEffect(() => { setIsPlaying(video.autoplay); setIsMuted(video.autoplay); setShowLastImage(false); }, [isOnScreen]); // Effect to check when video is ended useEffect(() => { if (isOnScreen && isVideoLoaded && hasWindow()) { const iframe = iframeRef?.current; if (platform === PLATFORMS.YOUTUBE) { } else if (platform === PLATFORMS.VIMEO) { playerRef?.current?.on('finish', function () { if (!video.loop) { setIsPlaying(false); setIsMuted(true); setShowLastImage(true); } }); } else if (platform === PLATFORMS.BUNNY) { } } }, [video.loop, isOnScreen, isVideoLoaded]); const handlePlayClick = () => { const iframe = iframeRef?.current; const iframeWindow = iframe?.contentWindow; if (iframe && isVideoLoaded) { if (platform === PLATFORMS.YOUTUBE) playerRef?.current?.playVideo(); } else if (platform === PLATFORMS.VIMEO) { playerRef?.current?.play(); } else if (platform === PLATFORMS.BUNNY && iframeWindow) { iframeWindow?.postMessage('{"event":"command","func":"play"}', '*'); } setIsPaused(false); setIsPlaying(true); setIsMuted(false); setShowLastImage(false); } }; const isFirstImageVisible = !isPlaying && !isPaused && !showLastImage && video.firstImage !== ''; const isLastImageVisible = !isPlaying && !isPaused && showLastImage && video.lastImage !== ''; const isPlayButtonVisible = !isPlaying && video.playButtonVisible; const renderFirstImage = () => { return <img src={video.firstImage} alt='Start of Video' className='rounded-16 h-full w-full absolute inset-0 object-cover' />; }; const renderLastImage = () => { return <img src={video.lastImage} alt='End of Video' className='rounded-16 h-full w-full absolute inset-0 object-cover' />; }; const renderPlayButton = () => { return <i className='fad fa-play-circle text-4xl md:text-6xl text-gray-200 hover:text-gray-100 cursor-pointer absolute z-1' onClick={handlePlayClick} />; }; const handleIframeLoad = () => { setIsVideoLoaded(true); }; return (<Fragment><Helmet><script src='https://player.vimeo.com/api/player.js'></script><script src='https://www.youtube.com/iframe_api'></script></Helmet><div className='rounded-16 h-full w-full relative flex items-center justify-center' onMouseEnter={() => setIsVideoHovered(true)} onMouseLeave={() => setIsVideoHovered(false)}> {isFirstImageVisible && renderFirstImage()}<iframe id={iframeId} ref={iframeRef} src={iframeUrl} allow='autoplay; fullscreen; picture-in-picture' title='Video' className='h-full w-full rounded-16' onLoad={handleIframeLoad}></iframe> {isPlayButtonVisible && renderPlayButton()} {isLastImageVisible && renderLastImage()}</div></Fragment> );};export default VideoExternal;
When the component loads the video starts playing (video.autoplay is true), and when video is ended I see console.log('Video ended.');
When I then click on play button and (executes handlePlayClick function) and thus playerRef?.current?.playVideo();
is executed, the video starts playing, but when it ends I do not see console.log('isEnded: ', true).
Any idea why? Do I need to reinitialize the iframe or is there something else that I'm missing?
Thanks.