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 = ";;
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 es.
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?
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./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 es.
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?
Share Improve this question edited Jun 20, 2020 at 9:12 CommunityBot 11 silver badge asked Jul 20, 2015 at 6:54 Dong Hyun KooDong Hyun Koo 131 silver badge6 bronze badges4 Answers
Reset to default 3I 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./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>
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++;
}
}
}
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++;
}
}
}
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
});
}
}