YouTube API — not firing 'onYouTubePlayerReady()' - javascript

From what I've read, this is how I should setup the YouTube API:
<!DOCTYPE html>
<html lang="en">
<head>
<meta content='text/html;charset=UTF-8' http-equiv='content-type' />
<title>Youtube Player</title>
<script src="jquery.js" type="text/javascript"></script>
<script src="http://ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js" type="text/javascript"></script>
<script type="text/javascript" charset="utf-8">
function onYouTubePlayerReady(id) {
console.log("onYouTubePlayerReady() Fired!");
var player = $("#youtube_player").get(0);
}
var params = { allowScriptAccess: "always" };
var atts = { id: "youtube_player" };
swfobject.embedSWF("http://www.youtube.com/apiplayer?enablejsapi=1",
"youtube", "425", "356", "8", null, null, params, atts);
</script>
</head>
<body>
<div id="youtube"></div>
</body>
</html>
However, 'onYouTubePlayerReady()' doesn't fire at all, and if I manually get a reference to the player, a lot of methods are undefined; for example, cueVideoById() works, but playVideo() doesn't.
How can I fix this problem?

You need to be on a web server with your test script, as stated in the documentation:
Note: To test any of these calls, you must have your file running on a webserver, as the Flash player restricts calls between local files and the internet.

this function:
function onYouTubePlayerReady(playerid) {
console.log('readyIn');
};
don't have to be directly in head in separate script tag.
Only rule you have to keep is: don't put this function inside domready event - it has to be defined sooner.
For example in mootools I use it like this:
function onYouTubePlayerReady(playerid) {
echo('readyIn');
};
document.addEvent('domready', function() {
...
});

I have the answer, separate out this portion of the script and put it in the head in its own script tag. OMG, finally
<script type="text/javascript" language="javascript">
function onYouTubePlayerReady(playerid) {
ytp = document.getElementById('ytplayer');
ytp.mute();
};
</script>

