Dynamically Pause YouTube Video via Unfocused Window from FancyBox - javascript

I already know how to play/pause a YouTube video dynamically as you can see from my weave.
However I'm having difficulty getting it to work dynamically with FancyBox using onBlur (when the window is not focused video should pause).
Here's my Pen: http://codepen.io/anon/pen/wJXoJy?editors=0010
// Show Lightbox Video Onload
$.fancybox.open({
youtube : {
controls : 0,
showinfo : 0
},
src : '//www.youtube.com/embed/-AszZcClVXA?enablejsapi=1', // Source of the content
type : 'iframe', // Content type: image|inline|ajax|iframe|html (optional)
});
// Inject YouTube API script
var tag = document.createElement('script');
tag.src = "//www.youtube.com/player_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
var player;
function onYouTubePlayerAPIReady(e) {
// create the global player from the specific iframe (#video)
player = new YT.Player($(".fancybox-iframe").attr("id"), {
events: {
// call this function when player is ready to use
'onReady': onPlayerReady
}
});
}
function onPlayerReady() {
window.addEventListener("blur", function() {
player.pauseVideo();
});
}
<link rel="stylesheet" href="//www.fancyapps.com/fancybox/3/fancybox/jquery.fancybox.min.css?v=1490320405" />
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="//www.fancyapps.com/fancybox/3/fancybox/jquery.fancybox.min.js?v=1490320405"></script>

