Moving through Vimeo videos with Javascript - javascript

I would like to play through Vimeo videos in sequence with JavaScript with continuous playback and looping through items. The following code moves to the second video at the end of the first but the same functions are not called at the end of the second video. Only the end of the first video shows Called! in the Javascript console, not the end of the second.
The Vimeo Player SDK has player.getVideoId() but not player.setVideoId() so I used a hack to load the next video: setting the source of the iframe and starting the Vimeo player anew. I wonder if this is the problem and the listener for the end of the video is attached to the discarded player.
Another issue with this code is that it exits fullscreen to load the next video.
I attempted this CodePen that sets the Vimeo Player on any element instead of an iframe and was unable to change the played video.
What is a cleaner or effective way of changing videos with the Vimeo Player SDK?
The HTML is:
<div class="vimeo">
<div class="resp-iframe-container container-centered">
<iframe class="resp-iframe" scrolling="no" frameborder="no" src="https://player.vimeo.com/video/238301525" allowfullscreen="" data-ready="true"></iframe></div></div>
And the javascript is:
var l = ["238301525", "496371201", "238301525", "496371201", "..."];
window.current = 0;
var increment = function() {
window.current += 1;
if (window.current == l.length) {
window.current = 0;
}
};
var decrement = function() {
window.current -= 1;
if (window.current < 0) {
window.current = l.length - 1;
}
};
prevA.addEventListener("click", function() {
decrement();
loadPlayer();
});
nextA.addEventListener("click", function() {
increment();
console.log("here!");
loadPlayer();
console.log("there!");
});
var loadPlayer = function() {
console.log("Called!");
var iframe = document.querySelector('iframe');
iframe.src = "https://player.vimeo.com/video/" + l[window.current];
var player = new Vimeo.Player(iframe);
player.autoplay = true;
var treatEvent = function(data, eventLabel) {
// Custom code...
if ("end" == eventLabel) {
console.log("incrementing automatically");
increment();
loadPlayer();
}
};
var onPlay = function(data) {
treatEvent(data, "play");
}
var onPause = function(data) {
treatEvent(data, "pause");
}
var onSeeked = function(data) {
treatEvent(data, "seeked");
}
var onEnd = function(data) {
treatEvent(data, "end");
}
player.on('play', onPlay);
player.on('pause', onPause);
player.on('seeked', onSeeked);
player.on('ended', onEnd);
setTimeout(function() {
//console.log("Trying to play...");
player.play().then(function() {
// the video was played
console.log("success: video played");
}).catch(function(error) {
console.log("Error! " + error.name);
});
}, 1000);
}
loadPlayer();

It seems that the Vimeo Player keeps track of whether it was initialized, adding a tag data-vimeo-initialized="true" in the HTML element.
One solution is to use the Vimeo Player SDK function .loadVideo():
var song_iframe = document.querySelector("iframe#song_video");
var song_player = new Vimeo.Player(song_iframe);
var on_song_end = function(data) {
// Logic to get the new id.
song_player.loadVideo(newId).then(function() {
song_player.play();
});
};
song_player.on("ended", on_song_end);

Related

How to play more video on the same player with Vimeo player.js

I'm trying to play videos one after the other in the same Vimeo player, without success.
This is the code I'm working on. I can't find any example on how to do that.
I'm sure I'm wrong but I don't know how to go further...
var iframe = document.querySelector('iframe.main-player');
var player = new Vimeo.Player(iframe);
var video_ids = ['123456789', '987654321'];
video_ids.forEach(function(item, index) {
player.pause();
player.loadVideo(item);
player.on('loaded', function() {
player.play();
});
})
I'm not sure about this, because can't test it right now , but you can try something like this:
var iframe = document.querySelector('iframe.main-player');
var player = new Vimeo.Player(iframe);
var video_ids = ['123456789', '987654321'];
var index = 0;
var playNext = function(data){
player.pause();
if(index<=video_ids.length)
player.loadVideo(video_ids[index++])
}
player.pause();
player.loadVideo(video_ids[index++]);
player.on('loaded', function() {
player.play();
});
player.on('ended', playNext);
The idea is pretty simple by listen to the ended event then moving to the next item.
First of all, we just create a class to hold some information such as the list & current playing index:
import Player from "#vimeo/player";
class Playlist {
constructor(playlist) {
this.playlist = playlist;
this.currentIdx = 0;
}
init() {
this.player = new Player("app", {
id: this.currentItem,
width: 640
});
this.player.on("ended", this.onEnded.bind(this));
}
onEnded() {
if (this.currentIdx < this.playlist.length) {
this.currentIdx++;
const nextId = this.currentItem;
this.player.loadVideo(nextId);
// Check next item has loaded then play it automatically
// you might not receive any error in case of having to interact with document
this.player.on("loaded", () => {
this.player.play();
});
}
}
get currentItem() {
return this.playlist[this.currentIdx];
}
}
// Try to run 2 items
const pl = new Playlist([59777392, 28582484]);
pl.init();
NOTE: I also created a codesandbox link for you here https://codesandbox.io/s/focused-firefly-ej0fd?file=/src/index.js