I consider this the best way of adding a youtube video to your website with javascript. It gives you a very clear way of dealing with events. It works on a local machine, and as far as I know it works on apple devices. You can use all the events and function described in the javascript documentation for the youtube api.
<div id="player"></div>
<script>
//Load player api 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);
var done = false;
var player;
function onYouTubePlayerAPIReady() {
player = new YT.Player('player', {
height: '390',
width: '640',
videoId: 'JW5meKfy3fY',
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
}
function onPlayerReady(evt) {
evt.target.playVideo();
}
function onPlayerStateChange(evt) {
if (evt.data == YT.PlayerState.PLAYING && !done) {
setTimeout(stopVideo, 6000);
done = true;
}
}
function stopVideo() {
player.stopVideo();
}
</script>
source: http://apiblog.youtube.com/2011/01/introducing-javascript-player-api-for.html

<!DOCTYPE html>
had to lead the page in order for the html5 stuff to function for me in FF4

If you're embedding youtube videos like so:
<iframe src="http://www.youtube.com/embed/VIDEO_ID?jsapi=1" width="1280" height="720" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe>
then you should place
<script src="http://www.youtube.com/player_api"></script>
after the </iframe>. At least that's how I got it to work.
Additionally, if you're dynamically changing the [src] attribute of the iframe via jQuery or whatever to load a new video then you need to call onYouTubePlayerAPIReady() after it has loaded.
I prefer to change the [src] attribute and then:
setTimeout(onYouTubePlayerAPIReady, 500);

Just had the same issue, but for another reason. It worked in Chrome but not Firefox, and the reason was that I had a http header "Content-type: text/xml" instead of "Content-type: text/html". Serving as HTML now fires the onYouTubePlayerReady event in Firefox, too.
Just posting this in case someone stumbles on this answer from Google (like I just did when trying to find a solution).

Related

How to play/pause video depending on visibility with jQuery

I want one or more videos to play/pause depending on whether or not they're in the viewport.
I understand this can be achieved with jQuery (and plugins), so I've tried using the isInViewport plugin along with the following code, but I receive the error shown below.
HTML
<script src="scripts/jquery.js"></script>
<script src="scripts/isInViewport.js"></script>
[...]
<video id="video1" src="file.mp4" width="50%"></video>
[...]
<script src="scripts/script.js"></script>
JS
var $video = document.getElementsByTagName("video1");
if ($video.is(":in-viewport")) {
$video.play();
} else {
$video.pause();
};
Console
TypeError: $video.is is not a function
try
$('video').each(function() {
if ($(this).is(":in-viewport")) {
$(this)[0].play();
} else {
$(this)[0].pause();
}
}
);

An Iframe Inside Iframe. Can this be done?

We have a video (vimeo) link we would like our users to watch.
Each video is followed by a short questionnaire.
Our intent is to not make the questionnaire visible to the user until the user had clicked open the video for viewing.
I can only think of embedding the code below inside another iframe just to hide the link.
Is this possible?
Is there an alternative approach to this?
<!DOCTYPE HTML>
<html>
<head>
<meta name="google" value="notranslate" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Dog Smoking</title>
<style type="text/css">
body {
padding-top:0;
padding-bottom:0;
padding-left:0;
padding-right:0;
margin-top:0;
margin-bottom:0;
margin-left:0;
margin-right:0;
}
</style>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script src="javascript/froogaloop.js"></script>
<script src="javascript/froogaloop.min.js"></script>
<script type="text/javascript">
var iframe = $('#player1')[0],
player = $f(iframe),
status = $('.status');
// When the player is ready, add listeners for pause, finish, and playProgress
player.addEvent('ready', function() {
status.text('ready');
player.addEvent('pause', onPause);
player.addEvent('finish', onFinish);
player.addEvent('playProgress', onPlayProgress);
});
// Call the API when a button is pressed
$('button').bind('click', function() {
player.api($(this).text().toLowerCase());
});
function onPause(id) {
status.text('paused');
}
function onFinish(id) {
status.text('finished');
}
function onPlayProgress(data, id) {
status.text(data.seconds + 's played');
}
player.addEvent('ready', function() {
status.text('ready');
$("#survey_button").show(); // <-- or whatever
});
</script>
</head>
<body>
<iframe src="http://player.vimeo.com/video/4644119?api=1" width="400" height="375" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
<a href="http://show.aspx?testid=27#activate"
target="target-iframe"
onclick="frames['target-iframe'].document.getElementById('activate')
.scrollIntoView();return false">Click</a>
</body>
</html>
I would use the JS API for video and use the event callbacks built into the player to make the questionnaire visible.
==UPDATE==
Ok - so that link is a step by step example of how to incorporate the JS controls and callbacks for the player. But... here we go..
step 1 is to add the "?api=1" after your initial embed code.
step 2 is to load their Froogaloop library so you can listen for events...
step 3 would be to set up a callback to handle whatever event you want to listen to... The example right from this page is fantastic:
var iframe = $('#player1')[0],
player = $f(iframe),
status = $('.status');
// When the player is ready, add listeners for pause, finish, and playProgress
player.addEvent('ready', function() {
status.text('ready');
player.addEvent('pause', onPause);
player.addEvent('finish', onFinish);
player.addEvent('playProgress', onPlayProgress);
});
// Call the API when a button is pressed
$('button').bind('click', function() {
player.api($(this).text().toLowerCase());
});
function onPause(id) {
status.text('paused');
}
function onFinish(id) {
status.text('finished');
}
function onPlayProgress(data, id) {
status.text(data.seconds + 's played');
}
So, depending on when you want your survey to show, you can just tap into one of those...
player.addEvent('ready', function() {
status.text('ready');
$("#survey_button").show(); // <-- or whatever
});
make sense?
============= ANOTHER UPDATE ================
here's a working fiddle: http://jsfiddle.net/QkGRd/10/. You may want to read a bit about embedding resources and how the jsfiddle works as well.
TL;DR Answer
Yes you can have an iframe inside an iframe. Though it's generally not a good idea in terms of performance.

how to know the webpage is loaded

i have a iframe and i am redirecting pages in iframe.
how to get the event for each page loading finish.
main.html
<html>
<body>
<iframe src="http://www.child.html" id="childframe" style="height:100px"></iframe>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script>
$(window).load(function(){
var Body = $("#childframe").contents().find("body");
var Element = Body.find("tag");
// page is redirecting to new page
$(Element[0].click());
window.setTimeout(reallyNext, 1000);
function reallyNext() {
//how to know inner page is loaded
var result= Body.find("#tag1");
//how to get element from anotherpage.html
$(result).bind('DOMSubtreeModified', function(event) {
//how to reach here
});
}
});
</script>
</body>
</html>
child.html
<html>
<head></head>
<body>
<p><br></p>
</body>
</html>
please tell me how to know the inner page of iframe has done loading?
You can use the onload paremeter inside the body tag, which runs after the page is loaded.
For example:
<body onload="myJavascriptFunction();" >
$('#childframe').ready(function() {
...
});
or
$('#childframe').load(function() {
...
});
<script language="javascript">
iframe = document.getElementById("frameid");
WaitForIFrame();
function WaitForIFrame() {
if (iframe.readyState != "complete") {
setTimeout("WaitForIFrame();", 200);
} else {
done();
}
}
function done() {
//some code after iframe has been loaded
}
</script>
This should work
You can hook on the onLoad javascript event of the <iframe /> element (like <iframe onLoad="myHandler" />, where myHandler is your js function), or, if using jQuery, with the following snippet:
$('#childframe').load(function() {
// your code handling the iframe loaded.
});
Note, that your code needs to be part of the page that holds the iframe not the page within it.

JWPlayer handle youtube errors

I would like to handle the youtube errors in the JWPlayer, so in case the video doesn't exists or is not available for the country show a message on the player, or with javascript, i am doing something like this...
var options = {
height: 330,
},
flashplayer: '/player.swf',
width: 560,
events:{
onError:function(obj){
alert('ERROR'+obj);
}
} ,
debug: 'console'
};
jwplayer("player").setup(options);
jwplayer("player").play();
but its not getting inside from the onError event, even though the video doesnt even exist... and i can see in the console.. LOG (Error loading preview image: Error #2036)
In the case of youtubes restriction country i cannot even see that in the console.
In any case the video just show the loading animation, which it makes belieave the user that it can be load in any time, which its not true.
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets">
<script type="text/javascript" src="#{facesContext.externalContext.requestContextPath}/assets/jwplayer.min.js"></script>
<script type="text/javascript" src="#{facesContext.externalContext.requestContextPath}/assets/swfobject.js"></script>
<div id="player"></div>
</body>
<script type="text/javascript">
//<![CDATA[
window.onload=createPlayer();
function createPlayer() {
var flashvars = {
file:"http://www.youtube.com/watch?v=pnEHsUWFuNM",
autostart:"true"
}
var params = {
allowfullscreen:"true",
allowscriptaccess:"always"
}
var attributes = {
id:"player1",
name:"player1"
}
swfobject.embedSWF("#{facesContext.externalContext.requestContextPath}/assets/player.swf", "player", "320", "196", "9.0.115", false, flashvars, params, attributes);
}
function loadPlayer() {
var options = {
height: 325,
flashplayer: '#{facesContext.externalContext.requestContextPath}/assets/player.swf',
width: 560,
events:{
onError:function(error){
alert('Error loading your link, please try another one');
}
} /* ,
debug: 'console'*/
};
options.file = 'http://www.youtube.com/watch?v=pnEHsUWFuNM';
options.events.onReady= function(){
jwplayer("player").play();
};
jwplayer("player").setup(options);
}
//]]>
</script>
loadPlayer to try with jwplayer.js and the createPlayer directly from SWFObject... that video exist just that it shouldnt be shown in germany, still its trying to load it.
and if i set any other unexisting URL let say "http://www.youtube.com/watch?v=ABC" still keeps trying to load the unexisting video.
It looks like JW5 doesn't support catching YouTube errors. However, the following setup with JW6 works:
<!DOCTYPE html>
<html>
<head>
<title>YouTube Test Page</title>
<script type="text/javascript" src="http://www.longtailvideo.com/jwplayer/jwplayer.js"></script>
</head>
<body>
<div id="player"></div>
<script type="text/javascript">
jwplayer("player").setup({
file: "https://www.youtube.com/watch?v=ABCD",
events:{
onError: function() {
jwplayer().load({file: "http://content.longtailvideo.com/videos/flvplayer.flv",duration: "27"});jwplayer().play()
}
}
});
</script>
</body>
</html>

Using Youtube's javascript API with jQuery

I'm currently trying to use the YouTube API as part of a jQuery plugin and I've run into a bit of a problem.
The way the YT api works is that you load the flash player and, when it's ready it will send a call back to a global function called onYouTubePlayerReady(playerId). You can then use that id combined with getElementById(playerId) to send javascript calls into the flash player (ie, player.playVideo();).
You can attach an event listener to the player with player.addEventListener('onStateChange', 'playerState'); which will send any state changes to another global function (in this case playerState).
The problem is I'm not sure how to associate a state change with a specific player. My jQuery plugin can happily attach more than one video to a selector and attach events to each one, but the moment a state actually changes I lose track of which player it happened in.
I'm hoping some example code may make things a little clearer. The below code should work fine in any html file.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="application/text+html;utf-8"/>
<title>Sandbox</title>
<link type="text/css" href="http://jqueryui.com/latest/themes/base/ui.all.css" rel="stylesheet" />
<script type="text/javascript" src="http://www.google.com/jsapi"></script>
<script type="text/javascript">
google.load("jquery", "1.3.2");
google.load("jqueryui", "1.7.0");
</script>
<script type="text/javascript" src="http://swfobject.googlecode.com/svn/tags/rc3/swfobject/src/swfobject.js"></script>
<script type="text/javascript">
(function($) {
$.fn.simplified = function() {
return this.each(function(i) {
var params = { allowScriptAccess: "always" };
var atts = { id: "ytplayer"+i };
$div = $('<div />').attr('id', "containerplayer"+i);
swfobject.embedSWF("http://www.youtube.com/v/QTQfGd3G6dg&enablejsapi=1&playerapiid=ytplayer"+i,
"containerplayer"+i, "425", "356", "8", null, null, params, atts);
$(this).append($div);
});
}
})(jQuery);
function onYouTubePlayerReady(playerId) {
var player = $('#'+playerId)[0];
player.addEventListener('onStateChange', 'playerState');
}
function playerState(state) {
console.log(state);
}
$(document).ready(function() {
$('.secondary').simplified();
});
</script>
</head>
<body>
<div id="container">
<div class="secondary">
</div>
<div class="secondary">
</div>
<div class="secondary">
</div>
<div class="secondary">
</div>
</div>
</body>
</html>
You'll see the console.log() outputtin information on the state changes, but, like I said, I don't know how to tell which player it's associated with.
Anyone have any thoughts on a way around this?
EDIT:
Sorry, I should also mentioned that I have tried wrapping the event call in a closure.
function onYouTubePlayerReady(playerId) {
var player = $('#'+playerId)[0];
player.addEventListener('onStateChange', function(state) {
return playerState(state, playerId, player); } );
}
function playerState(state, playerId, player) {
console.log(state);
console.log(playerId);
}
In this situation playerState never gets called. Which is extra frustrating.
Edit:
Apparently calling addEventListener on the player object causes the script to be used as a string in an XML property that's passed to the flash object - this rules out closures and the like, so it's time for an old-school ugly hack:
function onYouTubePlayerReady(playerId) {
var player = $('#'+playerId)[0];
player.addEventListener('onStateChange', '(function(state) { return playerState(state, "' + playerId + '"); })' );
}
function playerState(state, playerId) {
console.log(state);
console.log(playerId);
}
Tested & working!
Im Using Jquery SWFobject plugin, SWFobject
It is important to add &enablejsapi=1 at the end of video
HTML:
<div id="embedSWF"></div>
Jquery:
$('#embedSWF').flash({
swf: 'http://www.youtube.com/watch/v/siBoLc9vxac',
params: { allowScriptAccess: "always"},
flashvars: {enablejsapi: '1', autoplay: '0', allowScriptAccess: "always", id: 'ytPlayer' },
height: 450, width: 385 });
function onYouTubePlayerReady(playerId) {
$('#embedSWF').flash(function(){this.addEventListener("onStateChange", "onPlayerStateChange")});
}
function onPlayerStateChange(newState) {
alert(newState);
}
onYouTubePlayerReady must be outside of $(document).ready(function() to get fired
I had this same problem and tried the accepted answer. This didn't work for me; the playerState() function was never called. However, it put me on the right path. What I ended up doing was this:
// Within my mediaController "class"
window["dynamicYouTubeEventHandler" + playerID] = function(state) { onYouTubePlayerStateChange(state, playerID); }
embedElement.addEventListener("onStateChange", "dynamicYouTubeEventHandler" + playerID);
// End mediaController class
// Global YouTube event handler
function onYouTubePlayerStateChange(state, playerID) {
var mediaController = GetMediaControllerFromYouTubeEmbedID(playerID);
mediaController.OnYouTubePlayerStateChange(state);
}
It's fairly nasty, but so is the current state of the YouTube JavaScript API.
Here is some other helpful/nasty code if you are using any kind of advanced prototyping patterns. This basically allows you to retrieve a "class" instance from the YouTube player ID:
// Within my mediaController "class"
// The containerJQElement is the jQuery wrapped parent element of the player ID
// Its ID is the same as the player ID minus "YouTubeEmbed".
var _self = this;
containerJQElement.data('mediaController', _self);
// End mediaController class
// Global YouTube specific functions
function GetMediaControllerFromYouTubeEmbedID(embedID) {
var containerID = embedID.replace('YouTubeEmbed', '');
var containerJQObject = $("#" + containerID);
return containerJQObject.data('mediaController');
}
function onYouTubePlayerReady(playerId) {
var mediaController = GetMediaControllerFromYouTubeEmbedID(playerId);
mediaController.OnYouTubeAPIReady();
}
Here's a nice article that goes through creating a class to wrap an individual player, including dispatching events to individual objects using a similar approach to that mentioned in a previous answer.
http://blog.jcoglan.com/2008/05/22/dispatching-youtube-api-events-to-individual-javascript-objects/
How about something like so:
var closureFaker = function (func, scope) {
var functionName = 'closureFake_' + (((1+Math.random())*0x10000000)|0).toString(16);
window[functionName] = function () {
func.apply(scope || window, arguments);
};
console.log('created function:', functionName, window[functionName]);
return functionName;
};
ytplayer.addEventListener("onStateChange", closureFaker(function () {
//place your logic here
console.log('state change', arguments)
}));

Categories