Get video play of youtube player - javascript

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

Related

YouTube IFrame API - setPlaybackQuality() is not changing video resolution from current playback time

I have been trying to change the video playback quality/resolution of an iframe embedded video from YouTube using YouTube IFrame API by simply calling player.setPlaybackQuality("hd720") in the middle of playback.
According to YouTube: https://developers.google.com/youtube/iframe_api_reference#setPlaybackQuality
"The function causes the video to reload at its current position in the new quality."
BUT, the quality of the video is changing only when the current playback time reaches the end point of the buffered old quality stream. So, how can I force the player to buffer the video at the new resolution at that very moment and start showing it from exactly that 'current duration' of the video just as it happens inside YouTube?
By the way, I'm using pre-defined iframe tag in the html with all the parameters in the embed URL, like so:
<iframe id="genesis" src="https://www.youtube.com/embed/EZgTo1kKSsg?enablejsapi=1&controls=0&showinfo=0&iv_load_policy=3&modestbranding=1&rel=0&fs=1" frameborder="0"></iframe>
And creating the player, like so:
$.getScript("https://www.youtube.com/player_api");
function onYouTubeIframeAPIReady() {
player = new YT.Player('genesis', {
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange,
'onPlaybackQualityChange': onQualityChange
}
});
}
function onQualityChange(){
console.log('Now playing at ' + player.getPlaybackQuality());
// Though it returns "hd720" within a few moments after hitting
// setPlaybackQuality("hd720"), actual playback quality remains the older one.
}
$(document).on('click', '.play', function(){
player.playVideo();
});
$(document).on('click', '#res_change_while_playing', function(){
player.setPlaybackQuality($(this).data("id")); // data-id="hd720"
});
Please help!
Thanks.
You can use seek function to re-buffer the video after you call setPlaybackQuality function
function onQualityChange(){
player.setPlaybackQuality("small")
player.seekTo(60) // or set to CurrentTime using player.getCurrentTime()
}
if this code doesnt work, you must stop the video first, then set the video quality, then seek to your time

Youtube Player API iframe Embed | player.clearVideo() not working

I checked the Youtube API v3 iframe embed docs and am trying to apply player.clearVideo() function to my button as follows (ellipsis replaces code) :
...
function onPlayerReady(event) {
var zapButton = document.getElementById('zapvideo');
zapButton.addEventListener("click", function() {
player.clearVideo(); // NOT WORKING
});
}
...
$(function(){
$('#zapvideo').on('click', function(){ ... });
});
Nothing happens (no errors). player.stopVideo() and other controls work. How can I clear the video from the Youtube player? I'm using Youtube's HTML5 player, but even when Youtube switches to Flash player for some videos, I still cannot clear the video that's in the player (what's worst is that Youtube doesn't revert to the HTML5 player when an HTML5 compatible video is subsequently selected and played in my app regardless if I have opt-in HTML5 or added the relevant html5 playerVars, which means I cannot tab out of Flash-based player controls when they're in focus. So much for "key-bored" navigation!). I'm using Firefox 36.0.1 .
Any suitable workaround function to clear video while keeping the player available will be fine with me.
Found a workaround with the following code:
...
function onPlayerReady(event) {
...
$('#zapvideo').on('click', function(){
$('#player').hide();
event.target.loadVideoById('',0);
event.target.seekTo(0); // iOS
event.target.stopVideo();
return false;
});
}
#zapvideo button hides the iframe player since we don't want to see any error message in player after an empty or dummy video id is submitted via event.target.loadVideoById(). Remember to show player before playing a new video. The relevant code is encapsulated within the onPlayerReady() function to make sure the player is always ready prior to code execution.

Change time in embedded youtube video when a button is clicked

