Pause youtube video, youtube api - javascript

I'm trying to pause and play YouTube videos with the following code which is pretty much a copy from the Youtube API page:
// 2. This code loads the IFrame Player API code asynchronously.
var tag = document.createElement('script');
tag.src = "http://www.youtube.com/player_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 onYouTubePlayerAPIReady() {
player = new YT.Player('player', {
height: '315',
width: '560',
videoId: 'bpOR_HuHRNs',
});
}
Here's a demo in jsFiddle
However, it's not working. Anyone have a idea how to do this?

Use player.playVideo(); (resume) and player.pauseVideo(); (pause) once the player is ready: http://jsfiddle.net/4WPmY/6/
function onYouTubePlayerAPIReady() {
    player = new YT.Player('player', {
        height: '315',
        width: '560',
        videoId: 'bpOR_HuHRNs',
    });
    document.getElementById('resume').onclick = function() {
        player.playVideo();
    };
    document.getElementById('pause').onclick = function() {
        player.pauseVideo();
    };
}

In your HTML, have some buttons to control the video:
<input type="button" id="play">
<input type="button" id="pause">
Using jQuery, bind an event listener (the click) to trigger a function on your player object:
$(function() {
$('#play').click(function() {
player.playVideo();
});
$('#pause').click(function() {
player.pauseVideo();
});
});
I built an app using YouTube's Player and Data api. Take what you need:
https://github.com/HunterMeyer/YouTV

<div id="player"></div>
Play
In this code I added the Resume and Pause buttons in one: Example
// 2. This code loads the IFrame Player API code asynchronously.
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/player_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 onYouTubePlayerAPIReady() {
player = new YT.Player('player', {
height: '315',
width: '560',
videoId: '0Bmhjf0rKe8',
events: {
'onStateChange': onPlayerStateChange
}
});
document.getElementById('resume').onclick = function() {
PlayPause();
return false;
};
}
// 4. This function change name of tag click.
var playerState;
function onPlayerStateChange(event) {
var getId = document.getElementById('resume');
if(event.data === 0) {
getId.innerText = 'Play';
}
else if(event.data === 1) {
getId.innerText = 'Pause';
}
else if(event.data === 2) {
getId.innerText = 'Resume';
}
else if(event.data === 3) {
getId.innerText = 'Loading...';
}
playerState = event.data;
}
// 5. This function Play/Pause the video.
function PlayPause() {
if(playerState == '1') {
player.pauseVideo();
}
else {
player.playVideo();
}
}

Related

using YouTube iFrame API within jQuery event