Index of object and play next with youtube api

I am using the youtube api to search for youtube videos. The videos will then be displayed on #searchBar with the video id ex. NJNlqeMM8Ns as data-video. I get the video id by pressing on a img:
<img data-video = "{{videoid}}" src = "bilder/play.png" alt = "play" class = "knapp" width = "40" height = "40">
Which in my poorly understanding of javascript becomes (this).
When I search for videos I will get more than one result which means that I will get more than one img tag.
In this case I want to play the next song when the first one is finished. I tried to get the index when I pressed on my img tag:
$(".knapp").click(function(){
var index = $(".knapp").index(this);
alert(index);
});
However, when I alerted the index after the video was finshed I always got the value 0 back.
So I thought I could do something like this:
function onPlayerStateChange(event) {
if (event.data == YT.PlayerState.ENDED){
playNext();
}
}
$('#searchBar').on('click', '[data-video]', function(){
player.current_video = $(this).attr('data-video');
playVideo();
});
function playVideo(){
var video_id = player.current_video;
player.loadVideoById(video_id, 0, "large");
}
function playNext(){
var player.current_videon = **$(this + 1).attr('data-video');**
var next_id = player.current_videon;
player.loadVideoById(next_id, 0, "large");
}
But I'm not sure how to make it work, as you can see in the bold section, can I solve my problem like this or do I need another approach?
Edit:
With some research I found out that I need to set the value of the current video being played and also efter the video was done playing I add this number by 1.
However even if it did make the next video play, I was unable to chose which song I wanted anymore...
function onPlayerStateChange(event) {
if (event.data == YT.PlayerState.ENDED){
player.current_video++;
playVideo();
}
}
var player = document.querySelector('iframe');
function onYouTubeIframeAPIReady() {
player = new YT.Player('player', {
height: '390',
width: '640',
videoId: '40mSZPyqpag',
playerVars: {rel: 0},
events: {
'onStateChange': onPlayerStateChange
}
});
player.current_video = 0;
}
$('#searchBar').on('click', '[data-video]', function(){
player.current_video = $(this).index();
alert(player.current_video);
playVideo();
});
function playVideo(){
var video_id = $('[data-video]').eq(player.current_video).attr('data-video');
player.loadVideoById(video_id, 0, "large");
}
Here is a working PEN (click to RUN)
The solution is based on a global currentSongIndex index, without facilitating next()
var currentSongIndex = null;
$(".knapp").click(function () {
var index = $(this).attr('data-video');
playVideo(index);
});
function playVideo(index) {
console.log("Playing song INDEX: " + index);
currentSongIndex = index;
playNext();
}
function playNext() {
currentSongIndex++;
let nextSongIndex = $('img[data-video="' + currentSongIndex + '"]').attr('data-video');
console.log("Next song INDEX: " + nextSongIndex);
if(typeof nextSongIndex != "undefined") {
playVideo(nextSongIndex);
} else {
console.log('end of list... you can play from index 1 or whatever....');
}
}
I got a suggestion to get player.current_video by the closest li index, so I made an update to my data-video img tag.
<li class = liItem>
<img data-video = "{{videoid}}" src = "bilder/play.png" alt = "play" class = "knapp" width = "40" height = "40">
</li>
Then I changed the index on my click function in my edited example:
$('#searchBar').on('click', '[data-video]', function(){
player.current_video = $(this).closest('li').index();
playVideo();
});
With this new fuction I was able to chose and play the next song!
Shoutout to #cale_b for providing me with the .closest('li') suggestion.

Controlling when Vimeo thumbnail turns off and video begins