I want to embed a youtube video and provide buttons which, when you click them goes to a specific time in the video and resumes playing from there.
I've tried using jquery and changing the "src" attribute, like so:
Original source:
<iframe src="http://www.youtube.com/embed/PjDw3azfZWI?&t=5m30s&rel=0&amp">
JS:
$("#link1").click(function() {
$("#video").attr("src", "http://www.youtube.com/embed/PjDw3azfZWI?&t=10m30s&rel=0&amp");
});
This caused the browser to refresh when I clicked the button.
Link to image of what I'm thinking: http://i.imgur.com/sCFZSIn.png. Clicking the buttons should make the video jump to the time specified.
You shouldn't reload the iframe to control the video; use the Javascript API methods. Check out seekTo here: https://developers.google.com/youtube/iframe_api_reference#Playback_controls
Basically, once your iframe loads, the JS API will call onYouTubeIframeAPIReady(), where you construct a YouTube player object. Then you can use that player reference to control the video, such as player.seekTo().
You can still use your iframe, as described at the botton of this section:
As mentioned in the Getting started section, instead of writing an
empty element on your page, which the player API's JavaScript
code will then replace with an element, you could create the
tag yourself.
...
If you do write the tag, then when you construct the YT.Player object, you do not need to specify values for the width and height, which are specified as attributes of the tag, or the videoId and player parameters, which are are specified in the src URL.
The piece your code is missing is the YT.Player object, which you must construct in the callback method mentioned above. This provides access to player controls.
Here's a Fiddle demonstrating:
var player, seconds = 0;
function onYouTubeIframeAPIReady() {
console.log("player");
player = new YT.Player('player', {
events: {
'onReady': onPlayerReady
}
});
}
function onPlayerReady(event) {
event.target.playVideo();
}
function seek(sec){
if(player){
seconds += sec;
player.seekTo(seconds, true);
}
}
You can put this code in a separate script, but make sure it is in the root scope (like in your head tag) instead of putting it in an onLoad handler.

YouTube iFrame API behavior is inconsistent/nondeterministic

