Youtube API multiple videos with events - javascript

Dear Community!
I want to show multiple videos on my website. The speakers should be deactivated by default (i use the mute()-function).
And the videos should start to play automatically when the user scrolls and the videos come into the browser viewport.
I built this with one single video- worked like a charm. But not with multiple Vidoes on one site..
please help what do i miss in my Code?
This ist html-Part:
<div class="video-container">
<div data-id="olBOo_S5AHY"></div>
</div>
<div class="video-container">
<div data-id="3IXKIVZ9T-U"></div>
</div>
<div class="video-container">
<div data-id="LAQDcnwwspQ"></div>
</div>
This ist the js-Part:
function onYouTubePlayerAPIReady() {
var players = document.querySelectorAll('.video-container div')
for (var i = 0; i < players.length; i++) {
new YT.Player(players[i], {
width: 600,
height: 400,
videoId: players[i].dataset.id,
events: {
onReady: initialize
}
});
}
}
function initialize(){
players[i].mute(); // I know that players[i] is wrong..
var waypoints = jQuery('.video-container').waypoint(function() {
if( players[i]) { // I know that players[i] is wrong..
var fn = function(){
players[i].playVideo(); // I know that players[i] is wrong..
}
setTimeout(fn, 1000);
}
}, {
offset: '50%'
})
}
So the videos show up on my site but i do not have an idea how to add these events to each single video? What am i doing wrong
(a lot i guess ;( ....)
Thank you!
Melanie

Hej Milenoi,
your players variable is a nodeList of the divs you query - and does not contain the addressable YouTube elements.
You have to assign those youtube player objects to some place to address them. (Or there might be some other magic to find them?)
Have a look at my bin here: http://jsbin.com/hozaluzaho
It is a working setup - when you scroll down, you will trigger the other players.
You can have a look at how I created the needed objects and so on.
// get .player nodes
var playerDivs = document.querySelectorAll(".player");
// nodelist to array to use forEach();
var playerDivsArr = [].slice.call(playerDivs);
var players = new Array(playerDivsArr.length);
var waypoints = new Array(playerDivsArr.length);
// when youtube stuff is ready
function onYouTubeIframeAPIReady() {
// create yt players
playerDivsArr.forEach(function(e, i) { // forEach ...
players[i] = new YT.Player(e.id, {
height: '390',
width: '640',
videoId: 'M7lc1UVf-VE',
events: { /* no events set */ }
})
})
// create waypoints
$(".player").each(function(i, e) {
waypoints[i] = new Waypoint({
element: e,
handler: function() {
players[i].playVideo();
}
})
});
}
EDIT ADDITION:
Hej again,
No worries,
The initialize function needs to iterate over the array with the many youtube player objects, you are just talking to one player variable in your initialize function (which might not even be set when you followed my code?).
Look at the place where it says create yt players above. You see that each slot of the array players[] gets stuffed with a player-object. Then you have to talk to each of them again to tell them .mute().
In the forEach loop the current object from the array is handed over to the yt variable.
function initialize() {
players.forEach(function(yt, i) {
yt.mute();
});
}
another bin:
http://jsbin.com/ficoyo/edit?html,output
cheers!

Related

custom youtube playlist with custom start and end time

I am trying to make a custom youtube playlist based on the example here.
However, the youtube player gets "jammed" and skips videos (in my case the middle video is skipped). The code is supposed to iterate through the arrays below and play one video at a time with each video having separate start/end times.
How would one go about making this work properly. (note that the code below needs to be uploaded to a website to work. Apparently from a local computer, it does not work)
Here is the code I am using:
<html>
<body>
<div id="ytplayer"></div>
<script>// Load the IFrame Player API code asynchronously.
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/player_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
var i = 0;
var videoId_arr = ['O57DyNMRGY8','-Yh2QGJBd2U','M7lc1UVf-VE'];
var startSeconds_arr = [41,26,17];
var endSeconds_arr = [50,40,30];
// Replace the 'ytplayer' element with an <iframe> and
// YouTube player after the API code downloads.
var player;
var playerConfig = {
height: '360',
width: '640',
videoId: videoId_arr[i],
playerVars: {
autoplay: 1, // Auto-play the video on load
controls: 1, // Show pause/play buttons in player
showinfo: 1, // Hide the video title
modestbranding: 0, // Hide the Youtube Logo
fs: 1, // Hide the full screen button
cc_load_policy: 0, // Hide closed captions
iv_load_policy: 3, // Hide the Video Annotations
start: startSeconds_arr[i],
end: endSeconds_arr[i],
autohide: 0, // Hide video controls when playing
},
events: {
'onStateChange': onStateChange
}
};
function onYouTubePlayerAPIReady() {
player = new YT.Player('ytplayer', playerConfig);
}
function onStateChange(state) {
if (state.data === YT.PlayerState.ENDED) {
i++;
if(typeof videoId_arr[i] === 'undefined')
return;
player.loadVideoById({
videoId: videoId_arr[i],
startSeconds: startSeconds_arr[i],
endSeconds: endSeconds_arr[i]
});
}
}
</script>
</body>
</html>
I have tested your code and I figured out that the state is changing for some unknown reasons very quickly. The state has sometimes the value 0 which equals YT.PlayerState.ENDED although the video was not played.
You can see it by console logging state.data within the onStateChange function.
A small change fixed the problem:
function onStateChange(state) {
var _video_url = state.target.getVideoUrl();
var _video_id = _url.split('v=')[1];
var _current_index = videoId_arr.indexOf(_video_id) +1;
console.log('State: ', _video_id, _current_index, state );
// ensure that the video has been played
if (state.data === YT.PlayerState.ENDED && player.getCurrentTime() >= endSeconds_arr[i]) {
i++;
if(typeof videoId_arr[i] === 'undefined'){
i = 0; // rest the counter
return;
}
}
}
For the code to run properly you should disable browser plugins like Video Resumer or similar - since they can change the state of a youtube video or resumes the videos from where you stopped them last
fiddle: https://jsfiddle.net/_kdts/Lx91ehdw/
I it possible to loop the videos? I was trying by changing i=1
if(typeof videoId_arr[i] === 'undefined'){
i = 1; // rest the counter
return;
}

how can I get my YouTube playlist to shuffle on start and play random videos until the full playlist has played without repeating any of the videos?

OK... been working on this for a couple of months with no working results as of yet... So, now asking for help! I have a YouTube playlist, ID: PLl_KM23gznEAZW-INW8ty4QNaHH8JCnNW. This playlist has close to 1500 videos on it. I am needing a code that will call the list, and play a random video from the list. and I need it to play all 1500 videos in a random order without repeating any of the videos. then after the playlist is completed, it needs to start over, continuing to play the videos in a completely different random order.
I have tried several code snippets and can't seem to get it all to come together. I either get a shuffle with repeats, or I get just a list that doesn't play anything, or it will randomly pick the first video, then maybe the second one, but it will start playing in order from either the first or the second video. And the current youtube player that is working will only call the videos in a 200 song list. IE: if the payer starts in order, only will play 1 through 200, then stop. Or, I can set it to start with any song in the playlist, for instance, # 999, it will go to that video, but will only play videos fromm 999 to 1198.
I have to randomly pick the song and put it in my code to get it to do that.
I need it to start in shuffle mode, choosing any song from the list of 1500 videos, then continue randomly choosing and playing any other video within the list except those that have already played, until it has played all the videos, then loop the playlist and continuing to play a random video from the playlist in no certain order, including the order it just played. My main thing to avoid... having to create the list array manually. I need to be able to call the url of the playlist, and retrieve a list of the videos either by number, video ID, name of the song, etc. Using the easiest, cleanest code.
PS: having comments in place is extremely helpful for my learning process.
And please don't worry about anything, I am 51, disabled, and trying to remind myself of the coding syntaxes after getting a degree in 2003 and not using a bit of it since! I am working on a project for myself, more or less trying to get myself back into being able to read, repair, and create coding for myself. This part though, has me totally stumped!
I hope this is making sense to someone, I'm getting confused just trying to ask the question!!!
tried this one, got nothing... just a blank page...
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() {
var player = new YT.Player("player", {
height: '390',
width: '640',
events: {
'onReady': function (event) {
event.target.cuePlaylist({list: "PLl_KM23gznEAZW-INW8ty4QNaHH8JCnNW"});
event.target.playVideo();
setTimeout(function() {
event.target.setShuffle({'shufflePlaylist' : true});
}, 1000);
}
}
});
}
this one will load the player, but doesn't shuffle or play randomly. just starts with the first video, then continues in order...
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 player;
function onYouTubeIframeAPIReady() {
player = new YT.Player('player', {
height: '390',
width: '640',
events: {
'onReady': onPlayerReady
},
playerVars: {
listType:'playlist',
list: 'PLl_KM23gznEAZW-INW8ty4QNaHH8JCnNW'
}
});
}
function onPlayerReady(event) {
num = _.random(0, 1500);
setTimeout(() => {
player.playVideoAt(num);
}, 1000);
}
this one will start with a random video, but then continues in order from there...
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() {
var numPl = Math.floor((Math.random() * 1500) + 1);
var player = new YT.Player("player", {
height: '390',
width: '640',
playerVars: {
listType:'playlist',
list:'PLl_KM23gznEAZW-INW8ty4QNaHH8JCnNW',
index: numPl,
autoplay: 1,
},
events: {
'onReady': function (event) {
event.target.cuePlaylist({list: "PLl_KM23gznEAZW-INW8ty4QNaHH8JCnNW"});
event.target.playVideo();
setTimeout(function() {
event.target.setShuffle({'shufflePlaylist' : true});
}, 1000);
}
}
});
}
function onPlayerReady(event) {
event.target.mute();
setTimeout( function() {
event.target.setShuffle(true);
event.target.setLoop(true);
}, 2000);
}
function getRandomId() {
var random_id = 0
while(played_idx.indexOf(random_id) != -1) {
random_id = Math.floor(Math.random * playlist.length)
}
return random_id
}
I'm pretty sure there were more, but can't find them at the moment.

Play random youtube video from list/playlist and loop

We have a number of clients who have youtube video advertisements. These are currently in a YouTube playlist, but by embedding the playlist, the same video is always displayed first on the website so we want to randomise which video is displayed on pageload from the playlist. I have a code snippet which will load a random video from the input video url however when the video is finished it does not move on to the next video in the list. Could anyone suggest how I can accomplish what I am trying to do? My code is below.
<!-- Youtube video loop playlist -->
<script>
var videos = ["https://www.youtube.com/embed/9bZkp7q19f0", "https://www.youtube.com/embed/dQw4w9WgXcQ", "https://www.youtube.com/embed/CzJ-h7W1hVw"];
window.onload = function () {
var playerDiv = document.getElementById("random_player");
var player = document.createElement("IFRAME");
var randomVideoUrl = videos[Math.floor(Math.random() * videos.length)];
player.setAttribute('width', '528');
player.setAttribute('height', '330');
player.setAttribute('src', randomVideoUrl);
playerDiv.appendChild(player);
};
onStateChange: function(e){
var id = 'qzZuBWMnS08';
if(e.data === YT.PlayerState.ENDED){
player.loadVideoById(videos);
}
}
</script>
<div id="random_player"></div>
Thank you in advance.
Donna
The function loadVideoById can either get a single ID or a single video in an object syntax. It can't receive an array of videos or a playlist.
Here's my implementation
http://jsfiddle.net/thatkookooguy/e11oy0eu/2247/
(code also embedded at the end)
Notice that the setTimeout is used since there's a bug with the youtube API. if you set either setShuffle or playVideoAt immediately, nothing happens (or the playlist resets and starts from the beginning).
You can add anything else you want to change in the player's playback options (shuffle, loop). If it doesn't work as is, try to add those parameters to the setTimeout as well.
reference: youtube API - setShuffle don't work
// 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);
var player;
// load the playlist
function onYouTubeIframeAPIReady() {
player = new YT.Player('player', {
height: '390',
width: '640',
events: {
'onReady': onPlayerReady
},
playerVars: {
listType: 'playlist',
list: 'PLOy0j9AvlVZPto6IkjKfpu0Scx--7PGTC'
}
});
}
// when the video player is ready, generate a random number, and play from that
function onPlayerReady(event) {
// create a random number between 0 and 149
num = Math.floor(Math.random() * 150);
// the timeout is set because of a bug with the youtube API. if you do any of this line without it, it won't affect anything
// see: https://stackoverflow.com/questions/12916017/youtube-api-setshuffle-dont-work
setTimeout(() => {
player.playVideoAt(num);
}, 1000);
}
<div id="player"></div>

Youtube Javascript API - disable related videos

Right, this seems to be poorly documented or I can't see it in the documentation. I basically want no related videos (?rel=0) using the JavaScript API.
$players[$vidIdPlaceholderRef] = new YT.Player('player_' + $vidIdPlaceholderRef, {
height: '550',
width: '840',
videoId: $vidId
});
is what I have in place.
I have also tried:
$players[$vidIdPlaceholderRef] = new YT.Player('player_' + $vidIdPlaceholderRef, {
height: '550',
width: '840',
videoId: $vidId + '?rel=0',
rel : 0
});
with no luck. Does any one know of an option which can be added (tried rel : 0 with no luck )
"rel" is a player parameter, as specified here:
https://developers.google.com/youtube/player_parameters#rel
To add player parameters to iframe players, you need to specify the playerVars property of the second constructor argument (at the time of writing this is documented here, and on the IFrame API documentation page)
e.g.
new YT.Player('playerid', {
height: '550',
width: '840',
videoID: 'video_id',
playerVars: {rel: 0, showinfo: 0, ecver: 2}
});
The behavior of the rel player parameter has changed.
From documentation,
The behavior for the rel parameter is changing on or after September
25, 2018. The effect of the change is that you will not be able to
disable related videos. However, you will have the option of
specifying that the related videos shown in the player should be from
the same channel as the video that was just played
So, it's no longer possible to disable related videos. Instead playerVars: {rel:0} will change the behavior of the player and shows suggestion from specified channel.
You get related videos in two places: at the end of the video with the grid, and at the bottom of the video while paused. I've figured out a way to remove them at the end and make the ones at the bottom at least tolerable for most businesses.
1. Remove related videos at the end of a video
IFrame Player API: Events
To avoid showing related videos at the end of a video, I just stopped the video so it returned to showing the thumbnail and play button:
var player = new YT.Player('player', {
height: '390',
width: '640',
events: {
'onStateChange': function(event){
switch(event.data){
// Stop the video on ending so recommended videos don't pop up
case 0: // ended
player.stopVideo();
break;
case -1: // unstarted
case 1: // playing
case 2: // paused
case 3: // buffering
case 5: // video cued
default:
break;
}
}
}
});
You could also replace player.stopVideo(); with any other code you want to run.
2. Making related videos at the bottom of a video only show your videos
IFrame Player API: YouTube Embedded Players and Player Parameters
rel=0 no longer avoids showing any related videos; now, it will still show related videos, but at least they'll only be from your channel. This changed sometime around September 25, 2018 (documentation).
By setting playerVars in YT.Player, we can at least have related videos only show our channel's videos. The documentation isn't clear that you have to have playerVars set up as an object, but you can set it up like so:
var player = new YT.Player('player', {
...
playerVars:{
rel: 0
modestbranding: 1, // If you're trying to remove branding I figure this is helpful to mention as well; removes the YouTube logo from the bottom controls of the player
// color: 'white', // Can't have this and modestbranding active simultaneously (just a note in case you run into this)
},
...
});
2A. Potential way to remove related videos from bottom
I may look more into it if I have the time, but here's where an answer may lie:
We can easily access the iframe object but we can't do anything with it: IFrame Player API: Accessing and modifying DOM nodes. It appears that because we'd be editing an iframe from YouTube there are security concerns (regardless of what we'd actually be doing). Ideally I could just remove the "More videos" text with player.getIframe().contentWindow.document.querySelector('.ytp-pause-overlay.ytp-scroll-min').remove(), but when I run player.getIframe().contentWindow.document I get an error SecurityError: Permission denied to access property "document" on cross-origin object.
But playerVars also has an origin value that may let us access the iframe's object anyway:
var player = new YT.Player('player', {
...
playerVars:{
origin: 'https://mywebsite.com'
},
...
});
It's not working with localhost, but that may be a Chromium and Firefox thing. Perhaps this is a legitimate option on a live site; I'll update this post when/if I try that to let you know if I succeed.
The accepted solution was not working for me. What does work is:
1) Putting the iframe in html that includes the rel parameter
<iframe id="youtube-video" width="560" height="315"
src="https://www.youtube.com/embed/M7lc1UVf-VE?enablejsapi=1&rel=0&modestbranding=1"
frameborder="0" enablejsapi="1" allowfullscreen></iframe>
2) Using the javascript API to attach to that existing player
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 player;
function onYouTubeIframeAPIReady() {
player = new YT.Player('youtube-video', {
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
}
function onPlayerReady(event) {
console.log("ready");
}
function onPlayerStateChange(event) {
console.log("state changed");
}
demo fiddle: http://jsfiddle.net/bf7zQ/195/
If you're using SWFObject, you simply need to do something like this:
function loadVideo() {
var params = { allowScriptAccess: "always" }
, atts = { id: "myvideo" }
;
//NOTE THE END OF THE BELOW LINE vvvvvv
swfobject.embedSWF("https://www.youtube.com/v/[video id here]?enablejsapi=1&playerapiid=myvideo&version=3&rel=0"
, "videoplaceholderid"
, "768", "432", "8", null, null, params, atts);
}
Just add rel=0 to the end of your url.
No need to code through the API,now its easily can be done by
You tube embed button -> Show more -> tickout the option 'Show suggested videos when the video finishes'
Here is a Quick solution:
setInterval(function(){
if($('iframe').length > 0){
$('iframe').each(function(){
if($(this).hasClass('gotYou')){
//do nothing
}else{
var getMySrc = $(this).attr('src');
var newSrc = getMySrc.split('?');
console.log(newSrc);
var freshURL = newSrc[0]+'?rel=0&'+newSrc[1];
console.log(freshURL);
$(this).addClass('gotYou');
$(this).attr('src', freshURL );
}
});
}
}, 1);
What it does it, it looks for the iframe in your document. If it finds iframe, it grabs the src of the iframe, finds the ? mark and then replaces ? by ?rel=0& . Here the goal is to out rel=0
new YT.Player('playerid', {
height: '550',
width: '840',
videoID: 'video_id',
playerVars: {rel: 0},
});

Youtube API and javascript questions

I know this has to be totally ghetto, but I'm trying to figure out how to get a feed of my youtube links to display on my homepage in a somewhat stylish fashion. I get tired of having to post something on youtube, then create a post on my website that is basically a duplication of the youtube post. Perhaps there is already something out there that has this functionality built in, but so far I haven't seen it. I have a couple questions about what I'm trying to accomplish thus far:
How can I update my code so I can use 'this' in my youTubeMe object verse having to reference the variable name. I'm pretty sure I understand why I can't use it how I'm doing it currently, but I don't know how to fix?
Second, the google api seems a bit weird to me. I'm not too stoked about using iFrames and the split operation I have to do in order to get the VideoId can't be correct.
Any advice would be greatly appreciated. I'll post the code, but you can also find a working example here
HTML:
<div id="pager">
</div>
<div id="player">
</div>
<script type="text/javascript">
var tag = document.createElement('script');
tag.src = "http://www.youtube.com/player_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
function onYouTubePlayerAPIReady() {
youTubeMe.init();
}
</script>
JAVASCRIPT:
var youTubeMe = {
pageSize: 10,
player: null,
startIndex: 1,
username: 'google',
init: function() {
$.getJSON('http://gdata.youtube.com/feeds/users/' + this.username + '/uploads?alt=json&start-index=' + this.startIndex + '&max-results=' + youTubeMe.pageSize, youTubeMe.createYouTubePlayers);
},
createYouTubePlayers: function(data) {
$('#player').empty();
$('#pager').empty();
if (data.feed.entry.length < youTubeMe.pageSize) {
youTubeMe.createPreviousButton();
} else {
if (youTubeMe.startIndex !== 1) {
youTubeMe.createPreviousButton();
}
youTubeMe.createNextButton();
}
for (var i = 0; i < data.feed.entry.length; i++) {
player = new YT.Player('player', {
height: '195',
width: '320',
videoId: data.feed.entry[i].id.$t.split('/')[5]
});
}
},
createNextButton: function() {
$('<a id=\"next\" href=\"#\">next</a>').appendTo('#pager');
$('#next').click(function(e) {
e.preventDefault();
youTubeMe.startIndex += youTubeMe.pageSize;
youTubeMe.init();
});
},
createPreviousButton: function() {
$('<a id=\"prev\" href=\"#\">prev</a>').appendTo('#pager');
$('#prev').click(function(e) {
e.preventDefault();
youTubeMe.startIndex -= youTubeMe.pageSize;
youTubeMe.init();
});
}
};
CSS:
iframe { margin: 20px; }
#pager { background-color: #666; line-height: 3em; text-align: center; }
#pager a { color: #fff; font-size: 1.8em; margin: 0 15px; }
The way you should go is create a closure and have everything contained in that. You can do it like this:
//a closure function that calls itself
(function(){
//with var it would be private and not accesable like this:
//youTubeMe.pageSize
var pageSize = 10;
//declare a global reference to the youTubeMe object
var youTubeMe = window.youTubeMe = function(){
};
//with youTubeMe.* it is accessable from anywhere in your page
//you can either
//declare a public variable like this
youTubeMe.player = "youtube player";
//or a public method like this
youTubeMe.foo = function(){
//this "this" here is your youTubeMe object
console.log(this);
bar();
};
//like the private variable at the top, this function is private
//and can only be called from inside the youTubeMe object
function bar(){
//this "this" here is the window
console.log(this);
}
})();
console.log(youTubeMe.player); //out puts youtube_player
youTubeMe.foo(); //outputs the youTubeMe object
youTubeMe.bar() //throws an undefined error
As for the youtube api; I've always found it to be really good. I've never used the iframe embed just because "iframe embed" sounds not right to me. If you use the youtube api you have two options: Embedded player or the chromeless player. Take a look at the embedded player because unless you want to build a custom skin for your player, its the way to go. Creating a playlist becomes easy when you use the api because you let javascript do all the playing and playlist stuff.
Hope that helps.

Categories

Resources