I have a youtube video that I've embedded with youtube's iFrame API. I would like to:
show a translucent overlay when a user pauses the video (WORKS)
hide that overlay when the user plays the video (WORKS)
NOT show an overlay when the user is "seeking" via the youtube controls (POSSIBLE?)
Having trouble controlling the seek behavior. Is it possible?
To reproduce, hold the seek at the same position for a few seconds and watch the overlay appear. Example jsfiddle is here:
http://jsfiddle.net/dNU84/3/
var ytvideo;
window.onYouTubePlayerAPIReady = function () {
ytvideo = new YT.Player('ytvideo', {
width: '400',
height: '300',
videoId: 'BOksW_NabEk',
playerVars: {
'autoplay': 1,
'controls': 1
},
events: {
"onStateChange": onPlayerStateChange
}
});
}
function showOverlay() {
if ($('.video .video-overlay').length) $('.video .video-overlay').fadeIn(1200);
}
function hideOverlay() {
if ($('.video .video-overlay').length) $('.video .video-overlay').hide();
}
var overlay;
function onPlayerStateChange(event) {
console.log(event.data);
clearTimeout(overlay);
// youtube fires 2xPAUSED, 1xPLAYING on seek
if (event.data == YT.PlayerState.PAUSED) {
overlay = setTimeout(showOverlay, 1000);
}
if (event.data == YT.PlayerState.PLAYING) {
overlay = hideOverlay();
}
}
Unfortunately, the YouTube player APIs don't have a reliable way to report on a "seek" state. If you're interested, here's a link to an (older) explanation as to why this is the case:
https://groups.google.com/forum/#!topic/youtube-api-gdata/1xGLZ54YOPI
If you have any desire to use a chromeless player instead of the default one with YouTube controls, you can get around this limitation by listening for events on your custom scrubber ... as a simple example, jQuery UI's slider can be set up as a scrubber for a chromeless player and report the "seek" state by using the 'start,' 'stop,' and 'slide' events.
I know this question is old, but I was just searching for a solution to this because I show an overlay on pause, but the overlay was showing each time the user would seek as well due to both event values being 2.
The easiest solution I've come across is to set a one second timeout:
setTimeout(function() {
if ( event.target.getPlayerState() == 2 ) {
// execute your code here for paused state
}
}, 1000)
This will only execute code on the paused state, and not on seek because after the 1 second timeout the PlayerState would be 1 again if it were the user seeking.
Related
Attempting to use a self hosted video background hero (in wordpress with elemnetor) that auto plays on load but with no sound as it should be muted for both ADA compliance and to be supported by certain web browsers.
I am wondering if it's possible to have a button/icon that unmutes the sound but also restarts the video at the same time so the 30 sec message and sound starts over from the beginning?
Problem:
I have it set up to auto play with no sound and added an icon using this technique and this code (https://elementorcodes.com/elementor-video-background-sound-button/) but how can I trigger a restart at the same time?
Code:
document.addEventListener('DOMContentLoaded', function() {
var toggleSoundButton = document.querySelector('.fa-volume-mute');
var heroBackgroundVideo = document.querySelector('.herosection video');
toggleSoundButton.addEventListener('click', function (event) {
if (heroBackgroundVideo.muted !== false){
heroBackgroundVideo.muted=false;
toggleSoundButton.classList.add('fa-volume-up');
} else {
heroBackgroundVideo.muted=true;
toggleSoundButton.classList.remove('fa-volume-up');
} }); });
</script>
heroBackgroundVideo.currentTime = 0;
heroBackgroundVideo.play();
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.
I'm using YouTube's API for embedded videos. I use the exact same API code for every video on every page. But on one particular video, it loads with subtitles, but only for the first run. Hit refresh and the subtitles disappear. Clear cache and cookies and they're back.
Why is this behavior manifesting for one video, but not any of the others that share the same code?
Ok so here is the HTML tag:
<div id="youTube" data-video-id="[YouTube video ID here]"></div>
And here is the API code:
window.onYouTubeIframeAPIReady = function () {
player = new YT.Player('youTube', {
videoId: $("#youTube").data("videoId"),
playerVars: {
'rel': 0,
},
events: {
'onReady': function () {
player.unMute();
player.setVolume(35);
player.playVideo();
},
'onStateChange': function () {
if (player.getPlayerState() == 2 && !counted) {
viewCount++;
counted = true;
}
}
}
});
}
Oh, and here's a couple more bits of relevant information:
The bug is repeatable on any client, and it shows up whether deployed to server or from localhost.
I cannot get rid of subtitles using 'cc_load_policy': 0,
The subtitles do not show up on when viewing the video on YouTube.com
I don't get subtitles when I use the iframe embed code instead of the full API:
Again, I have other videos that share the same API code with no subtitle bug.
* UPDATE *
Ok, now I'm seeing this same behavior with other videos. This did not used to happen, so I'm thinking it is something on the YouTube side.
...I still would like some help looking into this, though. Here's a jsfiddle:
https://jsfiddle.net/4ruz2xcx/3/
I have copied the Youtube embedded player demo code Youtube embedded player demo code almost verbatim - the changes are inserting console.log so that I can see what is going on.
<!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 = "https://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',
videoId: 'M7lc1UVf-VE',
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
}
// 4. The API will call this function when the video player is ready.
function onPlayerReady(event) {
console.log('onPlayerReady');
event.target.playVideo();
}
// 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.
var done = false;
function onPlayerStateChange(event) {
console.log('onPlayerStateChange');
if (event.data == YT.PlayerState.PLAYING && !done) {
setTimeout(stopVideo, 6000);
done = true;
}
}
function stopVideo() {
player.stopVideo();
}
</script>
</body>
</html>
This works as intended in Safari and Firefox, that is once the API loads the choosen video plays for six seconds and the console.log contains evidence that the events are firing. However in Internet Explorer the events onReady and onStateChange do not fire. The video will play if I manually click the play control in the player but I do not get the expected onStateChange events.
I checked the version of Flash on my machine and it is: 11.2.202.228 and the current available is 12.0.0.70. If I disable Flash in IE (manage add ons) the player works as expected: plays for 6 seconds and events fire.
I did not update Flash because while that might fix the issue on my machine my audience will be limited to those only that can do the same and if I updated I would not be able to find out if the issue was resolved by other means.
I have also tried to manually create the iframe myself as mentioned in the above Youtube documentation, this worked as expected in Firefox and Safari but not in IE.
There is a Youtube demo player this works perfectly in Firefox, the play, pause and stop controls via the API work and the events are clearly firing as the Events and Function Calls are written to the screen in the "Statistics" section. In contrast when I look at this in IE the play, pause and stop controls via the API do nothing. There is no output in the statistics section. The only way to play and pause is to use the buttons on the player. If I disable Flash then the player & API works perfectly.
If I try an iframe non API embed then the player works correctly, this leads me to believe that it is an issue arising from using the API.
I know some would say that all users should have the latest Flash, easier said than done. Many schools, companies and libraries lock down the options section in IE so the user would be able to turn off Flash for my site.
I wonder is there some way of turning off Flash when using the API?
I have searched around Stackoverflow and elsewhere and while I have found similar issues I have not found any fixes. I did find a somewhat similar promising lead but alas I had no joy. Also here and here and here and here and here.
I must point out that the issue is present when used on a local machine and on a website and even if I set the origin parameter.
I would appreciate suggestions and help. Thanks in advance.
I wonder is there some way of turning off Flash when using the API?
You could force the YouTube player to use its html5 player using the following option:
playerVars: {html5: 1}
Changing your code to:
// 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',
videoId: 'M7lc1UVf-VE',
playerVars: {
html5: 1
},
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
}
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 :)