Quantcast
Channel: Active questions tagged youtube-api - Stack Overflow
Viewing all articles
Browse latest Browse all 3642

How to play youtube video in iframe in react and get correct state changes

$
0
0

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.


Viewing all articles
Browse latest Browse all 3642

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>