Dong Hyun Koo
Dong Hyun Koo

Reputation: 13

Youtube Iframe API loadVideoById() skips the video

Problem

I'm using Youtube Iframe API, And I need to use the API's startSeconds and endSeconds option of each video.

But here's the problem: the loadVideoById function skips the video. In my example code, the first, third, fifth video is only played.

Here's the code. It's just simplified version of my application.

Source Code

<!DOCTYPE html>
<html>
  <body>
    <!-- 1. The <iframe> (and video player) will replace this <div> tag. -->
    <div id="player"></div>

    <script>
      // 2. This code loads the IFrame Player API code asynchronously.
      var tag = document.createElement('script');
      tag.src = "http://www.youtube.com/iframe_api";
      var firstScriptTag = document.getElementsByTagName('script')[0];
      firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

      // 3. This function creates an <iframe> (and YouTube player)
      //    after the API code downloads.
      var player;
      function onYouTubeIframeAPIReady() {
        player = new YT.Player('player', {
          height: '390',
          width: '640',
          events: {
            'onReady': onPlayerReady,
            'onStateChange': onPlayerStateChange
          }
        });
      }

      var videos = [
        {
          vid: 'nbCqWMIT-Pk',
          startSeconds: 10,
          endSeconds: 15
        },
        {
          vid: 'sAoJGNF_laA',
          startSeconds: 10,
          endSeconds: 15
        },
        {
          vid: 'kF_23_XxaHQ',
          startSeconds: 10,
          endSeconds: 15
        },
        {
          vid: 'zxYp3I0Gyrg',
          startSeconds: 10,
          endSeconds: 15
        },
        {
          vid: 'U_gA99OQwO4',
          startSeconds: 10,
          endSeconds: 15
        }
      ];
      var index = 0;
      // 4. The API will call this function when the video player is ready.
      function onPlayerReady(event) {
        event.target.cueVideoById({
          videoId: videos[index].vid,
          startSeconds: videos[index].startSeconds,
          endSeconds: videos[index].endSeconds
        });
        event.target.playVideo();
      }

      function onPlayerStateChange(event) {
        if (event.data === YT.PlayerState.ENDED) {
          console.log(index);
          if (index < videos.length - 1) {
            index++;
            event.target.loadVideoById({
              videoId: videos[index].vid,
              startSeconds: videos[index].startSeconds,
              endSeconds: videos[index].endSeconds
            });
          }
        }
      }

    </script>
  </body>
</html>

Simple explanation for the source code

The videos array is assigned for test of my own. ( It's all Faker's highlights because I'm a big fan of him :) )

I made the player plays the videos in the list. If the player emits the "ENDED" event, then change the index and play the next video.

But when the time second and fourth video is to be played, This video isn't played. Only the ENDED event comes.

It seems like that the loaded video's endSeconds value isn't equal to video's total duration, It skips next video.

How can I solve this situation? Is it Youtube API's bug?

Upvotes: 1

Views: 6565

Answers (4)

Adiel Ayala
Adiel Ayala

Reputation: 1

  var index = 0;
   function onPlayerReady(event) {

    event.target.cueVideoById({
      videoId: videos[index].vid,
      startSeconds: videos[index].startSeconds,
      endSeconds: videos[index].endSeconds
    });
    event.target.playVideo();

  }

  function onPlayerStateChange(event) {
    if (event.data === YT.PlayerState.ENDED) {  
      index++;
      if (index > videos.length -1 ) {index=0;}else{index=index;}



        event.target.loadVideoById({
          videoId: videos[index].vid,
          startSeconds: videos[index].startSeconds,
          endSeconds: videos[index].endSeconds

          });


    }
  }

Upvotes: 0

user8501070
user8501070

Reputation: 1

This code works, but the first video is playing twice, and the last is not displayed. You need to increment the index only for the first video in onPlayerReady, and to put <= in onPlayerStatechange.

function onPlayerReady(event) {
    event.target.cueVideoById({
        videoId: videos[index],
    });
    event.target.playVideo();
    if (index == 0){
        index++;
    }
}

// 5. The API calls this function when the player's state changes.
//    The function indicates that when playing a video (state=1),
//    the player should play for six seconds and then stop.
;
function onPlayerStateChange(event) {
    if (event.data === YT.PlayerState.ENDED) {
        console.log(index);
        if (index <= videos.length - 1) {

            event.target.loadVideoById({
                videoId: videos[index],
            });
            index++;
        }
    }
}

Upvotes: 0

abdeljalil nachi
abdeljalil nachi

Reputation: 26

I found your problem it's in the function onPlayerStateChange() incrementation should be at the end (after loading your video ):

function onPlayerStateChange(event) {
        if (event.data === YT.PlayerState.ENDED) {
          console.log(index);
          if (index < videos.length - 1) {

            event.target.loadVideoById({
              videoId: videos[index].vid,
              startSeconds: videos[index].startSeconds,
              endSeconds: videos[index].endSeconds
            });
            index++;
        }
    }
}  

Upvotes: 1

timtoady
timtoady

Reputation: 31

I added a log function to see which states are called and it seems to be a problem in the API. When a new video loads a state of -1 (unstarted) is immediately followed by a state of 0 (ended).

To prevent this from happening, I just added an extra check to make sure at least a fraction of the video is loaded.

<!DOCTYPE html>
<html>
  <body>
    <!-- 1. The <iframe> (and video player) will replace this <div> tag. -->
    <div id="player"></div>

    <script>
      // 2. This code loads the IFrame Player API code asynchronously.
      var tag = document.createElement('script');
      tag.src = "http://www.youtube.com/iframe_api";
      var firstScriptTag = document.getElementsByTagName('script')[0];
      firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

      // 3. This function creates an <iframe> (and YouTube player)
      //    after the API code downloads.
      var player;
      function onYouTubeIframeAPIReady() {
        player = new YT.Player('player', {
          height: '390',
          width: '640',
          events: {
            'onReady': onPlayerReady,
            'onStateChange': onPlayerStateChange
          }
        });
      }

      var videos = [
        {
          vid: 'nbCqWMIT-Pk',
          startSeconds: 10,
          endSeconds: 15
        },
        {
          vid: 'sAoJGNF_laA',
          startSeconds: 10,
          endSeconds: 15
        },
        {
          vid: 'kF_23_XxaHQ',
          startSeconds: 10,
          endSeconds: 15
        },
        {
          vid: 'zxYp3I0Gyrg',
          startSeconds: 10,
          endSeconds: 15
        },
        {
          vid: 'U_gA99OQwO4',
          startSeconds: 10,
          endSeconds: 15
        }
      ];
      var index = 0;
      // 4. The API will call this function when the video player is ready.
      function onPlayerReady(event) {
        event.target.cueVideoById({
          videoId: videos[index].vid,
          startSeconds: videos[index].startSeconds,
          endSeconds: videos[index].endSeconds
        });
        event.target.playVideo();
      }

      function onPlayerStateChange(event) {
        console.log("State change: " + event.data + " for index: " + index);

        if (event.data === YT.PlayerState.ENDED && player.getVideoLoadedFraction() > 0) {
          console.log(index);
          if (index < videos.length - 1) {
            index++;
            event.target.loadVideoById({
              videoId: videos[index].vid,
              startSeconds: videos[index].startSeconds,
              endSeconds: videos[index].endSeconds
            });
          }
        }
      }

    </script>
  </body>
</html>

Upvotes: 3

Related Questions