I am new to the YouTube Iframe API and am trying to pause several embedded Iframe videos that are in a slideshow (jQuery flexslider plugin) when a user moves to a different slide. If the player isn't paused, the video continues to play and, since there will be multiple videos in the slide show, I need each one to pause when a new slide is revealed. The Iframes are not inserted via the API, but are already present in the html due to the CMS I am using.
I have read through the API reference and several answers I found on here, but am having trouble figuring out how to pause any/every Iframe video when a user transitions to a new slide.
In my latest attempt, as seen in the code below, I have tried to pause the Iframes whenever a link is clicked, since the only links on the page will be for navigating to the next and previous slides. I also have tried to pause all videos on a slide transition event provided via the flexslider API, but with no success.
var players = {}; //players storage object
function onYouTubeIframeAPIReady(){
$('iframe[id]').each(function(){
var identifier = this.id;
var frameID = getFrameID(identifier);
if (frameID) { // if iframe exists
players[frameID] = new YT.Player(frameID, {
events: {
"onStateChange" : createYTEvent(frameID, identifier)
}
});
}
});
}
//returns a function to enable multiple events
function createYTEvent(frameID, identifier){
return function (event){
var player = players[frameID]; //set player reference
var done = false;
$('a').click(function(){
player.pauseVideo();
return false;
});
}
}
Any help would be greatly appreciated
Sorry for my English, I'm French, but I got the same problem recently, and maybe I thought that I could help you or another person in the future.
The difference with you is that I only used 1 player loading a list of 4 videos, and not 4 players.
There is my HTML:
<div id='videos'>
<div id="player">
<!-- the iframe drectly write in the html, with a list of videos (4 in the example) -->
<iframe id="ytplayer" type="text/html" width="640" height="360" src="https://www.youtube.com/embed/youtubeVideoId1?playlist=youtubeVideoId2,youtubeVideoId3,youtubeVideoId4&version=3" frameborder="0" allowfullscreen></iframe>
</div>
<!-- below, the buttons for switching the 4 videos -->
<span id='pagination'>
<a onclick='video_slide(0);' id='puce1'></a>
<a onclick='video_slide(1);' id='puce2'></a>
<a onclick='video_slide(2);' id='puce3'></a>
<a onclick='video_slide(3);' id='puce4'></a>
</span>
</div>
</div>
and my Javascript:
<script type="text/javascript">
// call the youtube API
var tag = document.createElement('script');
tag.src = "//www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
// init the player
var player;
function onYouTubeIframeAPIReady() {
player = new YT.Player('ytplayer', {
events: {
// the function "onPlayerStateChange is call when the player load,
play, pause or stop a video
'onStateChange': onPlayerStateChange
}
});
}
function onPlayerStateChange(event) {
// if a new video is buffering (the event.data is -1 when buffering,
1 when playing, 2 when paused ...)
if (event.data == -1) {
// it mean that the player pass at the next video,
so we call the bellow function to turn on the corresponding button
getTheRightPuce();
}
}
// I add a function to recognize the current video playing,
and turn on the right button automatically when at the end of a video,
the player pass on the next one
function getTheRightPuce(){
var vidIndex = player.getPlaylistIndex();
$("#pagination a").css('backgroundColor','#000000');
if (vidIndex==0){$("#puce1").css('backgroundColor','red');}
else if (vidIndex==1){$("#puce2").css('backgroundColor','red');}
else if (vidIndex==2){$("#puce3").css('backgroundColor','red');}
else if (vidIndex==3){$("#puce4").css('backgroundColor','red');}
}
// the function called by the buttons, change the current video
on the player and turn on the corresponding button,
the parameter is the index of the video in the play-list
(0 for the first, 1 for second...)
function video_slide(sld){
player.playVideoAt(sld);
$("#videos").css('display','none');
$("#pagination a").css('backgroundColor','#000000');
$("#videos").fadeIn(500);
if (sld==0){$("#puce1").css('backgroundColor','red');}
else if (sld==1){$("#puce2").css('backgroundColor','red');}
else if (sld==2){$("#puce3").css('backgroundColor','red');}
else if (sld==3){$("#puce4").css('backgroundColor','red');}
}
</script>
I tried to make it as clearer as possible.
I hope this will help you or someone else :)
Related
Good day,
I know this question has been asked many times. I searched high and low to get it to work but it seems that something has changed that the answers are not working anymore.
On YouTube, when I run this simulateClick function in the console. It works.
function simulateClick() {
var evt = new MouseEvent("click", {
bubbles: true,
cancelable: true,
view: window
});
var cb = document.getElementsByClassName("ytp-play-button")[0]; //element to click on
var canceled = !cb.dispatchEvent(evt);
if(canceled) {
// A handler called preventDefault
alert("canceled");
} else {
// None of the handlers called preventDefault
alert("not canceled");
}
}
That is because there is a button called "ytp-play-button".
However, when I take that to YouTube TV (formerly leanback). It does not work. The div function there has a "role=button".
This is the div responsible for the play button.
<div class="toggle-button selected material-icon-play-arrow toggle-selected transport-controls-toggle-button" tabindex="-1" role="button" style=""> <div class="background"></div> <span class="label">Pause</span></div>
So I changed the "ytp-play-button" to the "material-icon-play-arrow" but even though it gets the class right. It does not work.
Any pointers would be truly appreciated it. Thank you.
P.S.: This is a pure JavaScript question not a jQuery one.
Edit#1: When I tried to run the onclick like this in the console
document.getElementsByClassName("material-icon-play-arrow")[0].onclick()
I got this error.
Uncaught TypeError: document.getElementsByClassName(...)[0].onclick is not a function
at :1:64
(anonymous) # VM7969:1
You can use YouTube Iframe Player API for set a embed YouTube video and control the way you can interact with the video.
For your specific case, you need play/pause a YouTube video by clicking an HTML element (in this case, a div element).
For achieve this functionality, you can use the following code - see the working sample in this jsfiddle.
There, basically I have a div element (called playButton) and (using the onPlayerStateChange function) I set the click event as follows:
When the video is playing, the div playButton will have its text as "Pause" and its click event allows pause the video.
When the video is paused, the div playButton will have its text as "Play" and its click event allows play the video.
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
// Variables of the divs (where the YouTube iframe will load):
var player;
function onYouTubeIframeAPIReady() {
// Div player:
player = new YT.Player('player', {
height: '360',
width: '640',
videoId: 'M7lc1UVf-VE',
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
// After loading the iframe, set the "playVideo" onclick event on "playButton" anchor element.
document.getElementById('playButton').onclick = function() {
player.playVideo();
};
}
// 5. The API calls this function when the player's state changes.
function onPlayerStateChange(event) {
// If the video is PLAYING, set the onclick element for pause the video.
// Once the "playButton" is clicked, the video will be paused.
if (event.data == YT.PlayerState.PLAYING) {
document.getElementById('playButton').innerHTML = 'Pause';
// Set the onclick event to the button for pause the YouTube video.
document.getElementById('playButton').onclick = function() {
player.pauseVideo();
};
}
// If the video is PAUSED, set the onclick element for pause the video.
// Once the "playButton" is clicked, the video will resume the video = continue playing the video.
if (event.data == YT.PlayerState.PAUSED) {
document.getElementById('playButton').innerHTML = 'Play';
document.getElementById('playButton').onclick = function() {
player.playVideo();
};
}
}
// Div "player" - The API will call this function when the video player is ready.
function onPlayerReady(event) {
event.target.playVideo();
}
<!-- In this div, the YouTube video will be loaded with YouTube iframe Player API. -->
<div id="player"></div>
<!-- N.B this is the div element used for play or pause the current video loaded with YouTube iframe Player API. -->
Play
Here is the "Playback controls and player settings" in the official documentation for further details.
Im having trouble firing up the audio (playback+pause) on the same page.
My standard HTML5 audio player works perfect and has standard controlls like this:
<play title="Play spoken audio for the visually impaired">▶</play>
<pause title="Pause audio, and press again to resume play">❚❚</pause>
Now imagine you would like to have a simplified alternative play/pause controls elsewhere on the same page. Good idea right? Now my problem is, that if I add a separate more minimalistic play / pause control elsewhere on the page, then the first play/pause buttons dissappear entirely!
<play>▶</play>
<pause>❚❚</pause>
All that I want is to duplicate the functionality of the first play/pause and place them elsewhere on the page, allowing users on mobile to have the play/pause on another location of the page for ease of use.
So in summary, I would like to allow the user to controll the playback from two different places simultaneously. The main one has fancier layout, while the alternative one in location 2 has only play and pause toggle. Both should toggle if either one is pressed. (when play is pressed it shows as a pause button and when pause is pressed it becomes a play button).
What must I change in html and or javascript to achieve this? Thanks in advance!
The javascript looks like this:
window.onload = function(){
var myAudio = document.getElementsByTagName('audio')[0];
var play = document.getElementsByTagName('play')[0];
var pause = document.getElementsByTagName('pause')[0];
function displayControls() {
play.style.display = "block";
}
// check that the media is ready before displaying the controls
if (myAudio.paused) {
displayControls();
} else {
// not ready yet - wait for canplay event
myAudio.addEventListener('canplay', function() {
displayControls();
});
}
play.addEventListener('click', function() {
myAudio.play();
play.style.display = "none";
pause.style.display = "block";
});
pause.addEventListener('click', function() {
myAudio.pause();
pause.style.display = "none";
play.style.display = "block";
});
}
DEMO
So you have the following code...
var myAudio = document.getElementsByTagName('audio')[0];
var play = document.getElementsByTagName('play')[0];
var pause = document.getElementsByTagName('pause')[0];
Step-by-step breakdown...
document.getElementsByTagName('audio')[0]
Get the 0th (1st) element in the document that has the tag name audio.
document.getElementsByTagName('play')[0]
Get the 0th (1st) element in the document that has the tag name play.
Problem #1. You only register the first play button for the code. You must add code for the second play button.
document.getElementsByTagName('pause')[0]
Get the 0th (1st) element in the document that has the tag name pause.
Problem #2. Same problem as #1.
So the solution is:
var audio;
window.onload=function(){
audio=document.getElementsByTagName("audio")[0];
//YOU MUST REGISTER AN EVENT LISTENER FOR EVERY PLAY AND PAUSE BUTTON.
document.getElementsByClassName("playpause")[0].addEventListener("click",playpause);
document.getElementsByClassName("playpause")[1].addEventListener("click",playpause);
}
function playpause(){
var state;
if(audio.paused){
audio.play();
state="Pause";
}else{
audio.pause();
state="Play";
}
for(var i=0;i<document.getElementsByClassName("playpause").length;i++){
document.getElementsByClassName("playpause")[i].innerHTML=state;
}
}
<audio>
<source src="http://www.kozco.com/tech/32.mp3" type="audio/mpeg">
</audio>
<button class="playpause">Play</button>
<button class="playpause">Play</button>
I have an embedded Vimeo video on the homepage my site, which is set to autoplay when the site loads. I am also using the api and froogaloop.js for some custom controls.
What I need to do is save the time the video has got to when a visitor navigates to another page, then resume playing from this point if and when they return to the homepage.
I know I can use playProgress to get the time elapsed, but am not sure how to store this and how to use it when the visitor returns to the homepage.
EDIT
I now have the following code, and am using js-cookie to store the progress cookie. How would I get the value of playProgress and set it as a cookie using beforeunload on window? I am not great at javascript so help would be great!
JAVASCRIPT (also including this library https://github.com/js-cookie/js-cookie)
$(function() {
var iframe = $('#player1')[0];
var player1 = $f(iframe);
var status1 = $('.status1');
// When the player is ready, add listener for playProgress
player1.addEvent('ready', function() {
status1.text('ready');
player1.addEvent('playProgress', onPlayProgress);
});
function onPlayProgress(data, id) {
status1.text(data.seconds + ' seconds played');
};
// SETTING A COOKIE
Cookies.set('timeElapsed','something');
});
HTML
<script src="https://f.vimeocdn.com/js/froogaloop2.min.js"></script>
<div class="videoholder">
<h3>Player 1</h3>
<iframe id="player1" src="https://player.vimeo.com/video/142216434?api=1&player_id=player1" width="500" height="281" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
<div>
<p><span class="status1">…</span></p>
</div>
</div>
You can simply read the value of the cookie saved using
function onPlayProgress(data, id) {
Cookies.set('timeElapsed', data.seconds);
status1.text(Cookies.get('timeElapsed') + ' seconds played');
}
and then set the value of the video when it is being loaded by appending &t=0m0s at the end of the url.
$('#player1').attr('src','https://player.vimeo.com/video/142216434?api=1&player_id=player1&t='+timeElapsed)
I got this working with the following javascript:
$(function() {
var iframe = $('#player1')[0];
var player1 = $f(iframe);
// When the player is ready, add listener for playProgress
player1.addEvent('ready', function() {
player1.api('seekTo',(Cookies.get('timeElapsed')));
player1.api('pause');
player1.addEvent('playProgress', onPlayProgress);
});
function onPlayProgress(data, id) {
Cookies.set('timeElapsed', data.seconds);
};
});
My only issue now is that when you return to the (paused) video, you need to click twice to get it to resume as the Pause button is visible. Does anyone know why this would be? This is the last piece of my Vimeo puzzle!
I have a slick.js slider that contains video and I want the slider to pause once it reaches a video slide and resume cycling once the video finishes without user interaction. I can get this functionality to work with the first video in a cycle but on the second video slide, the slider will not resume once the video completes.
Fiddle
I have a console log that writes out when the video completes but it won't say anything once the second video completes. I believe it is not seeing the function to play the slick slider.
function myHandler(e) {
console.log('Video Complete')
$('.sliderMain').slick('slickPlay');
}
You were only binding the first video tag to your myHandler function:
// It only gets the first element
var video = document.getElementsByTagName('video')[0];
video.addEventListener('ended',myHandler,false);
Since you're using jQuery, you can bind an event when the videos have ended like that:
$('video').on('ended',function(){
console.log('Video Complete')
$('.sliderMain').slick('slickPlay');
});
jQuery demo
The JavaScript equivalent would be so:
var videos = document.getElementsByTagName('video');
for (var i=0; i<videos.length; i++) {
videos[i].addEventListener('ended',myHandler,false);
}
JavaScript demo
SlickSlider is responsive and needs to work 360 (across all devices).
Your solution will not work on mobile, since autoplay of a video is forbidden.
Also this solution allows multiple videos to be playing at once, which is sub-optimal.
A better solution would be to pause the carousel only when the video is played by the user, and resume the carousel (pausing the video) when a slide is detected.
This works also on mobile devices. Just make sure, you don't serve a video tag on mobile. Before outputting your slide via PHP template, just check the user agent and serve a fallback image instead. Then use this for your video/autoplay/resume issue:
$('.homepage .hero-slider').on('afterChange', function(event, slick, currentSlide, nextSlide) {
var $active = $('.slick-slide.slick-current.slick-active');
var video = $active.find('video');
if (video.length == 1) {
var $slickInstance = $(this);
// play() only works with a valid id as selector :)
var video = document.getElementById(video.attr('id'));
video.play();
$slickInstance.slick('slickPause');
video.addEventListener('ended', function () {
$slickInstance.slick('slickPlay');
}, false);
}
});
See this link: http://jitimanagementcoach.com/TC_test/tabbed4try.html
I've already got the videos to play and/or pause on one tab or another when a tab is clicked... but now I need the video on the Prelearn tab to "click" the Solution tab and play the video once the Prelearn video is finished. Here's the code:
<script>
var iframe1 = document.getElementById("prelearnvid");
var iframe2 = document.getElementById("solutionvid");
var player1 = $f(iframe1);
var player2 = $f(iframe2);
var prelearnBtn = document.getElementById("prelearnbtn");
prelearnBtn.addEventListener("click", function() {player1.api("play");player2.api("pause");});
var solutionBtn = document.getElementById("solutionbtn");
solutionBtn.addEventListener("click", function() {player2.api("play");player1.api("pause");});
player1.addEvent('ready', function() {player1.addEvent('finish', onFinish);});
function onFinish(id) {window.location.href = '#solution-tab';};
</script>
It all works fine until the very last two lines... where am I going wrong?
The ready event is not firing for your player. In order for the player's events to fire, you need to add a player_id parameter to your URL that includes the id of your <iframe>.
Change the src attribute of your <iframe> to this:
<iframe id="prelearnvid" src="http://player.vimeo.com/video/92349330?&player_id=prelearnvid"
From the Froogaloop documentation:
If you’re embedding and controlling multiple players on a page or
using our JS API library (Froogaloop), you should give each player a
player_id that matches the id of the iframe element.
This stackoverflow answer and this forum post helped uncover this solution.