I have a page in which clicking a link opens a lightbox and embeds a YouTube video in an <iframe>. The lightbox and <iframe> markup are generate on the fly by Lity.
Following the example right out of the documentation, where the <iframe> is hard-coded into the page, it works as expected.
<iframe id="existing-iframe-example"
width="640" height="360"
src="https://www.youtube.com/embed/M7lc1UVf-VE?enablejsapi=1"
frameborder="0"
style="border: solid 4px #37474F">
</iframe>
<script type="text/javascript">
var tag = document.createElement('script');
tag.id = 'iframe-demo';
tag.src = 'https://www.youtube.com/iframe_api';
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
var player;
function onYouTubeIframeAPIReady() {
console.log('api ready');
player = new YT.Player('existing-iframe-example', {
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
}
function onPlayerReady(event) {
document.getElementById('existing-iframe-example').style.borderColor = '#FF6D00';
}
function changeBorderColor(playerStatus) {
var color;
if (playerStatus == -1) {
color = "#37474F"; // unstarted = gray
} else if (playerStatus == 0) {
color = "#FFFF00"; // ended = yellow
} else if (playerStatus == 1) {
color = "#33691E"; // playing = green
} else if (playerStatus == 2) {
color = "#DD2C00"; // paused = red
} else if (playerStatus == 3) {
color = "#AA00FF"; // buffering = purple
} else if (playerStatus == 5) {
color = "#FF6DOO"; // video cued = orange
}
if (color) {
document.getElementById('existing-iframe-example').style.borderColor = color;
}
}
function onPlayerStateChange(event) {
changeBorderColor(event.data);
}
</script>
See this Codepen
I'm trying to modify it to work with a dynamically generated <iframe> (which is how Lity handles YouTube videos). I can see that the YouTube API script is being added to the page, but the function onYouTubeIframeAPIReady does not ever seem to be called, which according to documentation is supposed to fire as soon as API script loads.
HTML (to open lightbox)
<a href="https://www.youtube.com/embed/M7lc1UVf-VE?enablejsapi=1" class="lity" data-lity>open</a>
JavaScript (fires after lightbox object is available in DOM)
$(document).on("lity:ready", function (event, instance) {
console.log("Lightbox ready");
$(".lity-youtube iframe").attr("id", "x");
if ($("iframe#x").length) {
console.log("ID added to <iframe>");
} else {
console.log("ID NOT added to <iframe>");
}
var tag = document.createElement("script");
tag.id = "iframe-demo";
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName("script")[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
if ($("#iframe-demo").length) {
console.log("api script added");
} else {
console.log("api script NOT added");
}
var player;
function onYouTubeIframeAPIReady() {
console.log("api ready");
player = new YT.Player("x", {
events: {
onReady: onPlayerReady,
onStateChange: onPlayerStateChange
}
});
}
function onPlayerReady(event) {
console.log("player ready");
document.getElementById("x").style.borderColor = "#FF6D00";
}
function changeBorderColor(playerStatus) {
var color;
if (playerStatus == -1) {
color = "#37474F"; // unstarted = gray
} else if (playerStatus == 0) {
color = "#FFFF00"; // ended = yellow
} else if (playerStatus == 1) {
color = "#33691E"; // playing = green
} else if (playerStatus == 2) {
color = "#DD2C00"; // paused = red
} else if (playerStatus == 3) {
color = "#AA00FF"; // buffering = purple
} else if (playerStatus == 5) {
color = "#FF6DOO"; // video cued = orange
}
if (color) {
document.getElementById("x").style.borderColor = color;
}
}
function onPlayerStateChange(event) {
console.log('state change');
changeBorderColor(event.data);
}
});
See this Codepen.
I tried pulling everything out of the lity:ready event handler with the same results....
Can anyone see what's going wrong?
EDIT/UPDATE
I tried running onYouTubeIframeAPIReady as a deferred object
var YTdeferred = $.Deferred();
window.onYouTubeIframeAPIReady = function() {
YTdeferred.resolve(window.YT);
};
and using it in the callback
var player;
YTdeferred.done(function (YT) {
console.log("api ready");
player = new YT.Player("x", {
events: {
//onReady: onPlayerReady,
//onStateChange: onPlayerStateChange
onReady: function () {
console.log("player ready from ananonymous");
},
onStateChange: onPlayerStateChange
}
});
console.log(player);
});
Now the YT.Player object is created (presumably on the iframe created by lity), but neither of the events (onReady and onStateChange) seem to be triggering. Also, it doesn't have access to any of the methods or properties that it should:
player.playVideo()
produces an error: player.playVideo is not a function`
Still stumped.
Codepen
ANOTHER EDIT/UPDATE
Now I'm very confused because i created a version that replicates what lity does (I think) and the events (onReady and onStateChange) do in fact fire as expected.
Codepen
Solution to a STUPID mistake
I can' believe I beat my head into the wall over this for so long... G'AAAAAAH!!
It's definitely a lity thing
When lity receives an argument (YouTube URL) formatted like
https://www.youtube.com/embed/XXXXXXXXX
or
http://youtu.be/XXXXXXXXX
it converts it to
https://www.youtube.com/embed/XXXXXXXXX?autoplay=1
If you try to pass query string arguments to to a similarly formatted URL (such as: https://www.youtube.com/embed/XXXXXXXXX?enablejsapi=1 (which is required for the API calls to work), it URLencodes the ?enablejsapi=1 and adds it to the end of the converted URL, so you get:
https://www.youtube.com/embed/XXXXXXXX?autoplay=1&%3Fenablejsapi=1
As a result the enablejsapi=1 is never read in and therefore the YT.Player is never attached to the <iframe> DOM element.
** SOLUTION **
Pass the URL to lity in a format that passes the video ID as a query string argument (and append enablejsapi=1):
https://www.youtube.com/watch?v=XXXXXXXX&enablejsapi=1
lity will now keep your argument(s) intact and convert to
https://www.youtube.com/embed/XXXXXXXX?autoplay=1&enablejsapi=1
Now the YT.Player call can read enablejsapi=1 and properly attach to the <iframe> element, and all is good in the universe.
<a href="https://www.youtube.com/watch?v=TJU-tBquzcM&enablejsapi=1" class="lity" data-lity>open lightbox with video</a>
Final Working CodePen
.
It looks like the "lity:ready" event is not fired in my case.
I changed
$(document).on("lity:ready", function (event, instance) {
to
$(document).ready(function (event, instance) {
using the jQuery ready event.
And most important, the function onYouTubeIframeAPIReady must be global (on window scope) to be detected by the youtube iFrame API (actually it was created inside an anonymous function() ). So I changed
function onYouTubeIframeAPIReady() {
to
window.onYouTubeIframeAPIReady=function() {
Codepen
EDIT:
To work on a global context inside an anonymous function. Other local functions created and referenced (onPlayerReady and onPlayerStateChange) must be declared in the global context using the window object.
window.onPlayerReady=function(event) {
console.log("player ready");
document.getElementById("x").style.borderColor = "#FF6D00";
}
window.changeBorderColor=function(playerStatus) {
var color;
if (playerStatus == -1) {
color = "#37474F"; // unstarted = gray
} else if (playerStatus == 0) {
color = "#FFFF00"; // ended = yellow
} else if (playerStatus == 1) {
color = "#33691E"; // playing = green
} else if (playerStatus == 2) {
color = "#DD2C00"; // paused = red
} else if (playerStatus == 3) {
color = "#AA00FF"; // buffering = purple
} else if (playerStatus == 5) {
color = "#FF6DOO"; // video cued = orange
}
if (color) {
document.getElementById("x").style.borderColor = color;
}
}
window.onPlayerStateChange=function(event) {
console.log('state change');
changeBorderColor(event.data);
}

Lose context of this when youtube constructor method is called

I have created a youtube player using the youtube iframe api, I am listening for the ENDED event but I've realised that I lose the reference to this which becomes the window but I'm really unsure how to resolve this. I've tried binding this to the contsructor etc but with no joy whatesoever so could really do with you guys help.
JS
startPlayer: function (videoId) {
var instance = this;
console.log('startPlayer', instance);
if( instance.flags.isPlaying ) {
instance.selectors.playerCtn.empty();
instance.flags.isPlaying = false;
}
instance.selectors.playerCtn.append('<div id="player"></div>');
instance.player = new YT.Player('player', {
height: '390',
width: '640',
videoId: videoId,
events: {
'onReady': this.onPlayerReady,
'onStateChange': this.onPlayerStateChange
}
});
instance.flags.isPlaying = true;
},
onPlayerStateChange: function (event) {
console.log('onPlayerStateChange');
var instance = this;
console.log(instance); //undefined??
if (event.data == YT.PlayerState.PLAYING) {
console.log('PLAYING...');
}
if (event.data == YT.PlayerState.PAUSED) {
console.log('PAUSED...');
}
if (event.data == YT.PlayerState.ENDED) {
console.log('what is this', instance);
// if instance.counter === instance.playlist
if (instance.counter === instance.playlist) {
console.log('you\'ve come to the end of your playlist');
// Display message or go back to first?
return;
}
// Increase the counter
instance.counter++
// Set the new current element
instance.current = instance.selectors.listItems[instance.counter];
console.log(instance.counter);
console.log(instance.current);
// Get the new current element data-id
var videoId = instance.current.attr('data-id');
// Start the player
startPlayer(videoId);
}
if (event.data == YT.PlayerState.BUFFERING) {
console.log('BUFFERING...');
}
}
Test page http://go.shr.lc/1lh2dmu
events: {
'onReady': this.onPlayerReady.bind(this),
'onStateChange': this.onPlayerStateChange.bind(this)
}
Besides, why var instance = this;? this is quite shorter to type and you aren't using instance in any closure.

Binding YouTube Video to Div Element from Seperate JS file

I have this problem embedding YouTube video in a PhoneJS single-page mobile application. In PhoneJS, the JS scripts are defined in a different file. So I defined the HTML div like this:
<div id="player"></div>
Now in the JS file, I did this:
function getVideo() {
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var playerDiv = document.getElementById('player');
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
var player;
function onYouTubeIframeAPIReady() {
player = new YT.Player(playerDiv, {
height: '250',
width: '444',
videoId: sIFYPQjYhv8
});
}
}
When I run and view the debugger, the call is made to Youtube and response is received, but it is not displayed on the view.
Ok since I am using KnockoutJS binding, I modified the div in the html view like this:
<iframe id="player" type="text/html" width="444" height="250" frameborder="0" data-bind="attr: { src: src }"></iframe>
And then pass in the src video id thus:
src: ko.observable('http://www.youtube.com/embed/' + sIFYPQjYhv8 + '?autoplay=1')
In this case however, in the debugger, the call is not even made to Youtube. Nothing just happens. Actually I prefer to use the API call instead of the second approach.
Any suggestions on how to make the first approach work? I mean using the API call?
EDIT
Just want to mention that when I add the code below in the view, the video is streamed alright.
<h1>Video</h1>
<div id="player"></div>
<script>
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var playerDiv = document.getElementById('player');
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
var player;
function onYouTubeIframeAPIReady() {
player = new YT.Player(playerDiv, {
height: '250',
width: '444',
videoId: 'sIFYPQjYhv8'
});
}
</script>
I think the easiest way to do this is to use a custom binding handler with a flag set from the onYouTubeIFrameAPIReady callback
Sample jsFiddle
ko.bindingHandlers['player'] = {
init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
// Check if global script and function is declared.
if ( !document.getElementById('playerScript') ) {
// Create script
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var playerDiv = document.getElementById('player');
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
// Create global function that their API calls back
window.playerReady = ko.observable(false);
window.onYouTubeIframeAPIReady = function() {
window.playerReady(true);
};
}
},
update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
var value = valueAccessor(),
id = value.id(),
height = ko.unwrap(value.height) || '250',
width = ko.unwrap(value.width) || '444'
;
if ( !value.id()) {
return;
}
if ( !window.playerReady() ) {
// YT hasn't invoked global callback. Subscribe to update
var subscription;
subscription = window.playerReady.subscribe( function(newValue) {
if ( newValue ) {
subscription.dispose();
// Just get this binding to fire again
value.id.notifySubscribers(value.id());
}
});
} else {
var player = new YT.Player( element, {
height: height,
width: width,
videoId: id
});
}
},
}
Now change your player div to
<div data-bind="player: { id: id, height: height, width: width }"></div>
Finally bind
var vm = {
id: 'sIFYPQjYhv8',
height: '250',
width: '444'
};
ko.applyBindings( vm )
EDIT
To remove the reliance on window, put your script tag that adds the new script element back, tweek as below, modify their callback and use a setTimeout instead of the "playerReady" observable
HTML Script
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
tag.setAttribute('id', 'playerScript');
tag.setAttribute('data-ready', 'false');
...
function onYouTubeIframeAPIReady = function() {
document.getElementById('playerScript').setAttribute('data-ready', 'true');
};
Player Binding
update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
var value = valueAccessor(),
id = value.id(),
height = ko.unwrap(value.height) || '250',
width = ko.unwrap(value.width) || '444',
playerScript = document.getElementById('playerScript')
;
if ( !value.id()) {
return;
}
if ( !playerScript || playerScript.getAttribute('data-ready') !== 'true' ) ) {
// YT hasn't invoked global callback.
setTimeout( function() {
value.id.notifySubscribers(value.id());
}, 50);
} else {
var player = new YT.Player( element, {
height: height,
width: width,
videoId: id
});
}
}

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/

Using an array in Jquery

I'm not so experienced with Javascript and I have been struggling with this one pretty much all day.
I'm using Jquery to create and array of the ids of embedded youtube videos:
$(function() {
$('li').on("click",function(){
alert($(this).attr('data-pile'));
var pilename = $(this).attr('data-pile');
var videoIDs = [];
$("li[data-pile='"+pilename+"']").each(function(index){
videoIDs.push($(this).attr('id'));
});
$.each(videoIDs,function(){
});
});
});
And I need to use the array in this JS:
<script src="//www.youtube.com/iframe_api"></script>
<script>
/**
* Put your video IDs in this array
*/
var videoIDs = [
//my array of Ids here
];
var player, currentVideoId = 0;
function onYouTubeIframeAPIReady() {
player = new YT.Player('player', {
height: '350',
width: '425',
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
}
function onPlayerReady(event) {
event.target.loadVideoById(videoIDs[currentVideoId]);
}
function onPlayerStateChange(event) {
if (event.data == YT.PlayerState.ENDED) {
currentVideoId++;
if (currentVideoId < videoIDs.length) {
player.loadVideoById(videoIDs[currentVideoId]);
}
}
}
</script>
In each div where embedded videos are I'm applying an id with same id as video.
How should I make the two scripts work?
I'll really appreciate if someone can point me in the right direction.
You're declaring your videoIDs array twice, once in your click events and again in your second
script.
The one inside your click events is local to that function whereas the other one is global. Javascript has function scope, so that click event one gets discarded once that function ends.
If you remove the one inside your click events, I believe it should work. You should also remove the $.each... as I don't think it's going to help (you're trying to make a playlist, right?).
It should be noted that it's considered bad practice to pollute the global namespace by using global variables. If this is all the code you have on your page, it's probably not an issue.
Try doing it this way: add a custom listener after "click" event. Didn't check your array forming section, tested with a custom array, hope you won't have issues with it.
<script>
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
function onYouTubeIframeAPIReady() {
player = new YT.Player('player', {
height: '350',
width: '425',
});
}
$(function(){
$(document.body).on("click",".play", function(){
player.stopVideo();
var pilename = $(this).attr('data-pile');
var videoIDs = [];
$("li[data-pile='"+pilename+"']").each(function(index){
videoIDs.push($(this).attr('id'));
});
if(videoIDs.length > 0){
currentVideoId = 0;
player.loadVideoById(videoIDs[0]);
function onPlayerStateChange(event) {
if (event.data == YT.PlayerState.ENDED) {
currentVideoId++;
if (currentVideoId < videoIDs.length) {
player.loadVideoById(videoIDs[currentVideoId]);
}
}
}
player.addEventListener("onStateChange", onPlayerStateChange)
player.playVideo();
}
});
});
</script>

Categories

Resources