Youtube API - onclick play video - cross browser - javascript

I am using this script to fadeIn and autoplay YouTube video upon clicking on button and automatically fade it out when the video finishes playing (plus it's also supposed to scroll from the top by 90px). The script works perfectly in Safari and Chrome, however in Firefox 3.6 it fadesIn the video but doesn't automatically play it - the user has to click the play button on the player, and the scrollTop isn't working for some reason. And in Internet Explorer 8 is the same problem as in Firefox, but the video won't even fadeOut when finishes playing.
Any idea what could be the problem please and how could I fix it? Thanks a lot, any help is very much appreciated.
<script src="http://www.youtube.com/player_api"></script>
<script>
// create youtube player
var player;
function onYouTubePlayerAPIReady() {
player = new YT.Player('vid', {
height: '539',
width: '958',
videoId: 'wgDQoA7cqsQ',
events: {
'onStateChange': onPlayerStateChange
}
});
}
// when video ends
function onPlayerStateChange(event) {
if(event.data === 0) {
$("#vid").fadeOut(500);
}
}
function startVideo() {
$("#vid").fadeIn(2000);
player.playVideo();
$("html, body").animate({ scrollTop: 90 }, 600); return false;
};
</script>

I think in some browsers the video player is not ready to reproduce the video, but you can attach an event to know when the api is ready to play the video (onReady event), this is done by adding the event in the constructor.
Then when the builder told you that you are ready, there you can reproduce your video.
About the scroll problem, is likely the video player has not being initialized yet, so there is no playVideo function and that's why the animation does not scroll up, because your code breaks.
I have also noticed is some browsers that the container with a display:none property doesn't behave very well, in order to solve this I have hidden the container using width and height = 1px, and then when I want to see the video I change dinamically the size.
Here is an example:
var player = new YT.Player( containerId, {
height: 'auto',
width: 'auto',
suggestedQuality:"hd720",
"videoId":"ejWGThDRllE",
playerVars: { 'autoplay': 0, 'controls': 1,'autohide':1,rel:0,hd:1 },
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
container = document.getElementById(containerId);
container.style.width = "1px";
container.style.height = "1px";
onPlayerReady(event){
player.playVideo();
var playerr = document.getElementById(self.containerId);
playerr.style.display = "block";
playerr.style.width = "100%";
playerr.style.height = "100%";
}
hope it helps.

Try wrapping your script with this, if not already done :
$( document ).ready(function() {
//Script
});
It saved me from some strange behaviours!

Related

Youtube player.destroy(); throws 'this.a is null', even when validating player

So I've got a small app with two panels. Using the iframe API. Clicking on one panel will expand the panel full screen, as well as showing a 'play video' button with some additional information. Clicking a button in the top left will return the UI to it's standard state, closing down the video and shrinking the panels back to fit 50/50.
Now as we've got two videos, I've defined the videos as such, #vidPlayer2 being the second trigger.
$('#vidPlayer1').on('click', function(){
player = new YT.Player('player', {
height: '100%',
width: '100%',
videoId: '(video id here)',
controls: 0,
showinfo: 0,
autoplay: 0,
rel: 0,
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
Similarly, we've got the default demo code, with a small modification:
function onPlayerReady(event) {
event.target.playVideo();
}
var done = false;
function onPlayerStateChange(event) {
if (event.data == YT.PlayerState.PLAYING && !done) {
done = true;
}
if (event.data == YT.PlayerState.ENDED) {
resetView();
}
}
function stopVideo() {
player.stopVideo();
}
Then, we're trying to get the button to work. In some circumstances, not having clicked one of the vidPlayer buttons, no player is defined, so I threw in an if statement with some validation.
var resetView = function() {
// If a Youtube player is active, make sure we stop it.
if (player === undefined || !player || null) {
console.log("Player could not be found.");
} else {
player.stopVideo();
player.destroy();
}
// Additional code to reset the UI removed below. Works no matter what if the above code is removed.
};
Now for the most part, things work well UNTIL I try to go into a panel, play a video, reset UI, then try to enter and leave the next panel without playing a video. When I follow this exact series of steps, regardless of what panel starts first, I get a TypeError: this.a is null in console. I would've assumed that the validation would've done the trick, but apparently not.
So what I can distinguish from this is it works fine when initialized - i.e. var player is initialized. The return button works through just going back and forth without playing a video. The return button works when a video is actively playing, but the function fails if we try to use the return directly after the player is stopped and destroyed. It does work if we simply pop open another video, however.
Is there something I'm missing when I'm trying to reset the view? Does the youtube player have to be reinitialized? Any help or thoughts would be greatly appreciated. Thanks!
Edit: This is the note that's being thrown by the console. Something to note is main.js:44:5 is the player.stopVideo(); call, and main.js:70:3 is when resetView(); is called on a button click.
TypeError: this.a is null
www-widgetapi.js:120:73
f.C
https://s.ytimg.com/yts/jsbin/www-widgetapi-vflWgX7t4/www-widgetapi.js:120:73
V
https://s.ytimg.com/yts/jsbin/www-widgetapi-vflWgX7t4/www-widgetapi.js:112:97
Nb/</this[a]
https://s.ytimg.com/yts/jsbin/www-widgetapi-vflWgX7t4/www-widgetapi.js:130:124
resetView
file:///Users/cipher/Desktop/ERHS_video/js/main.js:44:5
<anonymous>
file:///Users/cipher/Desktop/ERHS_video/js/main.js:70:3
dispatch
file:///Users/cipher/Desktop/ERHS_video/js/jquery-3.2.1.min.js:3:10264
add/q.handle
file:///Users/cipher/Desktop/ERHS_video/js/jquery-3.2.1.min.js:3:8326
The problem here is player is NOT undefined. What's happening is you have a global player reference, and you're doing the following with it:
Creating a player in the first panel
Destroying it when the first panel closes
Calling player.stopVideo() on the already destroyed player (from the first panel) when the second panel closes
Currently, player holds a reference to whatever the last YouTube player you were using is, even if that player has already been destroyed.
What you should be doing is clearing out your reference to the player when you destroy it. Destroy won't (and can't) do that. You can also simplify your if condition since !player will check for null and undefined on its own:
var resetView = function() {
// If a Youtube player is active, make sure we stop it.
if (!player) {
console.log("Player could not be found.");
} else {
player.stopVideo();
player.destroy();
player = null; // Clear out the reference to the destroyed player
}
Highly inspired from IkeDoud's above answer and some others like this one, one year later, here is my way to avoid other video suggestions on play end in embedded API player:
<div id="player"></div>
<style>
#player{
min-width:auto;
min-height:auto;
}
</style>
<script>
// Load 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);
// Initialise the player with options
var player;
var playerOptions = {
videoId: 'ViDeOiD_HeRe',
events: {
'onStateChange': onPlayerStateChange
}
};
// Load the video whern player ready
function onYouTubeIframeAPIReady() {
player = new YT.Player('player', playerOptions);
}
// On video end, reset the player back to poster image
function onPlayerStateChange(event) {
if(event.data === 0) {
$(PaReNt_sElEcToR).find("#player").replaceWith('<div id="player"></div>');
player = null;
player = new YT.Player('player', playerOptions);
}
}
</script>
No more irrelevant suggestions playable from the embedded video container.
And no autoplay (mobile forbids it anyway) to have the poster (thumbnail) image.
On event.data === 0, which is video end... Destroy and reload the Iframe.

Simulate mouse click on Youtube videos on Android Kitkat

Youtube allows embedding user created playlist with the help of iframe code. I would like to embed them in a webpage to be played back on Android (Kitkat 4.4) tv box hardware. However it requires user to first click on the video.
As I found out that Apple iOS and Android disables autoplay on most mobile platforms to avoid poor user experiences
However, is it possible to simulate a user click on the iframe using Jquery or pure JS solution (preferred). Something like this:
function myFunction() {
setTimeout(function() { ("#myiframe").triggerHandler('click'); },3000)
};
I'd be very grateful if somebody can help me with this as this functionality is crucial for my purpose and I have searched extensively but couldn't get a proper solution.
thanks
dkj
Good morning dkjain,
as far as I've read in the Youtube Player API docs, there are several events triggered as soon as the Player is loaded, one of these events that should be used is the onReady() event.
Here's some updated code on how to auto-play a single video or a playlist:
HTML:
<div id="player"/>
will be the placeholder for the Youtube player
Playing a playlist (with playerVars):
JS:
var player;
function onYouTubeIframeAPIReady() {
player = new YT.Player('player', {
height: '390',
width: '640',
playerVars: {
'listType': 'playlist',
'list': 'PLi5VEqNXXQjVJ4-xZb92wTUawkSQRal0u'
},
events: {
'onReady': onPlayerReady
}
});
}
window.onYouTubeIframeAPIReady = onYouTubeIframeAPIReady;
// as soon as the player is loaded, start the playback
function onPlayerReady(event) {
event.target.playVideo();
}
var tag = document.createElement('script');
tag.src = "http://www.youtube.com/iframe_api";
document.head.appendChild(tag);
There is also an autoPlay: 1 playerVar, but this does not seem to be available on mobile plaforms: https://developers.google.com/youtube/iframe_api_reference#Mobile_considerations
Play a single video
JS:
var player;
function onYouTubeIframeAPIReady() {
player = new YT.Player('player', {
height: '390',
width: '640',
videoId: 'nhX4rQ79C1A',
events: {
'onReady': onPlayerReady
}
});
}
window.onYouTubeIframeAPIReady = onYouTubeIframeAPIReady;
// as soon as the player is loaded, start the playback
function onPlayerReady(event) {
event.target.playVideo();
}
var tag = document.createElement('script');
tag.src = "http://www.youtube.com/iframe_api";
document.head.appendChild(tag);
JSFiddles showing the above code:
Single video: http://jsfiddle.net/Moonbird_IT/akjpmvpf/
Playlist: http://jsfiddle.net/Moonbird_IT/akjpmvpf/4/ (updated again)
Let me know if we are going in the right direction :-)

Youtube video API onStateChange event cannot be used to change video

I want to use the onStateChange event provided by the Youtube API to listen to for the end of the video and then get a new video to play in the player. However, this does not seem to be possible for some reason.
function onPlayerStateChange(event) {
if(event.data === 0) {
console.log('done');
goNext();
}
}
function goNext() {
player.loadVideoById('JBJ1VPBrCl0', 0, 'default');
}
I register the event handler like this
player;
function onYouTubePlayerAPIReady() {
player = new YT.Player('player', {
height: '530',
width: '640',
videoId: '0Bmhjf0rKe8',
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
}
Problem is: if I call my function goNext() manually, the video changes. If I wait for the video termination, the 'done' message is printed to the console, but the video does not change. Any ideas what am I doing wrong?
I've put up a fiddle here. Thanks!
http://jsfiddle.net/PHXY2/
FWIW, your fiddle example worked fine for me (after the video ends it automatically starts playing the "Short - Cat Meowing - Funny Cat Video - Red Laser" video ) Did you happen to have any YouTube-related browser extensions installed earlier? Some have been known to cause issues with the YT API.

Check if Embedded YouTube Video has Finished

So I'm writing a TamperMonkey script that sends specific videos to YouTube's embedded player however I want to automatically send them back once the video is finished.
So for example, video http://youtube.com/watch?v=XXXXX it would redirect to http://youtube.com/v/XXXXX. And then, once the video is complete, it would use window.history.go(-2) (as -1 would go to the normal page causing a loop).
The problem I'm having is that I haven't been able to get the second part, the function that runs when the video finishes, to work.
I have tried following the api and looking at other peoples problems and seeing what helped them but I can't seem to get it.
At the moment this is the code I have.
$(document).ready( function() {
var loc = document.location.href;
var l = loc.split('/');
var s = l[4];
var id = s.split('?')[0]
// create youtube player
var player;
function onYouTubePlayerAPIReady() {
player = new YT.Player('player', {
height: '100%',
width: '100%',
videoId: id,
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
}
// autoplay video
function onPlayerReady(event) {
event.target.playVideo();
alert('spotted');
}
// when video ends
function onPlayerStateChange(event) {
if(event.data === 0) {
window.history.go(-2);
}
}
});
I would appreciate it if someone would work with me to get this script working.
Thanks.

how do i program the youtube embed player to unmute when clicked

How do I set the youtube embedded player to unmute upon clicking it. You can see the embedded player i'm referring to at http://www.harvestarmy.org home page. It's the one at the right where it says "Latest Videos from YouTube. I set it up to be muted by default, but I want it to automatically unmute when someone clicks it.
Here is the code I used:
<!-- 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');
// This is a protocol-relative URL as described here:
// http://paulirish.com/2010/the-protocol-relative-url/
// If you're testing a local page accessed via a file:/// URL, please set tag.src to
// "https://www.youtube.com/iframe_api" instead.
tag.src = "//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: '98',
width: '175',
playerVars: {
'list': 'UUFwY5Al1Doy7f0MdKnJ-gaw',
'modestbranding': 1,
'showinfo': 0,
'autoplay': 1
},
events: {
'onReady': onPlayerReady
}
});
}
// 4. The API will call this function when the video player is ready.
function onPlayerReady(event) {
event.target.mute();
}
</script>
Thank you for that answer! I implemented it a little differently, adding it to the onYouTubeIframeAPIReady function.
I also reversed the initialized value of the isUnMuted variable. Functionally it is the same, but makes more sense this way.
var player;
var isUnMuted = false;
window.onYouTubeIframeAPIReady = function() {
player = new YT.Player('youTube', {
videoId: '[myVideoId]',
playerVars: {
'rel': 0,
},
events: {
'onReady': function() {
player.mute();
player.playVideo();
},
'onStateChange': function () {
if (player.isMuted() && player.getPlayerState() == 2 && !isUnMuted) {
player.unMute();
player.playVideo();
isUnMuted = true;
}
}
}
});
}
This mimics closely the behavior of embedded videos in a Facebook newsfeed.
I don't think it is possible, because there is not such thing as a 'click' or 'activate' event. However, you may try adding an event handler to the "onStateChange" event and unmute and unpause your player. I haven't tried it, but give it a try and see if this works:
var isUnMuted = true;
player.addEventListener("onStateChange", function(event) {
if( player.isMuted() && player.getPlayerState() == 2 && isUnMuted ) {
player.unMute();
player.playVideo(); // resume playback
isUnMuted = false; // you want to run this once only!
}
});
This works. But unfortunately the pause icon fades in when the video is clicked. Even the video continues to run it is not a clean solution.
I fixed it by placing a <div> with exactly the same size above the actual video iframe and use its click() function to unmute the video.
HTML:
<div class="video-container">
<div class="video-dummy">
</div>
<div id="player">
</div>
</div>
CSS:
.video-container {
position: relative;
width: 640px;
height: 390px;
}
.video-dummy {
width: 640px;
height: 390px;
position: absolute;
}
Javascript:
$('.video-dummy').click(function(){
player.unMute();
});
This works out well for me.

Categories