Here is a demo - http://codepen.io/fancyapps/pen/jBKowp?editors=1010
Basically, idea is that you initialize fancyBox after YouTube API is available and then you can use YouTube API methods inside fancyBox callback.
// 1. 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);
// 2. This function initializes fancyBox
// after the API code downloads.
var player;
function onYouTubeIframeAPIReady() {
$('[data-fancybox="group"]').fancybox({
onComplete : function( instance, current ) {
if ( current.type === 'iframe' ) {
var id = current.$content.find('iframe').attr('id');
player = new YT.Player( id, {
events : {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
}
}
});
}
// 3. The API will call this function when the video player is ready.
function onPlayerReady(event) {
event.target.playVideo();
}
// 4. Fires when the player's state changes.
function onPlayerStateChange(event) {
// Go to the next video after the current one is finished playing
if (event.data === 0) {
$.fancybox.getInstance('next');
}
}
// Page Visibility API to pause video when window is not active
$(document).on("visibilitychange", function() {
if ( player ) {
if ( document.hidden ) {
player.pauseVideo();
} else {
player.playVideo();
}
}
});

You're only pausing the video on blur. Why not use mouseover event to play and mouseout event to pause the video?

Related

youtube iframe api not pausing video

I am currently working on a page with a slider with various iframe youtube embeds.
I am trying to get my JS to pause the video when you hit the "next" button on the slider. I think I've got everything set up according to the api.. but it doesn't seem to pause the videos when you click the slider button.
<script type="text/javascript">
// https://developers.google.com/youtube/iframe_api_reference
// global variable for the player
var player;
// this function gets called when API is ready to use
function onYouTubePlayerAPIReady() {
// create the global player from the specific iframe (#video)
player = new YT.Player('video', {
events: {
// call this function when player is ready to use
'onReady': onPlayerReady
}
});
}
function onPlayerReady(event) {
// bind events
var pauseButtonRight = document.getElementByID("pause-right");
pauseButtonRight.addEventListener("click", function() {
player.pauseVideo();
});
var pauseButtonLeft = document.getElementByID("pause-left");
pauseButtonLeft.addEventListener("click", function() {
player.pauseVideo();
});
}
// Inject YouTube API script
var tag = document.createElement('script');
tag.src = "//www.youtube.com/player_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
</script>
my iframes:
<iframe src="https://www.youtube.com/embed/6QB6jVjA2js?enablejsapi=1&html5=1&" frameborder="0" allowfullscreen="0"></iframe>
Any direction would be appreciated.
A few things :
this is document.getElementById not document.getElementByID
you've instanciated a Youtube player with id 'video' but your iframe don't have any id :
<iframe id="video" src="https://www.youtube.com/embed/6QB6jVjA2js?enablejsapi=1&html5=1&" frameborder="0" allowfullscreen="0"></iframe>
use onYouTubeIframeAPIReady instead of onYouTubePlayerAPIReady
You will have something like :
var player;
function onYouTubeIframeAPIReady() {
// create the global player from the specific iframe (#video)
player = new YT.Player('video', {
events: {
// call this function when player is ready to use
'onReady': onPlayerReady
}
});
}
function onPlayerReady(event) {
var pauseButtonRight = document.getElementById("pause");
pauseButtonRight.addEventListener("click", function() {
player.pauseVideo();
});
var pauseButtonLeft = document.getElementById("play");
pauseButtonLeft.addEventListener("click", function() {
player.playVideo();
});
}
// Inject YouTube API script
var tag = document.createElement('script');
tag.src = "//www.youtube.com/player_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
with :
<iframe id="video" src="https://www.youtube.com/embed/6QB6jVjA2js?enablejsapi=1&html5=1&" frameborder="0" allowfullscreen="0"></iframe>
<input id="pause" type="submit" value="pause" />
<input id="play" type="submit" value="play" />
Check this fiddle
Check Youtube iframe API reference

YouTube API - events on a embedded iframe not working

I am trying to get a "pause" event with the YouTube API on a YouTube video created by AMP (Accelerated Mobile Pages) with this basic example: https://ampbyexample.com/components/amp-youtube/
The code works and I get a video showing. The next thing I wanted to do was do something when the video is paused. I've had a look on how to do this and I've got the current code:
//The iframe generated from AMP does not give an ID so I have added one
$('#AMP_1 iframe').attr('id', 'yt_player');
//Load API code
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
var player;
function onYouTubeIframeAPIReady() {
player = new YT.Player('yt_player', {
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
}
function onPlayerReady() {
console.log("READY");
}
function onPlayerStateChange() {
console.log("STATE CHANGE");
}
When I run this I am not getting console errors and none of the console.log calls are displaying anything. The player variable stays undefined.
The iframe produced by AMP does have "enablejsapi=1" in the URL.
Do I need to do anything/am I missing something, to get the pause event on the video?
You need to have a parameter on function onPlayerStateChange to get the event data.
function onPlayerStateChange(event) {
switch(event.data){
case 2:
console.log("PAUSE!")
break;
}
}
other event.data list
-1 (unstarted)
0 (ended)
1 (playing)
2 (paused)
3 (buffering)
5 (video cued).

Black borders in YouTube player - Javascript API

I am adding a youtube video using YouTube Player API , based on the example provided from Getting Started.
Black borders(top and bottom) are my problem. And on YouTube Player Parameters I didn't find a parameter which can solve my problem.
Is there a way to hide the black borders, without CSS?
This is the code that I use(I only added playerVars in new YT.Player):
<!--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 : 'St_dIV8NIoc',
//
// here is where youtube player parameters are placed
//
playerVars : {
controls : 0,
cc_load_policy : 0,
loop : 1,
autoplay: 1,
modestbranding: 0,
rel: 0,
showinfo: 0
},
events : {
'onReady' : onPlayerReady,
'onStateChange' : onPlayerStateChange
}
});
}
// 4. The API will call this function when the video player is ready.
function onPlayerReady(event) {
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) {
if (event.data == YT.PlayerState.PLAYING && !done) {
setTimeout(stopVideo, 6000);
done = true;
}
}
function stopVideo() {
player.stopVideo();
}
</script>
The example adds 30px to the standard-height(for the controls).
When you don't show the controls use the standard-size(640x360)
The standard-sizes are listed at https://developers.google.com/youtube/iframe_api_reference#Playback_quality

How to mix javascript and meteor to use youtube api

I am trying to implement the example youtube api html page described here: https://developers.google.com/youtube/iframe_api_reference in a meteor application.
I have read that you can use Template.<template name>.rendered to implement traditional javascript functionality within a meteor application.
So I attempted to implement that youtube example in meteor by putting it into a rendered function.
However No video will display.
I worry I am not understanding meteors capabilities. Is something like this even possible in meteor?
Code:
home.html:
enter code here
<template name="home">
<h1> Home</h1>
This is the home page
<!-- 1. The <iframe> (and video player) will replace this <div> tag. -->
<div id="player"></div>
<script>
</script>
</template>
home.js:
Template.home.rendered = function() {
// 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) {
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) {
if (event.data == YT.PlayerState.PLAYING && !done) {
setTimeout(stopVideo, 6000);
done = true;
}
}
function stopVideo() {
player.stopVideo();
}
}
P.s. I am aware of adrianliaw:youtube-iframe-api and do not want to use that. I would like a better understanding of how to implement this on my own. Hopefully doing so will further my knowledge of javascript and meteor.
I think the problem here is that after https://www.youtube.com/iframe_api loads, it will try to call the onYouTubeIframeAPIReady function but it can't find it. The code works if you change the functions to anonymous functions stored in variables that are available across the entire application.
home.html:
<head>
<title>test</title>
</head>
<body>
{{> home}}
</body>
<template name="home">
<h1> Home</h1>
This is the home page
<div id="player"></div>
</template>
home.js:
Template.home.rendered = function() {
/* 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;
onYouTubeIframeAPIReady = function() {
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. */
onPlayerReady = function(event) {
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;
onPlayerStateChange = function(event) {
if (event.data == YT.PlayerState.PLAYING && !done) {
setTimeout(stopVideo, 6000);
done = true;
}
};
stopVideo = function() {
player.stopVideo();
};
};
Notice the function declaration changes:
function onYouTubeIframeAPIReady() has been changed to
onYouTubeIframeAPIReady = function()
function onPlayerReady(event) has been changed to onPlayerReady
= function(event)
function onPlayerStateChange(event) has been changed to
onPlayerStateChange = function(event)
function stopVideo() has been changed to stopVideo = function()
These global variables are now callable by the injected YouTube script.

Youtube Player API Samples

I was trying the following code from the samples given on developers.google.com/*
<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: 'yZxrao3zou4',
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
}
// 4. The API will call this function when the video player is ready.
function onPlayerReady(event) {
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) {
if (event.data == YT.PlayerState.PLAYING && !done) {
setTimeout(stopVideo, 6000);
done = true;
}
}
function stopVideo() {
player.stopVideo();
}
</script>
The code works perfectly when I have nothing else on my web page, but when I try to merge it with my project it doesn't seem to work.
I am guessing the problem is with the following lines:
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
Can someone tell me what does the above two lines do, especially the [0] part?
My code is pretty much the same except that instead of the script tag I have the code inside a function, which takes in a argument for the videoId.
EDIT:
My code is as follows:
<script>
// I have a input area, where the user can enter the movie name. When the user submits the movie name, I capture the val and pass it to the youtube().
function youtube(movie_name) {
var videoId;
$.ajax({
url:"https://www.googleapis.com/youtube/v3/search?part=snippet&q="+movie_name+"&type=video&key=my_key",
success: function (response) {
videoId = response.items[0].id.videoId;
findMovieById(videoId);
}
});
}
function findMovieById(videoID) {
$("#player").css('display', 'inline-block');
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: ""+videoID,
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
}
// 4. The API will call this function when the video player is ready.
function onPlayerReady(event) {
alert('Player Ready');
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) {
if (event.data == YT.PlayerState.PLAYING && !done) {
setTimeout(stopVideo, 6000);
done = true;
}
}
function stopVideo() {
player.stopVideo();
}
}
</script>
The idea behind the sample code is that it is much more consistent when you load the YouTube iFrame library code after the rest of the page has loaded; hence the sample code demonstrates that you put an inline at the bottom of the page, and within that, you traverse the DOM, find a place where you can insert another tag, and do so dynamically (the [0] just says 'the first entry in the array of all elements of name in the document).
The logic here is that, when the iFrame library loads, it will call the function onYouTubeIframeAPIReady. But since the library loads asynchronously, it's best to load it this way to ensure that anything else that your API hooks might depend on (the element in the DOM you're binding to, for example) already exists.
Also note that, because the loaded library will always call the onYouTubeIframeAPIReady function, it MUST be defined outside any other function. Otherwise it isn't callable. That could be why nesting it inside your code somewhere isn't working.
Feel free to post some of your merged code for more detailed help.

Categories