I was having trouble isolating a bug in my JavaScript code for controlling Youtube videos via the iframe/HTML5 API.
I went back to the demo code on the main documentation page:
https://developers.google.com/youtube/iframe_api_reference
...and to my surprise, I see the same inconsistent behavior even when I use the demo code from there and don't change anything.
The behavior is that some of the time, when I load this page, the player autoplays (which is the intent of the code), and other times it doesn't. It always does succeed in loading. Also, the player never seems to stop after 6 seconds, in contrary to what the comments say.
Breakpoints verify that part of the issue at least is that onPlayerReady() is not always being called. When I set a breakpoint in onPlayerReady(), it usually is not reached, and is only reached the times that the player goes on to succeed in autoplaying.
Of course, this behavior may be dependent on the speed and reliability of my internet connection, which is wired and otherwise seems decently fast. I just tested it -- 24 Mbps, and it seems pretty consistent.
If I make superficial changes to the html, that seems to sometimes prompt the page on loading to autoplay, but not always. Sometimes I will reload every few seconds 5 times in a row with no autoplay or onPlayerReady breakpoint being hit, then do it a 6th time and that time it will autoplay fine.
I'm using Chrome v30.0.1599.101 on Mac OS 10.8.4.
I know that code is in beta and in flux, and isn't supposed to be production level yet, but I was hoping there was something i can try.
Here is the code I'm using, FYI, in case the code posted on the api reference page above changes. Again, I'm not altering a single character.
<!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) {
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>
</body>
</html>
I was opening the page locally, which makes for different behavior in all sorts of little ways from how it works when delivered from a server. The browser client itself handles things like cacheing differently when content is local. When I put the same page on a server, it started to work every time.
In addition, FYI, for my bigger issue that led me down this rabbithole, I found that I needed to follow this advice: https://stackoverflow.com/a/14952334/2308190 ...in order to get my YouTube callback functions to be called with jQuery loaded.
I had a situation where my first YouTube iframe would load correctly, and subsequent ones would not.
The issue was caused by creating a new YT.Player before its <div> had been added to the DOM. This issue didn't occur the first time I created a YT.Player, because the YouTube API had to be loaded first. This caused a microsecond delay which allowed the rest of my code to execute, so the <div> was added to the DOM before the YouTube API finished loading.

Auto-play youtube and soundcloud embeds after one another

I have a music blog that contains a series of youtube and soundcloud embeds.
I would like to automatically play all of the embedded content on the page one after another. In other words after a youtube embed that I've played ends, I would like the next embed to start playing whether it be from soundcloud or youtube and vice versa.
The rendered HTML looks like this:
<span class="soundcloud_embed" id="soundcloud_post_308">
<iframe id="ui-id-1" width="100%" height="166" scrolling="no" frameborder="no" src="https://w.soundcloud.com/player/?url=http%3A%2F%2Fapi.soundcloud.com%2Ftracks%2F103518792&show_artwork=true&secret_token=s-LnOTK"></iframe>
</span>
<span class="youtube_embed" id="youtube_post_309">
<iframe id="ui-id-2" width="528" height="190" src="//www.youtube.com/embed/Y3CYKXBEtf0" frameborder="0" allowfullscreen></iframe>
</span>
<span class="youtube_embed" id="youtube_post_310">
<iframe id="ui-id-3" width="528" height="190" src="//www.youtube.com/embed/yMx1FnkrhYc" frameborder="0" allowfullscreen></iframe>
</span>
Building off help I received from this source: Pause Youtube embed when playing Soundcloud embed
To keep track of which players are on the page, which api's they belong to, and which of them is currently playing:
var playerCurrentlyPlaying = {"api":null,"frameID":null};
var players = {"yt":{},"sc":{}};
I need to define a generic playNext function that is called in the event that playerCurrentlyPlaying comes to an end. Depending on the api of the next embed, the playNext function has to execute the proper play command. In order to find which embed is next, the function can perhaps increment the ID of the currentlyPlaying iframe by 1. Such that if id="ui-id-2" has just ended then id="ui-id-3" should play.
Sometimes these youtube videos crash and say things like "video no longer exists" or "uploader has made this unavailable in your country". In these cases, how can I check for a crash and skip to the next incremented ID (e.g. id="ui-id-4") ?
This video no longer exists:
<span class="youtube_embed" id="youtube_post_311">
<iframe id="ui-id-4" width="528" height="190" src="//www.youtube.com/embed/Ym3DgqNTzyc" frameborder="0" allowfullscreen></iframe>
</span>
You've got two questions in one, here. I'll try to address them both.
In terms of making the next player auto-play, there are two small steps you'll need to take. The first is to bind your player objects to their API's respective event signaling that the media is done playing. For YouTube, your event listener would look something like this:
onYTPlayerStateChange = function (event) {
if (event.data == YT.PlayerState.PLAYING) {
onYTPlay(event.target.a.id);
}
else if (event.data == YT.PlayerState.ENDED) {
playNextPlayer();
}
};
Where playNextPlayer() is this generic function you mention you need to define. For your Soundcloud embeds, your event bindings would look something like this, now:
(function () {
$(".soundcloud_embed iframe").each(function () {
var frameid = $(this).attr('id');
players["sc"][frameid] = {};
players["sc"][frameid] = {
"widget": SC.Widget(document.getElementById(frameid)),
"firstplay": true
};
players["sc"][frameid]["widget"].bind(SC.Widget.Events.READY, function () {
players["sc"][frameid]["widget"].bind(SC.Widget.Events.PLAY, function () {
onSCPlay(frameid, SC.Widget.Events.PLAY);
});
players["sc"][frameid]["widget"].bind(SC.Widget.Events.PLAY_PROGRESS, function () {
onSCPlay(frameid, SC.Widget.Events.PLAY_PROGRESS);
});
players["sc"][frameid]["widget"].bind(SC.Widget.Events.FINISH, function () {
playNextPlayer();
});
});
});
}());
Once you've got those bindings in place, the playNextPlayer function will need to determine what the next player is, what API it comes from, and then execute that API's play call. Something like this:
playNextPlayer = function() {
var nextIdNum=parseInt(playerCurrentlyPlaying["frameID"].split("-").pop())+1;
nextFrameId="ui-id-"+nextIdNum;
switch($("#"+nextFrameId).parent().attr('class')) {
case "youtube_embed":
api="yt";
players[api][nextFrameId].playVideo();
break;
case "soundcloud_embed":
api="sc";
players[api][nextFrameId]["widget"].play();
break;
}
playerCurrentlyPlaying["api"]=api;
playerCurrentlyPlaying["frameID"]=nextFrameId;
};
Keep in mind that there's no error handling built in to this sample code; you'll have to write some to handle cases where the IDs aren't sequential, for example, or what to do when its out of iframes to play.
As to your second question -- to determine whether or not a video is playable, you'll have to set up some error event listeners as well as the playback event listeners.
function onYouTubeIframeAPIReady() {
$(".youtube_embed iframe").each(function () {
players["yt"][$(this).attr('id')] = new YT.Player($(this).attr('id'), {
events: {
'onError': seeError,
'onStateChange': onYTPlayerStateChange
}
});
});
}
The seeError function can then be defined in such a way that it determines what player threw the error (using the event.target.a.id parameter in way similar to how it's being done with the state change event listeners), and then leverages the same generic playNextPlayer function. Keep in mind that if a Youtube video doesn't exist in that way, it will NOT generate a "PLAYING" event, so you'll have to set the proper playerCurrentlyPlaying values in your error listener as well, just to make sure the system then properly advances.
The YouTube player is supposed to throw different types of errors based on whether the video doesn't exist, whether it isn't playable in a particular country, etc. See here: https://developers.google.com/youtube/js_api_reference#Events under the "onError" section to see what these different codes are supposed to be. I say 'supposed to' because it looks like, right now, it's just throwing code 0 for all "can't play" errors.
Here's a working fiddle which does all of the above (you can switch the ids of the soundcloud and youtube iframes to verify that the advancement works both directions). This fiddle also instantiates an onError listener but doesn't define what it will do. Shouldn't be hard for you to get that to work, though.
http://jsfiddle.net/jlmcdonald/NqRqm/8/

Categories