How can I embed different YouTube videos at different places on the page using YouTube API? (This means they can not share the same <div> "player".) They also start at different times based on different onclick events. My code works fine when only one video is on the page, but for the life of me I cannot figure out the code to let this all work with 2 or more!
At first I was trying to simply add multiple instances of the code where I wanted each one to be, but that wasn't working. I read that all the players need to be added to one <script>, so I tried this:
(Also, does it matter WHERE on the page the <script> is and where the <div>s are? Can the <script> write to a <div> no matter where they are on the page?)
Anyway, here's the code I'm using:
// inside other containers with with relative and absolute positioning
// that fadeIn and fadeOut using jQuery
<div id="video1"></div>
// inside other containers with with relative and absolute positioning
// that fadeIn and fadeOut using jQuery
<div id="video2"></div>
<script>
var tag = document.createElement('script');
tag.src = "//www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
var player1;
var player2;
function onYouTubeIframeAPIReady() {
player1 = new YT.Player('video1',{
width: '320',
height: '216',
videoId: 'VIDEO_ID_1',
playerVars: {rel: 0, controls: 0, autohide: 1, disablekb: 1, enablejsapi: 1, modestbranding: 1, showinfo: 0 },
events: { 'onStateChange': onPlayerStateChange1 } });;
player2 = new YT.Player('video2',{
width: '320',
height: '216',
videoId: 'VIDEO_ID_2',
playerVars: {rel: 0, controls: 0, autohide: 1, disablekb: 1, enablejsapi: 1, modestbranding: 1, showinfo: 0 },
events: { 'onStateChange': onPlayerStateChange2 } });; }
function startVideo1() {
player1.playVideo();
$('#video_box_B1').delay(1000).fadeIn();
$("#video_box_B1").delay(20000).hide();
};
function onPlayerStateChange1(event) {
if(event.data === 2) {
$("#video_box_B1").hide();
}
}
function startVideo2() {
player2.playVideo();
$('#video_box_E5').delay(1000).fadeIn();
$("#video_box_E5").delay(20000).hide();
};
function onPlayerStateChange2(event) {
if(event.data === 2) {
$("#video_box_E5").hide();
}
}
</script>
// onclick triggers at various places on the page
<img src="image_1.jpg" onclick="startVideo1()" />
<img src="image_2.jpg" onclick="startVideo2()" />
Is there anyone who can tell what I'm doing wrong? BTW, those containers fading in and out works perfectly if I'm using a still image, text-only, or with only one video on the page, so it's not those fading containers causing this. It's got to be the YouTube script. Can anyone help?
Seems to be working in this jsbin:
http://jsbin.com/catuhimo/3/edit
What browser are you trying it out in? If you're using Safari bleeding edge Version 8.0 (10538.39.41) on Yosemite, jsfiddle and jsBin had some trouble rendering things. I tried out your code on Chrome latest and replaced the placeholders with actual video IDs and it worked.
Does that help? Am I missing the point of the your question? Based on what you asked, it seems to work ok for me.
Related
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;
}
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.
I am using Angular-cli. I'd like to utilize the youtube iframe api within an Angular2 module. I couldn't get the youtube-iframe node package to work. And the more Angular2 specific packages don't seem to support the full api features.
Here's my work so far:
I have included the actual api in my assets folder. I have added the location as a script within my .angular-cli.json file.
This is what my AppComponent looks like:
export class AppComponent {
YT;
constructor(){
this.YT = window["YT"];
}
onYouTubeIframeAPIReady() {
console.log(this.YT);
var player;
player = new this.YT.Player('muteYouTubeVideoPlayer', {
videoId: 'KKYYAbGpw6A', // YouTube Video ID
width: 560, // Player width (in px)
height: 316, // Player height (in px)
playerVars: {
autoplay: 1, // Auto-play the video on load
controls: 0, // Show pause/play buttons in player
showinfo: 0, // Hide the video title
modestbranding: 0, // Hide the Youtube Logo
loop: 1, // Run the video in a loop
fs: 0, // Hide the full screen button
cc_load_policy: 0, // Hide closed captions
iv_load_policy: 0, // Hide the Video Annotations
autohide: 1 // Hide video controls when playing
},
events: {
onReady: function(e) {
e.target.mute();
}
}
});
}
ngAfterViewInit(){
this.onYouTubeIframeAPIReady();
}
It works when I have the devTools open in Chrome. But not when I have them closed. This is the error I get:
this.YT.Player is not a constructor
at AppComponent.webpackJsonp.328.AppComponent.onYouTubeIframeAPIReady
I guess the problem is using window["YT"]. Can anyone provide me with a step by step guide of doing this properly?
This should be a timing issue. For the onYouTubeIframeAPIReady, It is a youtube provided callback. So inside ngOninit() or ngAfterViewInit(), I would recommend you register it at the window level to let youtube API call it when everything is ready.
something like:
(<any>window).onYouTubeIframeAPIReady = ()=>{
console.log((<any>window).YT);
this.player = new (<any>window).YT.Player('muteYouTubeVideoPlayer', {
videoId: 'KKYYAbGpw6A', // YouTube Video ID
width: 560, // Player width (in px)
height: 316, // Player height (in px)
playerVars: {
autoplay: 1, // Auto-play the video on load
controls: 0, // Show pause/play buttons in player
showinfo: 0, // Hide the video title
modestbranding: 0, // Hide the Youtube Logo
loop: 1, // Run the video in a loop
fs: 0, // Hide the full screen button
cc_load_policy: 0, // Hide closed captions
iv_load_policy: 0, // Hide the Video Annotations
autohide: 1 // Hide video controls when playing
},
events: {
onReady: function(e) {
e.target.mute();
}
}
});
}
This is very weird. I'm using youtube JavaScript API to embed a playlist on my website. It would be all good except my recent check what's happening in my workers. It seems that the API decided to send it's messages to one of it.
here's the data which my worker is receiving.
bubbles: falsecancelBubble: falsecancelable: falsecurrentTarget: Windowdata: "{"event":"infoDelivery","info":{"currentTime":109.455757,"videoBytesLoaded":1,"videoLoadedFraction":1},"id":1}"defaultPrevented: falseeventPhase: 0lastEventId: ""origin: "https://www.youtube.com"path: Array[1]ports: Array[0]returnValue: truesource: WindowsrcElement: Windowtarget: WindowtimeStamp: 1428083437641type: "message"__proto__: MessageEvent
Also as I've seen in another question Youtube API does this
www-embed-player.js:167 GET chrome-extension://enhhojjnijigcajfphajepfemndkmdlo/cast_sender.js net::ERR_FAILED
I wasn't expecting Google to create such faulty API. Is there a way to disable those things?
Quick experiment rendered a solution. Moved all youtube code to a separate html and embedded in my parent page.
<iframe id="youtubePlayer" src="mediaPlayer.html">
You can still access youtube api from your main page like that
var mediaPlater = document.getElementById('youtubeFrame').contentWindow.player;
// i.e. skip to next video
mediaPlayer.nextVideo();
This solved totally unexpected worker activity. This console error remained but after reading that it's a won't-fix it doesn't bother me.
www-embed-player.js:167 GET chrome-extension://
Content of my mediaPlayer.html
<div id="ytplayer" class="musicPlayer"></div>
<script>
var player = null;
// 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);
// Replace the 'ytplayer' element with an <iframe> and
// YouTube player after the API code downloads.
function onYouTubePlayerAPIReady() {
player = new YT.Player('ytplayer', {
height: '180',
width: '280',
playerVars: {
autoplay: 1,
controls: 0,
listType: 'playlist',
list: 'RD4-OlYiH1DXI'
},
events: {
'onReady': onPlayerReady,
'onError': function () {
setTimeout(function () {
player.nextVideo();
}, 200);
}
}
});
}
function onPlayerReady() {
// fixes firefox ignoring first onerror if the first video is faulty
player.nextVideo();
}
</script>
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},
});