I am making a chrome extension that needs to know if a YouTube video is being played, paused, had a duration change, and if it is on an ad. I figured out how to do everything except knowing if it is on an advertisement. I found this post which was of some help, however, if I were to put this in my content script it would only run once and I want it to constantly check if there is an ad (since ads can happen in the middle of a video.
I am fairly new to Javascript, but I do understand the concepts of listeners and I would use a listener in this case, however, I do not know how to do that in this case because the div does not emit an event, it either exists or is null. Are there any other ways of doing that?
+1 to looking at YouTube video API events. Here's that page [0].
I haven't tried this myself, but I would start with the onStateChange event, because I suspect that an ad is a separate video from the desired video content itself. So there could be two "video cued" or "5" values fired. But, again, I haven't tried it myself. Good luck!
[0] https://developers.google.com/youtube/iframe_api_reference#Events
You can also use setInterval to detect ads continuously. This is a way without having to looking for API.
// According to the post you provided
function detectAds() {
return !!document.querySelector("div.ad-showing");
}
let timer;
function listen() {
timer = setInterval(function () {
if (detectAds()) { /* do something */ }
}, 1000); // runs every second
}
function unlisten() {
if (timer) clearInterval(timer);
}
I am trying to embed a vimeo video using iframe in my Qualtrics survey. When this video ends, I want to automatically advance to the next page (i.e., automatically press the "next button"). Before using vimeo, my videos were stored on dropbox and I used the following code for this (the url is not the real one):
<video autoplay="" id="video1" height="580" width="740"><source src="https://dl.dropboxusercontent.com/u/6339921/att/fam.mp4" type="video/mp4"></video>
Qualtrics.SurveyEngine.addOnload(function() {
that = this;
document.getElementById('video1').addEventListener('ended',myHandler,false);
function myHandler(e) {
if(!e) {
e = window.event;
}
that.clickNextButton();
}
});
However, it seems that I have to use iframe with vimeo, but I am unable to make the auto-advance work (the video will play but the page will not advance). Maybe it is because I am assigning the "ID" the wrong way. Here is the code:
<iframe id="player1" src="https://player.vimeo.com/video/20708824?autoplay=1api=1&player_id=player1&title=0&byline=0&portrait=0&background=1&mute=0&loop=0" width="600" height="400" frameborder="0"></iframe>
Qualtrics.SurveyEngine.addOnload(function() {
that = this;
var idPlayer = new Vimeo.Player('player1');
document.getElementByID('player1').addEventListener('ended',myHandler,false);
function myHandler(e) {
if(!e) { e = window.event; }
that.clickNextButton();
}
});
I am looking for a) an option to fix the iframe code, or b) an option to embed a vimeo video using the old code that I had used with dropbox videos.
Thanks so much and I apologize if this all sounds naive, I am not a programmer :-(
You can't add an event listener to an iframe from a different domain. It is called cross-domain scripting and for security reasons isn't allowed by the browser.
You have to use postMessage. There is a JavaScript class already written, but you would have figure out how to integrate it into Qualtrics:
https://github.com/vimeo/player.js
I'm creating this webpage on wordpress which have videos from youtube in some of it's posts, for tagging purposes I need to capture everytime a person clicks play on each of the videos. I've looked through the web, but all I could find is that, since this videos are on iframes from outside the main domain, it's impossible to catch something from the inside of it, like clicks.
Is there any way that I can catch this clicks on the play button without changing anything on the site? Just from JS.
Regards and thanks in advance.
You could capture some events within the iframe using youtube's js API
This is what you have to do:
1). Load the Player API in your page
<script src="http://www.youtube.com/player_api"></script>
2). Enable jsapi in your iframe as a trailing parameter (enablejsapi) like
<iframe id="myIframe" src="http://www.youtube.com/embed/opj24KnzrWo?enablejsapi=1&autoplay=0" width="420" height="280" frameborder="0"></iframe>
... also notice we added an ID to the iframe.
3). Create 3 functions :
a). onPlayerReady :
Here is where you can detect when the video has loaded and is ready to play. Here you can actually start the video, etc.
function onPlayerReady(event) {
// video is ready, do something
event.target.playVideo();
}
b). onPlayerStateChange :
Here is where you can detect what events are triggered:
function onPlayerStateChange(event) {
console.log(event.data); // event triggered
// e.g. end of video
if (event.data === 0) {
// end of video: do something here
}
}
When you click play or pause, an event is triggered. Then you can decide what action you want do, including pushing a tracking event, etc.
This is a list of the returned values of each event :
-1 – unstarted
0 – ended
1 – playing
2 – paused
3 – buffering
5 – video cued
Refer to the documentation to learn more about those events
c). onYouTubePlayerAPIReady :
This is where you actually initialize the API and bind the events to the other functions :
function onYouTubePlayerAPIReady() {
var id = document.getElementById("myIframe").getAttribute("id");
var player = new YT.Player(id, {
events: {
onReady: onPlayerReady,
onStateChange: onPlayerStateChange
}
});
} // youtube API ready
See JSFIDDLE
I have this test slider http://jsfiddle.net/dUyLY/2/
In Chrome it works nice, but in firefox and safari it bugs out when the animation is done.
In the scripts file I check after each animation if the current visible element is the youtube player, if so play the video. And when leaving the slide pause it.
I get this error in console player.pauseVideo is not a function
Anyone has a solution to this?
You're deferring the definition of onYouTubePlayerAPIReady. For this reason, it's likely that the YouTube API finishes before onYouTubePlayerAPIReady is defined. In that case, your code will fail.
To solve the problem, check whether the API is ready at run-time.
window.onYouTubePlayerAPIReady = function () {
player = new YT.Player('player', {
height: '315',
width: '560',
videoId: 'bpOR_HuHRNs',
});
};
if (window.YT) {
// Apparently, the API was ready before this script was executed.
// Manually invoke the function
onYouTubePlayerAPIReady();
}
Note. For simple one-way functions, such as player.playVideo() and player.pauseVideo(), I recommend to use this simple function, which is not as bloated as the documented YouTube API. See this answer.
Here's a the updated part of your page, using the callPlayer function from my other answer instead of the YouTube API: http://jsfiddle.net/ryyCZ/
<div id="player">
<iframe width="560" height="315" frameborder="0" src="http://www.youtube.com/embed/bpOR_HuHRNs?enablejsapi=1"></iframe>
</div>
if ($(".slides_control > div:visible #player").length == 1) {
callPlayer("player","playVideo");
} else {
callPlayer("player", "pauseVideo");
}
I have a hidden div containing a YouTube video in an <iframe>. When the user clicks on a link, this div becomes visible, the user should then be able to play the video.
When the user closes the panel, the video should stop playback. How can I achieve this?
Code:
<!-- link to open popupVid -->
<p>Click here to see my presenting showreel, to give you an idea of my style - usually described as authoritative, affable and and engaging.</p>
<!-- popup and contents -->
<div id="popupVid" style="position:absolute;left:0px;top:87px;width:500px;background-color:#D05F27;height:auto;display:none;z-index:200;">
<iframe width="500" height="315" src="http://www.youtube.com/embed/T39hYJAwR40" frameborder="0" allowfullscreen></iframe>
<br /><br />
<a href="javascript:;" onClick="document.getElementById('popupVid').style.display='none';">
close
</a>
</div><!--end of popupVid -->
The easiest way to implement this behaviour is by calling the pauseVideo and playVideo methods, when necessary. Inspired by the result of my previous answer, I have written a pluginless function to achieve the desired behaviour.
The only adjustments:
I have added a function, toggleVideo
I have added ?enablejsapi=1 to YouTube's URL, to enable the feature
Demo: http://jsfiddle.net/ZcMkt/
Code:
<script>
function toggleVideo(state) {
// if state == 'hide', hide. Else: show video
var div = document.getElementById("popupVid");
var iframe = div.getElementsByTagName("iframe")[0].contentWindow;
div.style.display = state == 'hide' ? 'none' : '';
func = state == 'hide' ? 'pauseVideo' : 'playVideo';
iframe.postMessage('{"event":"command","func":"' + func + '","args":""}', '*');
}
</script>
<p>Click here to see my presenting showreel, to give you an idea of my style - usually described as authoritative, affable and and engaging.</p>
<!-- popup and contents -->
<div id="popupVid" style="position:absolute;left:0px;top:87px;width:500px;background-color:#D05F27;height:auto;display:none;z-index:200;">
<iframe width="500" height="315" src="http://www.youtube.com/embed/T39hYJAwR40?enablejsapi=1" frameborder="0" allowfullscreen></iframe>
<br /><br />
close
Here's a jQuery take on RobW's answer for use hiding /pausing an iframe in a modal window:
function toggleVideo(state) {
if(state == 'hide'){
$('#video-div').modal('hide');
document.getElementById('video-iframe'+id).contentWindow.postMessage('{"event":"command","func":"pauseVideo","args":""}', '*');
}
else {
$('#video-div').modal('show');
document.getElementById('video-iframe'+id).contentWindow.postMessage('{"event":"command","func":"playVideo","args":""}', '*');
}
}
The html elements referred to are the modal div itself (#video-div) calling the show / hide methods, and the iframe (#video-iframe) which has the video url as is src="" and has the suffix enablejsapi=1? which enables programmatic control of the player (ex. .
For more on the html see RobW's answer.
Here is a simple jQuery snippet to pause all videos on the page based off of RobW's and DrewT's answers:
jQuery("iframe").each(function() {
jQuery(this)[0].contentWindow.postMessage('{"event":"command","func":"pauseVideo","args":""}', '*')
});
Hey an easy way is to simply set the src of the video to nothing, so that the video will desapear while it's hidden an then set the src back to the video you want when you click on the link that opens the video.. to do that simply set an id to the youtube iframe and call the src function using that id like this:
<script type="text/javascript">
function deleteVideo()
{
document.getElementById('VideoPlayer').src='';
}
function LoadVideo()
{
document.getElementById('VideoPlayer').src='http://www.youtube.com/embed/WHAT,EVER,YOUTUBE,VIDEO,YOU,WHANT';
}
</script>
<body>
<p onclick="LoadVideo()">LOAD VIDEO</P>
<p onclick="deleteVideo()">CLOSE</P>
<iframe id="VideoPlayer" width="853" height="480" src="http://www.youtube.com/WHAT,EVER,YOUTUBE,VIDEO,YOU,HAVE" frameborder="0" allowfullscreen></iframe>
</boby>
Since you need to set ?enablejsapi=true in the src of the iframe before you can use the playVideo / pauseVideo commands mentioned in other answers, it might be useful to add this programmatically via Javascript (especially if, eg. you want this behaviour to apply to videos embedded by other users who have just cut and paste a YouTube embed code). In that case, something like this might be useful:
function initVideos() {
// Find all video iframes on the page:
var iframes = $(".video").find("iframe");
// For each of them:
for (var i = 0; i < iframes.length; i++) {
// If "enablejsapi" is not set on the iframe's src, set it:
if (iframes[i].src.indexOf("enablejsapi") === -1) {
// ...check whether there is already a query string or not:
// (ie. whether to prefix "enablejsapi" with a "?" or an "&")
var prefix = (iframes[i].src.indexOf("?") === -1) ? "?" : "&";
iframes[i].src += prefix + "enablejsapi=true";
}
}
}
...if you call this on document.ready then all iframes in a div with a class of "video" will have enablejsapi=true added to their source, which allows the playVideo / pauseVideo commands to work on them.
(nb. this example uses jQuery for that one line that sets var iframes, but the general approach should work just as well with pure Javascript if you're not using jQuery).
I wanted to share a solution I came up with using jQuery that works if you have multiple YouTube videos embedded on a single page. In my case, I have defined a modal popup for each video as follows:
<div id="videoModalXX">
...
<button onclick="stopVideo(videoID);" type="button" class="close"></button>
...
<iframe width="90%" height="400" src="//www.youtube-nocookie.com/embed/video_id?rel=0&enablejsapi=1&version=3" frameborder="0" allowfullscreen></iframe>
...
</div>
In this case, videoModalXX represents a unique id for the video. Then, the following function stops the video:
function stopVideo(id)
{
$("#videoModal" + id + " iframe")[0].contentWindow.postMessage('{"event":"command","func":"pauseVideo","args":""}', '*');
}
I like this approach because it keeps the video paused where you left off in case you want to go back and continue watching later. It works well for me because it's looking for the iframe inside of the video modal with a specific id. No special YouTube element ID is required. Hopefully, someone will find this useful as well.
You can stop the video by calling the stopVideo() method on the YouTube player instance before hiding the div e.g.
player.stopVideo()
For more details see here: http://code.google.com/apis/youtube/js_api_reference.html#Playback_controls
RobW's way worked great for me. For people using jQuery here's a simplified version that I ended up using:
var iframe = $(video_player_div).find('iframe');
var src = $(iframe).attr('src');
$(iframe).attr('src', '').attr('src', src);
In this example "video_player" is a parent div containing the iframe.
just remove src of iframe
$('button.close').click(function(){
$('iframe').attr('src','');;
});
Rob W answer helped me figure out how to pause a video over iframe when a slider is hidden. Yet, I needed some modifications before I could get it to work. Here is snippet of my html:
<div class="flexslider" style="height: 330px;">
<ul class="slides">
<li class="post-64"><img src="http://localhost/.../Banner_image.jpg"></li>
<li class="post-65><img src="http://localhost/..../banner_image_2.jpg "></li>
<li class="post-67 ">
<div class="fluid-width-video-wrapper ">
<iframe frameborder="0 " allowfullscreen=" " src="//www.youtube.com/embed/video-ID?enablejsapi=1 " id="fitvid831673 "></iframe>
</div>
</li>
</ul>
</div>
Observe that this works on localhosts and also as Rob W mentioned "enablejsapi=1" was added to the end of the video URL.
Following is my JS file:
jQuery(document).ready(function($){
jQuery(".flexslider").click(function (e) {
setTimeout(checkiframe, 1000); //Checking the DOM if iframe is hidden. Timer is used to wait for 1 second before checking the DOM if its updated
});
});
function checkiframe(){
var iframe_flag =jQuery("iframe").is(":visible"); //Flagging if iFrame is Visible
console.log(iframe_flag);
var tooglePlay=0;
if (iframe_flag) { //If Visible then AutoPlaying the Video
tooglePlay=1;
setTimeout(toogleVideo, 1000); //Also using timeout here
}
if (!iframe_flag) {
tooglePlay =0;
setTimeout(toogleVideo('hide'), 1000);
}
}
function toogleVideo(state) {
var div = document.getElementsByTagName("iframe")[0].contentWindow;
func = state == 'hide' ? 'pauseVideo' : 'playVideo';
div.postMessage('{"event":"command","func":"' + func + '","args":""}', '*');
};
Also, as a simpler example, check this out on JSFiddle
This approach requires jQuery. First, select your iframe:
var yourIframe = $('iframe#yourId');
//yourId or something to select your iframe.
Now you select button play/pause of this iframe and click it
$('button.ytp-play-button.ytp-button', yourIframe).click();
I hope it will help you.
RobW's answers here and elsewhere were very helpful, but I found my needs to be much simpler. I've answered this elsewhere, but perhaps it will be useful here also.
I have a method where I form an HTML string to be loaded in a UIWebView:
NSString *urlString = [NSString stringWithFormat:#"https://www.youtube.com/embed/%#",videoID];
preparedHTML = [NSString stringWithFormat:#"<html><body style='background:none; text-align:center;'><script type='text/javascript' src='http://www.youtube.com/iframe_api'></script><script type='text/javascript'>var player; function onYouTubeIframeAPIReady(){player=new YT.Player('player')}</script><iframe id='player' class='youtube-player' type='text/html' width='%f' height='%f' src='%#?rel=0&showinfo=0&enablejsapi=1' style='text-align:center; border: 6px solid; border-radius:5px; background-color:transparent;' rel=nofollow allowfullscreen></iframe></body></html>", 628.0f, 352.0f, urlString];
You can ignore the styling stuff in the preparedHTML string. The important aspects are:
Using the API to create the "YT.player" object. At one point, I only had the video in the iFrame tag and that prevented me from referencing the "player" object later with JS.
I've seen a few examples on the web where the first script tag (the one with the iframe_api src tag) is omitted, but I definitely needed that to get this working.
Creating the "player" variable at the beginning of the API script. I have also seen some examples that have omitted that line.
Adding an id tag to the iFrame to be referenced in the API script. I almost forgot that part.
Adding "enablejsapi=1" to the end of the iFrame src tag. That hung me up for a while, as I initially had it as an attribute of the iFrame tag, which does not work/did not work for me.
When I need to pause the video, I just run this:
[webView stringByEvaluatingJavaScriptFromString:#"player.pauseVideo();"];
Hope that helps!
This is working fine to me with YT player
createPlayer(): void {
return new window['YT'].Player(this.youtube.playerId, {
height: this.youtube.playerHeight,
width: this.youtube.playerWidth,
playerVars: {
rel: 0,
showinfo: 0
}
});
}
this.youtube.player.pauseVideo();
A more concise, elegant, and secure answer: add “?enablejsapi=1” to the end of the video URL, then construct and stringify an ordinary object representing the pause command:
const YouTube_pause_video_command_JSON = JSON.stringify(Object.create(null, {
"event": {
"value": "command",
"enumerable": true
},
"func": {
"value": "pauseVideo",
"enumerable": true
}
}));
Use the Window.postMessage method to send the resulting JSON string to the embedded video document:
// |iframe_element| is defined elsewhere.
const video_URL = iframe_element.getAttributeNS(null, "src");
iframe_element.contentWindow.postMessage(YouTube_pause_video_command_JSON, video_URL);
Make sure you specify the video URL for the Window.postMessage method’s targetOrigin argument to ensure that your messages won’t be sent to any unintended recipient.