I am having issues getting the youtube api working. The API itself loads and the onYouTubeIframeAPIReady() function gets called, but the onReady doesn't work.
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() {
log('API')
log(document.getElementById('yt-pilezspnvu'));
var player = new YT.Player('yt-pilezspnvu', {
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
}
function onPlayerReady(event) {
log(event);
}
function onPlayerStateChange(event) {
log(event);
}
The code above isn't wrapped in any functions or anything. The errors in the picture below are just my adblock stuff. I've tried adding origin=http://example.com as pointed out in this thread https://stackoverflow.com/a/20505337/736967 but still not working.
I think that you need some extra bits that are missing.
Try adding in this to your code.
ytplayer = new YT.Player('ytplayer', {
height: '385',
width: '640',
videoId: '[your-videoID]',
playerVars: {'wmode': 'opaque', 'autohide': 1 , 'enablejsapi': 1 , 'origin': 'http://www.yousite.com', 'rel': 0},
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange,
}
playerVars has many parts and you can use or not. But you definatly need to have something load into the player. VideoID or PlayList. Else nothing will happen.
I had a similar issue with an overlay image being clicked and the onReady event never seemed to fire even though all the other events did; obvious through console logs in each.
The issue was apparently a race event. Clicking the overlay image should remove the image and start the YouTube video playing. I also have several videos on the same page. The click event to play the video should be placed inside the onReady event instead of the click event firing the play event. I have trimmed this down as much as I could as our DOM has several elements inside the video container, including the overlay image, captions, etc.
Here is my solution:
var player = new Array;
window.onYouTubeIframeAPIReady = function() {
// Loop through the existing video iframes designated with the inital string 'vidframe_' in the id
jQuery('iframe[id^="vidframe_"]').each(function (i, val) {
var $this = $(this); // iframe container
var $vidWrapper = $this.closest('.video-wrapper');
// Make sure it is a YouTube video. This data attribute is set when the iframe is created by my code
if( $vidWrapper.data("video-source") == "youtube" )
{
// Initialize each YouTube video present
player[i] = new YT.Player($this.attr('id'), {
events: {
onReady: function(event) {
// Set the click event listener here
$vidWrapper.on("click", function() {
// Target the overlay image
// 'this' is now the .video-wrapper image element
var imgOver = $(this).find('figure');
// Remove image overlay
if( imgOver )
imgOver.fadeOut();
// Target the right player
player[i].playVideo();
});
}
}
});
}
});
};
I hope this helps anyone else who may be searching for an errorless onReady event not seemingly working. This css-tricks article is what really gave me the best clue.
Related
I am new to coding and I am trying to learn how to use the youtube IFRAME to control embded videos. The following code is mostly from youtube's api documentation. The only thing I added were the buttons and event listeners that are attached to them.
Can someone explain to me why "play" button that I have created can't start the video?
// 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: '250',
width: '300',
videoId: 'M7lc1UVf-VE',
events: {
'onReady': onPlayerReady,
}
});
}
// 4. The API will call this function when the video player is ready.
function onPlayerReady(event) {
event.target.playVideo();
}
document.getElementById('pause').onclick = function() {
player.pauseVideo();
};
document.getElementById('play').onclick = function() {
player.playVideo();
};
<html>
<body>
<div><button id= "pause">Pause</button></div>
<div><button id= "play">Play</button></div>
<!-- 1. The <iframe> (and video player) will replace this <div> tag. -->
<div id="player"></div>
</body>
It seems that the documentation of the iFrame API is either outdated or completely wrong.
The function which should initialize the player onYouTubeIframeAPIReady() will never fire thus a click on the play/pause buttons won't work because the variable player is undefined.
To workaround this, you have to wait until the script you're loading into the freshly created <script> element has finished loading and inside the callback function you need to initialize the YT component by a call to it's own ready() function. This isn't mentioned anywhere.
Well, get rid of the complete onYouTubeIframeAPIReady function and replace it with this:
tag.onload = function() {
YT.ready(function() {
player = new YT.Player('player', {
height: '250',
width: '300',
videoId: 'M7lc1UVf-VE',
events: {
'onReady': onPlayerReady,
}
});
});
};
Currently I´m working on the possibility to zoom into a embedded youtube video. Therefore I have a player set up in a iframe (I am using the popcorn.js HTMLYoutubeElement for this)
player = new YT.Player( elem, {
width: "100%",
height: "100%",
wmode: playerVars.wmode,
videoId: aSrc,
playerVars: playerVars,
events: {
'onReady': onPlayerReady,
'onError': onPlayerError,
'onStateChange': onPlayerStateChange
}
});
From this iframe I would like to get access to the <video> element for my purposes.
Using the youtube iframe API I get the appropriate iframe with player.getIframe(). But as soon as I try to get the "inner" document with e.g
var innerDoc = iframe.contentDocument || iframe.contentWindow.document;
I receive the following error message:
Uncaught SecurityError: Blocked a frame with origin http://localhost:3000 from accessing a cross-origin frame.
This kind of error is discussed here but without helping alot with my specific problem.
And looking into the youtube iframe API I couldn´t find any possibility to directly access the <video> element. Therefore my question: is it actually possible at all?
You can't zoom a video even so the video quality will be degraded .
if you want the video in fullscreen mode then maybe this is what you searched for :
var player, iframe;
var $ = document.querySelector.bind(document);
// init player
function onYouTubeIframeAPIReady() {
player = new YT.Player('player', {
height: '100%',
width: '100%',
videoId: 'xxxxxxxxxxx',
events: {
'onReady': onPlayerReady
}
});
}
// when ready, wait for clicks
function onPlayerReady(event) {
var player = event.target;
iframe = $('#player');
setupListener();
}
function setupListener (){
$('button').addEventListener('click', playFullscreen);
}
// when ready, wait for clicks
function onPlayerReady(event) {
var player = event.target;
iframe = $('#player');
setupListener();
}
function setupListener (){
$('button').addEventListener('click', playFullscreen);
}
function playFullscreen (){
//won't work on mobile
player.playVideo();
var requestFullScreen = iframe.requestFullScreen ||
iframe.mozRequestFullScreen ||
iframe.webkitRequestFullScreen;
if (requestFullScreen) {
requestFullScreen.bind(iframe)();
}
}
I have a list of videos in an array and I want to be able to make the player play another video from the list after the current one ends. The problem I'm having is that it repeats the same video once its ends instead of selecting a new video to play. I've been looking for similar questions and havent been able to find anything to make it work. Any advice would be appreciated!
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.
function rotateYT() {
var videos = [
'be0T_owA1PU',
'Kp7eSUU9oy8',
'Th0V-fxo9CE',
];
var index=Math.floor(Math.random() * videos.length);
return videos[index];
}
var player;
function onYouTubeIframeAPIReady() {
var videoID = rotateYT();
player = new YT.Player('player', {
height: '300',
width: '300',
videoId: videoID,
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
}
// 4. The API will call this function when the video player is ready.
function onPlayerReady(event) {
player.setPlaybackRate(1);
event.target.playVideo();
}
// 5. This should play another random video
function onPlayerStateChange(event) {
if(event.data === 0) {
event.target.setShuffle(true);
event.target.playVideo();
}
}
I probably put the code in wrong so here is the jsfiddle ive been working on
https://jsfiddle.net/bbasham/L20k7x1o/2/
Your issue is that you are not telling the YT player to use a playlist of videos. Instead, you are only setting one video ID at a time, therefore, the shuffle method would not work. You need to update your method so that you swap the video ID before restarting:
// 5. This should play another random video
function onPlayerStateChange(event) {
if(event.data === 0) {
//event.target.setShuffle(true); //useless unless the player has a playlist
event.target.loadVideoById( rotateYT() );
event.target.playVideo();
}
}
That will cause the player to grab a new video and set it as the source before restarting the player. Alternatively you could provide a playlist and then use shuffle.
Documentation
I would like to pause the video when the user click on another tab in their browser. I have tried to do this with Youtube and Vimeo.
This is the basic idea behind the javascript:
For Youtube:
//YouTube
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 youtubePlayer;
var onYouTubeIframeAPIReady = function() {
youtubePlayer = new YT.Player('youtube', {
height: '390',
width: '640',
videoId: 'sXtekwuT8R0',
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
};
var onPlayerReady = function(event) {
event.target.playVideo();
};
var onPlayerStateChange = function(event) {
if (event.data == YT.PlayerState.PLAYING) {
parent.focus();
window.onblur = function() {
status.text("You went away!");
youtubePlayer.stopVideo();
};
}
};
For Vimeo (using their Froogaloop library):
$(function() {
//Vimeo
var iframe = $('#vimeo');
var vimeoPlayer = $f(iframe[0]);
var status = $('#status');
vimeoPlayer.addEvent('ready', function() {
vimeoPlayer.addEvent('play', function(){
status.text("Playing!");
parent.focus();
window.onblur = function() {
status.text("You went away!");
vimeoPlayer.api("pause");
};
});
});
});
Here are some codepen examples of these attempts:
Youtube:
http://codepen.io/earlonrails/pen/jugAm
Vimeo:
http://codepen.io/earlonrails/pen/KBAmd
Both examples will work if after I click the play button, I click on the parent document of the iframe then click a different window or tab. The Youtube example will also work when it is first loaded, but not if you click the play then pause then play. I believe both of these problems are due to the fact that you are clicking the iframe, therefore the event either is trigger at the same time or cannot be triggered because the event can't be captured there. I thought using the postMessages sent through the iframes along with callbacks would make this work, but alas I have not been able to figure this out.
Need to set the current window before adding the event callback and use this window variable in the callback function. IE
var myWindow = window;
vimeoPlayer.addEvent('play', function(){
status.text("Playing!");
myWindow.focus();
myWindow.onblur = function() {
status.text("You went away!");
vimeoPlayer.api("pause");
};
});
These can be confirmed and tested at the previously linked codepen examples:
Youtube: http://codepen.io/earlonrails/pen/jugAm
Vimeo: http://codepen.io/earlonrails/pen/KBAmd
I guess the window when clicked in the iframe would be setting onblur on the iframe window, which would then never get called, but I still can't explain why when you click play on the iframe, then click the body of the page, then click a different tab then it works. Perhaps the callback is being fired more than once from the iframe or the postMessage is being fired or still in some buffer.
I'm using jQuery to try to show a hidden YouTube player, and then start playing the video once its containing div is shown.
The problem is that this only works on Chrome, not in IE or FireFox. In IE, I see the error: JSON is undefined.
What can I do to make this work right in all three browsers?
Here's the code I have so far:
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 player;
function onYouTubePlayerAPIReady() {
player = new YT.Player('player', {
height: '390',
width: '640',
videoId: 'r3lPq7qY3TU',
events: {
'onReady': onPlayerReady
}
});
$('div#target_wrap img, div#main_vid').click(function(event){
event.preventDefault();
var p = $('#player');
p.slideToggle(function(){
if (p.is(":visible")) {
player.playVideo();
} else {
player.stopVideo();
}
});
});
}
My guess is that it's lucky accident that it works on Chrome in the first place. For example a common problem is not waiting for the call to "onYouTubePlayerReady". At least for debugging purposes you'll also want to do something like:
$('div#target_wrap img, div#main_vid').click(function(event){
event.preventDefault();
$('#player').slideToggle(function(){
if (player.getPlayerState) {
alert("player state: " + player.getPlayerState());
if ($('#player').is(":visible")) {
player.playVideo();
} else {
player.stopVideo();
}
} else {
alert("Player not ready yet.");
}
});
});
If you can share more of your code we might have a better answer.
Don't really know anything about playing YouTube videos via JS, but some versions of IE doesn't include an implementation of the JSON object which serializes/deserializes to/from JSON. You can find an implementation here.
You may wish to include this via conditional comments or use a script loader so it's loaded only when needed.
if you can't achieve crossbrowser compatibility i give you a suggestion:
onClick call the same video again but with the parameter &autoplay=1