I'm looking into the vimeo embed api. I want the video to autoplay on load which I have working but currently what happens is like this:
player loads then autoplays [event "ready"]
thumbnail removed and shows black for about a second
video begins playing [event "playProgess"]
The problem is the second step. I'm trying to eliminate that black screen between when the thumbnail hides (when play is initiated) to when the video actually appears and starts playing.
The way I figure it can be solved is to keep the thumbnail around and trigger the thumbnail hide on the first "playProgress" but I can't seem to find anyway to control when the thumbnail turns on or off.
Is this possible to control? I'm aware that I can pull the thumbnail and overlay it over the iframe but I'm hoping for a cleaner fix (keep it all contained to the iframe).
Here's a pen with api running:
http://codepen.io/mattcoady/pen/KMzZMZ
$(function() {
var player = $('iframe');
var playerOrigin = '*';
var status = $('.status');
// Listen for messages from the player
if (window.addEventListener) {
window.addEventListener('message', onMessageReceived, false);
}
else {
window.attachEvent('onmessage', onMessageReceived, false);
}
// Handle messages received from the player
function onMessageReceived(event) {
// Handle messages from the vimeo player only
if (!(/^https?:\/\/player.vimeo.com/).test(event.origin)) {
return false;
}
if (playerOrigin === '*') {
playerOrigin = event.origin;
}
var data = JSON.parse(event.data);
console.log(data.event);
switch (data.event) {
case 'ready':
onReady();
break;
case 'playProgress':
onPlayProgress(data.data);
break;
case 'pause':
onPause();
break;
case 'finish':
onFinish();
break;
case 'play':
onPlay();
break;
}
}
// Call the API when a button is pressed
$('button').on('click', function() {
post($(this).text().toLowerCase());
});
// Helper function for sending a message to the player
function post(action, value) {
var data = {
method: action
};
if (value) {
data.value = value;
}
var message = JSON.stringify(data);
player[0].contentWindow.postMessage(message, playerOrigin);
}
function onReady() {
status.text('ready');
post('play');
post('addEventListener', 'pause');
post('addEventListener', 'finish');
post('addEventListener', 'playProgress');
}
function onPause() {
status.text('paused');
}
function onFinish() {
status.text('finished');
}
function onPlay(){
alert('play')
}
function onPlayProgress(data) {
status.text(data.seconds + 's played');
}
});
What I ended up going with my hacky fix. It's pulls the thumbnail and lays it over the video. When my script detects the 'playProgress' event that means the video is actually playing. I use jQuery to fade away the thumbnail cover.
http://codepen.io/mattcoady/pen/YWqaWJ
$(function() {
var player = $('iframe');
var playerOrigin = '*';
var videoId = 76979871;
player.attr('src', 'https://player.vimeo.com/video/' + videoId + '?api=1&player_id=player1&background=1&autoplay=1&loop=1');
// Listen for messages from the player
if (window.addEventListener) {
window.addEventListener('message', onMessageReceived, false);
} else {
window.attachEvent('onmessage', onMessageReceived, false);
}
$.getJSON('http://vimeo.com/api/v2/video/' + videoId + '.json', {jsonp: 'callback',dataType: 'jsonp'}, function(data) {
var thumbnail = document.createElement('img');
thumbnail.src = data[0].thumbnail_large;
thumbnail.style.width = document.querySelector('#player1').offsetWidth + 'px';
thumbnail.style.height = document.querySelector('#player1').offsetHeight + 'px';
document.querySelector('#vimeo-thumb-container').appendChild(thumbnail);
})
// Handle messages received from the player
function onMessageReceived(event) {
// Handle messages from the vimeo player only
if (!(/^https?:\/\/player.vimeo.com/).test(event.origin)) {return false;}
if (playerOrigin === '*') { playerOrigin = event.origin; }
var data = JSON.parse(event.data);
switch (data.event) {
case 'ready':
onReady();
break;
case 'playProgress':
onPlayProgress(data.data);
break;
}
}
// Helper function for sending a message to the player
function post(action, value) {
var data = { method: action };
if (value) {data.value = value;}
var message = JSON.stringify(data);
player[0].contentWindow.postMessage(message, playerOrigin);
}
function onReady() {
post('play');
post('addEventListener', 'playProgress');
}
function onPlayProgress(data) {
$('#vimeo-thumb-container').fadeOut(250);
}
});

How can I detect whether my audio stream is: playing, paused or finished?

