There are multiple youtube videos playing in my site in a carousel. When a user click on a youtube video then I want to stop the auto scrolling of the carousel. Here is the code I am writing which is throwing me "players[player_id].getPlayerState() is not a function" error.
Also the youtube library is loading in my site from a thrid party javascript.
players = {};
window.onYouTubeIframeAPIReady = function(){
$('.youtube-video iframe').each(function() {
players[$(this).attr('id')] = new YT.Player($(this).attr('id'), {
events: {
'onStateChange': onPlayerStateChange($(this).attr('id'))
}
});
});
}
function onPlayerStateChange(player_id){
return function(event) {
if(players[player_id].getPlayerState() == 3 ||players[player_id].getPlayerState() == 1) {
//stop the auto scrolling
}
if(players[player_id].getPlayerState() == 0 || players[player_id].getPlayerState() == 2) {
//start auto scrolling.
}
}
}
Please let me know if you can find the issue in my code. Thanks in advance!
You forgot some sample paramters like videoId: $(this).attr('id') and events
was not placed at the good place.
I post you the correct code :
HTML
<div class="youtube-video" id="O1RHkPGb31Q"></div>
<div class="youtube-video" id="VjRb3RjqncQ"></div>
Javascript:
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
players = {};
window.onYouTubeIframeAPIReady = function(){
$('.youtube-video').each(
function() {
players[$(this).attr('id')] = new YT.Player($(this).attr('id'),
{
videoId: $(this).attr('id'),
events: { 'onStateChange': onPlayerStateChange($(this).attr('id')) }
});
});
};
function onPlayerStateChange(player_id){
return function(event) {
if(players[player_id].getPlayerState() == 3 || players[player_id].getPlayerState() == 1) {
//stop the auto scrolling
console.log("stop scolling video" + player_id);
}
if(players[player_id].getPlayerState() == 0 || players[player_id].getPlayerState() == 2) {
//start auto scrolling.
console.log("start scolling video" + player_id);
}
};
}
Live demo : http://jsbin.com/nisetafoga/1/edit?html,js,console,output
Related
Background video loads properly and autoplays etc. when the page is first loaded (and when refreshed) but when navigating to the page via the navbar links the video wont load.
Site is using Ruby on Rails if that makes any difference.
I suspect my issue is somewhere in the js but I'm new to this and haven't been able to sort out what isn't triggering
Script for the video:
// Video Script //
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
// Inserts YouTube JS code into the page.
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
var player;
// onYouTubeIframeAPIReady() is called when the IFrame API is ready to go.
function onYouTubeIframeAPIReady() {
player = new YT.Player('player', {
height: '360',
width: '640',
videoId: '7copSLUofm8',
playerVars: { 'autoplay': 1, 'controls': 0, 'showinfo': 0, 'rel': 0, 'enablejsapi':1, 'wmode' : 'transparent'},
events : {
'onReady' : pkOnPlayerReady,
'onStateChange' : pkOnPlayerStateChange
}
});
}
function pkOnPlayerStateChange(e) {
var frm = $(e.target.getIframe());
if (e.data === YT.PlayerState.ENDED) {
if ('player' === frm.attr('id')) {
player.playVideo();
}
}
if (e.data === YT.PlayerState.BUFFERING) {
if ('player' === frm.attr('id')) {
e.target.setPlaybackQuality('hd720');
}
}
}
function pkOnPlayerReady(e) {
player.mute();
e.target.setPlaybackQuality('hd720');
}
//Load a youtube pixel
var pkEnableYoutube = function() {
var deferred = jQuery.Deferred();
var img = new Image();
img.onload = function() { return deferred.resolve(); };
img.onerror = function() { return deferred.reject(); };
img.src = "https://s.ytimg.com/yts/img/pixel-vfl3z5WfW.gif?"+ new Date().getTime();
return deferred.promise();
};
//When the video starts to load, set a timer for the video wrap to fade in
jQuery(function($){
$.when(pkEnableYoutube()).done(function(){
setTimeout(function() {
$('.video_wrap').fadeIn();
}, 2000);
});
});
I have been working on the receiver in the google cast sdk. I have mutiple youtube videos and mp4 videos in cloud and i have an app that has these videos. I am able to able to cast the youtube videos but when i click on the mp4 link i cannot get back control to the receiver.
Anybody any help?`
var player;
function onYouTubePlayer(videoId) {
player = new YT.Player('player', {
height: '720',
width: '1280',
videoId: videoId,
playerVars: { autoplay:1, controls:1, showinfo: 0, rel: 0, showsearch: 0, iv_load_policy: 3, enablejsapi:1,listType:'playlist',
list: playlist},
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange,
'onError': catchError
}
});
}
var done = false;
var playlist;
function onPlayerStateChange(event) {
if (event.data == YT.PlayerState.PLAYING && !done) {
done = true;
} else if (event.data == YT.PlayerState.ENDED) {
event.target.destroy();
location.reload();
}else if(event.data == YT.PlayerState.PAUSED){
location.reload();
}
}
function onPlayerReady(event) {
//if(typeof(SONG.getArtistId()) == undefined)
//{
// console.log("undefineeeed");
//}
player.addEventListener('onStateChange', function(e) {
console.log('State is:', e.data);
});
event.target.playVideo();
}
function catchError(event)
{
if(event.data == 100) console.log("This Video does not exist!!");
}
function stopVideo() {
player.stopVideo();
}
/**
* Called when we receive a LOAD message. Calls load().
*
* #see sampleplayer#load
* #param {cast.receiver.MediaManager.Event} event The load event.
* #private
*/
sampleplayer.CastPlayer.prototype.onLoad_ = function(event) {
this.log_('onLoad_');
this.log_(event.data);
// handler for the CastMessageBus message event
this.messageBus.onMessage = function(event) {
this.log_('Message [' + event.senderId + ']: ' + event.data);
// display the message from the sender
// inform all senders on the CastMessageBus of the incoming message event
// sender message listener will be invoked
this.messageBus.send(event.senderId, event.data);
}
var videoId = event.data.media.contentId.split("?v=")[1];
if(event.data.media.contentId.includes("youtube.com")){
if (typeof(YT) == 'undefined' || typeof(YT.Player) == 'undefined') {
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
window.onYouTubePlayerAPIReady = function() {
onYouTubePlayer(videoId);
};
} else {
onYouTubePlayer(videoId);
}
}else{
}
this.cancelDeferredPlay_('new media is loaded');
this.load(new cast.receiver.MediaManager.LoadInfo(
/** #type {!cast.receiver.MediaManager.LoadRequestData} */ (event.data),
event.senderId));
};
`
I've looked through so many questions and the youtube api stuff but for the life of me can't figure out why the onYouTubeIframeAPIReady is not working.
Here is my iframe:
<iframe id="youtube_vid" width="763" height="430" src="https://www.youtube.com/embed/dlJshzOv2cw?theme=light&showinfo=0&rel=0&enablejsapi=1" frameborder="0" allowfullscreen=""></iframe>
And my script:
function callYTapi() {
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
console.log('script loaded');
function onYouTubeIframeAPIReady() {
console.log('IframeAPI = Ready');
var player = new YT.Player('youtube_vid', {
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
}
function onPlayerReady(event) {
event.target.playVideo();
}
function onPlayerStateChange(event) {
if (event.data == YT.PlayerState.PAUSED) {
console.log("Paused");
}
if (event.data == YT.PlayerState.PLAYING) {
console.log("Playing");
}
if (event.data == YT.PlayerState.ENDED) {
end();
}
}
}
I get the console.log for the loaded script but not for Iframe ready or anything else. Any ideas? Thanks
The callback functions must be in the global scope. Just move onYouTubeIframeAPIReady and the others outside callYTapi.
Just to be clear, the accepted answer above seems to work for me in this way:
Load API (from yt documentation)
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
specify YouTube's built-in ready function "onYouTubeIframeAPIReady" on window
window.onYouTubeIframeAPIReady = this.onYTready;
So this.onYTready is my function name and located elsewhere.
I can confirm my onYTready function can console logs/debugger breakpoints in Chrome.
(edit) you may want to bind this to your function, example:
window.onYouTubeIframeAPIReady = this.onYTready.bind(this);
or 'this' will be for window instead of a specific view you may be using..
Fortunately for me, after a lot of experimenting with console, I had something concrete. I kind of had the same issue until a day ago and figured out how to do when I was within a singleton scope.
Here is what my code looks like:
var XT = XT || {};
window.onYouTubeIframeAPIReady = function(){
setTimeout(XT.yt.onYouTubeIframeAPIReady,500);
}
XT.yt = {
/* load the YouTube API first */
loadApi: function () {
var j = document.createElement("script"),
f = document.getElementsByTagName("script")[0];
j.src = "//www.youtube.com/iframe_api";
j.async = true;
f.parentNode.insertBefore(j, f);
console.log('API Loaded');
},
/*default youtube api listener*/
onYouTubeIframeAPIReady: function () {
console.log('API Ready?');
window.YT = window.YT || {};
if (typeof window.YT.Player === 'function') {
player = new window.YT.Player('player', {
width: '640',
height: '390',
videoId: 'nE6mDCdYuwY',
events: {
onStateChange: XT.yt.onPlayerStateChange,
onError: XT.yt.onPlayerError,
onReady: setTimeout(XT.yt.onPlayerReady, 4000)
}
});
}
},
onPlayerReady: function() {
player.playVideo(); /* start the video */
player.setVolume(1); /* set volume to 1 (accepts 0-100) */
},
onPlayerStateChange: function (e) {
console.log(e.data, YT.PlayerState.PLAYING, e.data === YT.PlayerState.PLAYING);
var video_data = e.target.getVideoData();
//do something on video ends
if(e.data === YT.PlayerState.ENDED)
this.onPlayerStop();
},
onPlayerStop: function(){
//console.log('video ended');
},
onPlayerError: function (e) {
console.log( "youtube: " + e.target.src + " - " + e.data);
},
init: function () {
this.loadApi();
}
}
XT.yt.init();
function playIframeVideo(iframe) {
iframe.videoPlay = true; //init state
iframe.contentWindow.postMessage('{"event":"command","func":"playVideo","args":""}', '*');
}
function pauseIframeVideo(iframe) {
iframe.videoPlay = false; //init state
iframe.contentWindow.postMessage('{"event":"command","func":"pauseVideo","args":""}', '*');
}
$('.vc_video-bg-container').on('click', function () {
var iframe = $('iframe').get(0); //iframe tag
if (iframe.videoPlay != true) {
playIframeVideo(iframe);
} else {
pauseIframeVideo(iframe);
}
});
I need to know when a youtube video has stopped playing. I looked up existing Q&As and all of them suggested redirecting to another unique URL which can be detected in webview load finished delegate.
But to do this I need to have a HTML page on server or in my app(since I need to add javascript functions for onStateChange). If its on server, server downtime will affect the app, if its in the app, any change would require an app update.
Is there any other workaround for this ?
EDIT: JS code which needs to be injected/loaded in html.
var player;
var videoID;
var prmstr = window.location.search.substr(1);
var prmarr = prmstr.split ("&");
var params = {};
for ( var i = 0; i < prmarr.length; i++) {
var tmparr = prmarr[i].split("=");
params[tmparr[0]] = tmparr[1];
}
if (params.videoID !== undefined || params.videoID !== "") {
videoID = params.videoID;
} else {
videoID = "0Bmhjf0rKe8";
}
function onYouTubePlayerAPIReady() {
player = new YT.Player('player', {
height: '390',
width: '640',
videoId: videoID,
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
}
// autoplay video
function onPlayerReady(event) {
event.target.playVideo();
}
// when video ends
function onPlayerStateChange(event) {
if(event.data === 0) {
window.location.href = "http://example.com/done.html";
}
}
I have a jCarousel (jquery) running for several youtube videos. The carousel works great, and even pauses when you hover on a slide- but it will resume if you move your cursor off the slide, even if the video is playing.
Videos are embedded using the YouTube Player API.
Plugin: http://sorgalla.com/jcarousel/
This is the Carousel code I'm using:
<script type="text/javascript">
function mycarousel_initCallback(carousel, item, idx, state){
// Disable autoscrolling if the user clicks the prev or next button.
carousel.buttonNext.bind('click', function() {
carousel.startAuto(0);
});
carousel.buttonPrev.bind('click', function() {
carousel.startAuto(0);
});
// Pause autoscrolling if the user moves with the cursor over the clip.
$('#mycarousel').hover(function() {
carousel.stopAuto();
}, function() {
carousel.startAuto();
});
};
$(function() {
$('#mycarousel').jcarousel({
auto: 2,
wrap: 'both',
initCallback: mycarousel_initCallback
});
});
</script>
The YouTube script:
<script>
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: '505', // 535
width: '900',
videoId: 'DxZve0UV6UM',
playerVars: {
'autoplay': 0,
'controls': 0,
'modestbranding': 1,
'wmode': 'opaque'
},
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
}
function onPlayerReady(evt) {
player.setPlaybackQuality('hd720');
}
function onPlayerStateChange(evt) {
if (evt.data == YT.PlayerState.PLAYING && !done) {
done = true;
}
}
function stopVideo() {
player.stopVideo();
}
</script>
And the HTML...
<ul id="mycarousel" class="jcarousel-skin-tango">
<li>
<div id="player"></div>
</li>
<li>
<div id="player"></div>
</li>
</ul>
Any suggestions?
Simply call carousel.startAuto() and carousel.stopAuto() when the player triggers an event:
function onPlayerStateChange(evt) {
if(evt.data == YT.PlayerState.PLAYING) {
global_carousel.stopAuto(); // Stop the carousel, if video is playing
} else {
global_carousel.startAuto(); // Otherwise, start it
}
}
Edit:
Make the variable carousel global inside mycarousel_initCallback:
var global_carousel;
function mycarousel_initCallback(carousel, item, idx, state) {
global_carousel = carousel;
//Other code
Then use that instead in the code before (as I've edited).