Reputation: 13
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.
<!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>
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
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
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
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
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