I'm working on an online radio website and am trying to detect what state the audio player is currently in for the user.
The current setup I've got is often wrong in knowing this and if I'm on iOS and I pause from the lock screen player instead, it will still think it's playing because I never clicked the html pause button.
Finally how is it possible to detect when my stream has fully ended. I've tried: onstalled="", onwaiting="", onerror="", onended="". But none of them work 100% of the time. The closest one to work would be: onstalled="", but even that only had a 60% success rate or so (occasionally when I'm loading the site it would tell me it has ended).
HTML:
<audio autoplay="" id="player" title="" oncanplay="radioLoaded()">
<source src="...">
</audio>
Javascript:
function radioLoaded() {
if (player.paused) {
document.getElementById('radioplaypause').innerHTML = varRadioResume;
} else if (player.play) {
document.getElementById('radioplaypause').innerHTML = varRadioPause;
} else {
document.getElementById('radioplaypause').innerHTML = varRadioLoading;
}
window.player = document.getElementById('player');
document.getElementById('radioplaypause').onclick = function () {
if (player.paused) {
player.play();
this.innerHTML = varRadioPause;
} else {
player.pause();
this.innerHTML = varRadioResume;
}
}
};
function radioEnded() {
document.getElementById('radiolivetext').innerHTML = 'OFFLINE';
document.getElementById('radioplayer').style.display = 'none';
document.getElementById('radioinformation').style.display = 'none';
};
Try this, with some corrections/notes to the code in general:
function radioLoaded() {
// move this line to the top
window.player = document.getElementById('player'); // !!! <-- name too generic, possibility of global collisions
var playPauseButton = document.getElementById('radioplaypause');
if (player.paused) {
playPauseButton.innerHTML = varRadioResume;
} else if (player.play) {
playPauseButton.innerHTML = varRadioPause;
} else {
playPauseButton.innerHTML = varRadioLoading;
}
playPauseButton.onclick = function () {
if (player.paused) {
player.play();
this.innerHTML = varRadioPause;
} else {
player.pause();
this.innerHTML = varRadioResume;
}
};
player.onended = function () {
console.log('ended');
};
// other helpful events
player.onpause = function () {
console.log('paused...');
}
player.onplay = function () {
console.log('playing...');
}
player.onprogress = function (e) {
console.log(e.loaded + ' of ' + e.total + ' loaded');
}
};

Start youtube video on hover/mouseover

I'm trying to get youtube videos to start on hover. It will pause (not stop) when the user hovers over another video...
I am stuck on the hover command. Can someone help me work it out please?
The page has 16 videos, this is the working code from the jsfiddle that contains 3 videos as an example.
http://jsfiddle.net/sebwhite/gpJN4/
VIDEO:
<iframe id="player" width="385" height="230" src="http://www.youtube.com/embed/erDxb4IkgjM?rel=0&wmode=Opaque&enablejsapi=1;showinfo=0;controls=0" frameborder="0" allowfullscreen></iframe>
JAVASCRIPT:
function onYouTubeIframeAPIReady() {
player = new YT.Player('player', {
events: {
'onStateChange': onPlayerStateChange
}
});
onYouTubeIframeAPIReady();
function onPlayerStateChange(event) {
if (event.data == YT.PlayerState.PLAYING) {
player1.pauseVideo();
player2.pauseVideo();
}
UPDATED FIDDLE
Try this:
var $$ = function(tagname) { return document.getElementsByTagName(tagname); }
function onYouTubeIframeAPIReady() {
var videos = $$('iframe'), // the iframes elements
players = [], // an array where we stock each videos youtube instances class
playingID = null; // stock the current playing video
for (var i = 0; i < videos.length; i++) // for each iframes
{
var currentIframeID = videos[i].id; // we get the iframe ID
players[currentIframeID] = new YT.Player(currentIframeID); // we stock in the array the instance
// note, the key of each array element will be the iframe ID
videos[i].onmouseover = function(e) { // assigning a callback for this event
if (playingID !== currentHoveredElement.id) {
players[playingID].stopVideo();
}
var currentHoveredElement = e.target;
if (playingID) // if a video is currently played
{
players[playingID].pauseVideo();
}
players[currentHoveredElement.id].playVideo();
playingID = currentHoveredElement.id;
};
}
}
onYouTubeIframeAPIReady();
Fiddle:
http://jsfiddle.net/gpJN4/3/

Categories

Resources