A bigger issue that I notice is that the settings parameter looks to be broken. That needs to be fixed up before other things relating to it can be fixed. The problem looks to be happening inside of the createPlayerOptions function and required further investigation there.
Delving deeper into what’s causing the problem at https://jsfiddle.net/jwbrg2p1/2/, the createPlayerOptions function receives a settings object with the following:
{
height: 207,
width: 277
}
That is all good and expected.
What is returned from the createPlayerOptions function is the following broken object.
{
height: 600
playerVars: {
height: 600
playerVars: {
autoplay: 0
}
width: 360
}
width: 360
}
That’s quite messed up, and is quite different from what it should be doing.
What should be happening is that a combined version of both the settings and the managePlayer config should be returned instead, without changing anything about that config.
It’s possible to fix that, but it would be easier to copy over an already working version of the createPlayerOptions function.
Code 1 Playlist not working, Settings work.
https://jsfiddle.net/xvq8yup2/
players.push(new YT.Player(video, playerOptions));
Code 2 Playlist works, Settings don’t work
https://jsfiddle.net/xvq8yup2/2/
players.push(new YT.Player(video, config));
What you had me do: Post#338
https://jsfiddle.net/jwbrg2p1/2/
The main thing for me is being able to keep these separated, so they are not mixed in with each other.
Can that be achieved?
const config = {
host: "https://www.youtube-nocookie.com",
videoId
};
config.playerVars = {
playlist: playlist || undefined
};
config.events = {
"onReady": onPlayerReady
};
I got it working here, no jslint errors.
Does that look good to you,
Is there anything else you would do, any other adjustments needed?
Playlist and settings both work.
https://jsfiddle.net/v5up417y/
function addPlayer(video, settings, videoIds = video.dataset.id) {
const videoId = !Array.isArray(videoIds) && videoIds;
const playlist = Array.isArray(videoIds) && videoIds.join();
const defaults = {
playerOptions: {
events: {
"onReady": onPlayerReady,
"onStateChange": onStateChange
},
host: "https://www.youtube-nocookie.com",
playerVars: {
playlist: playlist || undefined
},
videoId
}
};
const defaultOptions = defaults.playerOptions;
const defaultVars = defaultOptions.playerVars;
const playerVars = settings.playerVars;
const playerOptions = Object.assign({}, defaultOptions, settings);
playerOptions.playerVars = Object.assign({}, defaultVars, playerVars);
const player = new YT.Player(video, playerOptions);
players.push(player);
return player;
}
return {
addPlayer
};
}());
const managePlayer = (function makeManagePlayer() {
const defaults = {
playerOptions: {
height: 600,
playerVars: {
autoplay: 0,
controls: 1,
disablekb: 1,
enablejsapi: 1,
fs: 0,
iv_load_policy: 3,
rel: 0
},
width: 360
}
};
function show(el) {
el.classList.remove("hide");
}
function createPlayerOptions(settings) {
function paramInOptions(opts, param) {
if (settings[param] !== undefined) {
opts[param] = settings[param];
delete settings[param];
}
return opts;
}
const optionParams = ["width", "height", "videoid", "host"];
const defaultOptions = defaults.playerOptions;
const preferred = optionParams.reduce(paramInOptions, {});
const playerOptions = Object.assign({}, defaultOptions, preferred);
// settings should now only consist of playerVars
const defaultPlayerVars = defaultOptions.playerVars;
const playerVars = Object.assign({}, defaultPlayerVars, settings);
playerOptions.playerVars = playerVars;
return playerOptions;
}
function createPlayer(videoWrapper, settings = {}, videoIds = "") {
const video = videoWrapper.querySelector(".video");
if (!videoIds) {
videoIds = video.dataset.id;
}
const playerOptions = createPlayerOptions(settings);
return videoPlayer.addPlayer(video, playerOptions, videoIds);
}
function createCoverClickHandler(playerSettings, videoIds) {
return function coverClickHandler(evt) {
const cover = evt.currentTarget;
const wrapper = cover.nextElementSibling;
show(wrapper);
const player = createPlayer(wrapper, playerSettings, videoIds);
wrapper.player = player;
};
}
function addPlayer(coverSelector, playerSettings, videoIds) {
const clickHandler = createCoverClickHandler(playerSettings, videoIds);
manageCover.addCoverHandler(coverSelector, clickHandler);
}
function addPlayerRandomVideo(coverSelector, playerSettings, videoIds) {
const index = Math.floor(Math.random() * videoIds.length);
const videoId = videoIds[index];
const clickHandler = createCoverClickHandler(playerSettings, videoId);
manageCover.addCoverHandler(coverSelector, clickHandler);
}
function init(playerOptions) {
Object.assign(defaults.playerOptions, playerOptions);
}
return {
add: addPlayer,
addRandom: addPlayerRandomVideo,
init
};
}());
2nd Question: If the above is good,
Can I do this?
What I did was move all the playerOptions
from: const managePlayer = (function makeManagePlayer() {
and placed them in here:
function addPlayer(video, settings, videoIds = video.dataset.id) {
If I can, and that is good, is there anything you would change?
Can further improvements be made from this point?
no jslint errors and the code works.
https://jsfiddle.net/1hjskb30/
Would this stay as it is, or would it be changed?
const defaults = {
playerOptions: {
playerVars: {}
}
};
Code
function addPlayer(video, settings, videoIds = video.dataset.id) {
const videoId = !Array.isArray(videoIds) && videoIds;
const playlist = Array.isArray(videoIds) && videoIds.join();
const defaults = {
playerOptions: {
events: {
"onReady": onPlayerReady,
"onStateChange": onStateChange
},
height: 600,
host: "https://www.youtube-nocookie.com",
playerVars: {
autoplay: 0,
controls: 1,
disablekb: 1,
enablejsapi: 1,
fs: 0,
iv_load_policy: 3,
playlist: playlist || undefined,
rel: 0
},
videoId,
width: 360
}
};
const defaultOptions = defaults.playerOptions;
const defaultVars = defaultOptions.playerVars;
const playerVars = settings.playerVars;
const playerOptions = Object.assign({}, defaultOptions, settings);
playerOptions.playerVars = Object.assign({}, defaultVars, playerVars);
const player = new YT.Player(video, playerOptions);
players.push(player);
return player;
}
return {
addPlayer
};
}());
const managePlayer = (function makeManagePlayer() {
const defaults = {
playerOptions: {
playerVars: {}
}
};
function show(el) {
el.classList.remove("hide");
}
function createPlayerOptions(settings) {
function paramInOptions(opts, param) {
if (settings[param] !== undefined) {
opts[param] = settings[param];
delete settings[param];
}
return opts;
}
const optionParams = ["width", "height", "videoid", "host"];
const defaultOptions = defaults.playerOptions;
const preferred = optionParams.reduce(paramInOptions, {});
const playerOptions = Object.assign({}, defaultOptions, preferred);
// settings should now only consist of playerVars
const defaultPlayerVars = defaultOptions.playerVars;
const playerVars = Object.assign({}, defaultPlayerVars, settings);
playerOptions.playerVars = playerVars;
return playerOptions;
}
No errors doesn’t mean that it was got right. It just means there are no syntax mistakes.
Does anything need to be removed or adjusted in the code from this point on?
https://jsfiddle.net/v5up417y/
if the answer is no.
Next what I want to do is work on this part.
or is that good the way it is?
https://jsfiddle.net/1hjskb30/
Is this able to stay the way it is?
const defaults = {
playerOptions: {
playerVars: {}
}
};
Code
function addPlayer(video, settings, videoIds = video.dataset.id) {
const videoId = !Array.isArray(videoIds) && videoIds;
const playlist = Array.isArray(videoIds) && videoIds.join();
const defaults = {
playerOptions: {
events: {
"onReady": onPlayerReady,
"onStateChange": onStateChange
},
height: 600,
host: "https://www.youtube-nocookie.com",
playerVars: {
autoplay: 0,
controls: 1,
disablekb: 1,
enablejsapi: 1,
fs: 0,
iv_load_policy: 3,
playlist: playlist || undefined,
rel: 0
},
videoId,
width: 360
}
};
const defaultOptions = defaults.playerOptions;
const defaultVars = defaultOptions.playerVars;
const playerVars = settings.playerVars;
const playerOptions = Object.assign({}, defaultOptions, settings);
playerOptions.playerVars = Object.assign({}, defaultVars, playerVars);
const player = new YT.Player(video, playerOptions);
players.push(player);
return player;
}
return {
addPlayer
};
}());
const managePlayer = (function makeManagePlayer() {
const defaults = {
playerOptions: {
playerVars: {}
}
};
Yep, things are looking a lot better there now in regard to the player options.
Is doing this good?
https://jsfiddle.net/1hjskb30/
And this can stay as this?
const managePlayer = (function makeManagePlayer() {
const defaults = {
playerOptions: {
playerVars: {}
}
};
Code:
function addPlayer(video, settings, videoIds = video.dataset.id) {
const videoId = !Array.isArray(videoIds) && videoIds;
const playlist = Array.isArray(videoIds) && videoIds.join();
const defaults = {
playerOptions: {
events: {
"onReady": onPlayerReady,
"onStateChange": onStateChange
},
height: 600,
host: "https://www.youtube-nocookie.com",
playerVars: {
autoplay: 0,
controls: 1,
disablekb: 1,
enablejsapi: 1,
fs: 0,
iv_load_policy: 3,
playlist: playlist || undefined,
rel: 0
},
videoId,
width: 360
}
};
const defaultOptions = defaults.playerOptions;
const defaultVars = defaultOptions.playerVars;
const playerVars = settings.playerVars;
const playerOptions = Object.assign({}, defaultOptions, settings);
playerOptions.playerVars = Object.assign({}, defaultVars, playerVars);
const player = new YT.Player(video, playerOptions);
players.push(player);
return player;
}
return {
addPlayer
};
}());
const managePlayer = (function makeManagePlayer() {
const defaults = {
playerOptions: {
playerVars: {}
}
};
Your default settings shouldn’t be Inside of the videoPlayer code. That is not an appropriate place for the defaults. Those should be specified somewhere outside of the videoPlayer, ideally in the managePlayer code instead.
Back to how it was originally then:
https://jsfiddle.net/v5up417y/
function addPlayer(video, settings, videoIds = video.dataset.id) {
const videoId = !Array.isArray(videoIds) && videoIds;
const playlist = Array.isArray(videoIds) && videoIds.join();
const defaults = {
playerOptions: {
events: {
"onReady": onPlayerReady,
"onStateChange": onStateChange
},
host: "https://www.youtube-nocookie.com",
playerVars: {
playlist: playlist || undefined
},
videoId
}
};
const defaultOptions = defaults.playerOptions;
const defaultVars = defaultOptions.playerVars;
const playerVars = settings.playerVars;
const playerOptions = Object.assign({}, defaultOptions, settings);
playerOptions.playerVars = Object.assign({}, defaultVars, playerVars);
const player = new YT.Player(video, playerOptions);
players.push(player);
return player;
}
return {
addPlayer
};
}());
const managePlayer = (function makeManagePlayer() {
const defaults = {
playerOptions: {
height: 600,
playerVars: {
autoplay: 0,
controls: 1,
disablekb: 1,
enablejsapi: 1,
fs: 0,
iv_load_policy: 3,
rel: 0
},
width: 360
}
};
How would I get the code working using this instead, where everything is separated?
Is this hard to do?
Fixed:
https://jsfiddle.net/okzcynda/
These are the only changes I made in the code.
function addPlayer(video, settings, videoIds = video.dataset.id) {
const config = {
host: "https://www.youtube-nocookie.com",
videoId
};
config.playerVars = {
playlist: playlist || undefined
};
config.events = {
"onReady": onPlayerReady,
"onStateChange": onStateChange
};
const managePlayer = (function makeManagePlayer() {
const config = {
height: 600,
width: 360
};
config.playerVars = {
autoplay: 0,
controls: 1,
disablekb: 1,
enablejsapi: 1,
fs: 0,
iv_load_policy: 3,
};
The code set like that is able to work in a single player code:
https://jsfiddle.net/ca4ex2po/
Can it work in a multiplayer code?
The iv_load_p property looks to be messed up. Was that supposed to be iv_load_policy ?
Thanks, didn’t notice that.
Fixed: iv_load_policy: 3,
https://jsfiddle.net/okzcynda/
Are there steps involved in allowing those to be separated in the code?
Here is the code in question:
const config = {
height: 600,
width: 360
};
config.playerVars = {
autoplay: 0,
controls: 1,
disablekb: 1,
enablejsapi: 1,
fs: 0,
iv_load_policy: 3,
};
Those shouldn’t be called config. They should be called defaults instead.
You can also use the managePlayer.init() method to change any of those defaults. You could even remove all of those defaults from the managePlayer code, but would need to use managePlayer.init() to set any defaults that you want to have in place.
Everything I removed from the code
https://jsfiddle.net/cna65Lwr/
Cleaned up code: no jslint errors
https://jsfiddle.net/6ug2r7xt/3/
Did I do a good job, and can the cleaned up code be improved?
2nd Question:
When controls are set to 0 here
They can still be viewed:
https://jsfiddle.net/mg9z62qp/1/
controls: 0,
Something is not right in that code, which is set up differently.
I am not sure where I messed up there.
Can you help me figure this out, I am not sure what needs to be changed.
const defaults = {
playerOptions: {
height: 600,
playerVars: {
autoplay: 0,
controls: 0,
disablekb: 1,
enablejsapi: 1,
fs: 0,
iv_load_policy: 3,
rel: 0
},
width: 360
}
};
Is this the right spot I am supposed to be looking in?
const optionParams = ["width", "height", "videoid", "host"];
const defaultOptions = defaults.playerOptions;
const preferred = optionParams.reduce(paramInOptions, {});
const playerOptions = Object.assign({}, defaultOptions, preferred);
// settings should now only consist of playerVars
const defaultPlayerVars = defaultOptions.playerVars;
const playerVars = Object.assign({}, defaultPlayerVars, settings);
playerOptions.playerVars = playerVars;
return playerOptions;
}
There are a few issues with the cleaned up code.
The hasShuffled part of this code is an ugly hack.
let hasShuffled = false;
function onStateChange(event) {
const player = event.target;
if (!hasShuffled) {
player.setShuffle(true);
player.playVideoAt(0);
hasShuffled = true;
}
}
Not only is it an ugly hack, but it’s broken. It doesn’t shuffle anything until you start interacting with the player, at which point it likely changes the video you wanted to start, into something else.
Instead of that, the onPlayerReady event runs only once for each video, so we can easily shuffle the playlist and check autoplay to find out if we should immediately stop it or let it play. That way if autoplay is off, the visual display updates to show which video is lined up to be first.
As there are no good examples of code out there that does this, here is the code to achieve that.
function shufflePlaylist(player) {
player.setShuffle(true);
player.playVideoAt(0);
}
Then because that proper shuffle plays the video, we can check if autoplay is set, and stop the video immediately if autoplay hasn’t been set to 1. That way everything keeps working as expected.
function getPlayerOptions(player) {
return Object.values(player.i)[0];
}
function checkAutoplay(player) {
const playerOptions = getPlayerOptions(player);
if (playerOptions.playerVars.autoplay !== 1) {
player.stopVideo();
}
}
We can then use both of those in the onPlayerReady function.
function onPlayerReady(event) {
const player = event.target;
player.setVolume(100); // percent
shufflePlaylist(player);
checkAutoplay(player);
}
Are there any issues with the shuffling and autoplaying in this code? https://jsfiddle.net/bsfj2otc/1/
I am stuck on this.
I don’t know how to make adjustments to
managePlayer.init
In this code:
https://jsfiddle.net/ngpubyq9/
const managePlayer = (function makeManagePlayer() {
const defaults = {
height: 600,
width: 360
};
defaults.playerVars = {
autoplay: 0,
controls: 1,
disablekb: 1,
enablejsapi: 1,
fs: 0,
iv_load_policy: 3
};
How would I add:
This
defaults.playerVars = {
To here?
managePlayer.init({
playerVars: {
autoplay: 1
}
});
Right now, managePlayer doesn’t work.
I forgot to make adjustments to that.
I tried this:
managePlayer.init({
defaults.playerVars = {
autoplay: 1
};
});
and this:
managePlayer.init({
defaults.playerVars: {
autoplay: 1
};
});
Those did not work, or I was doing it wrong.
It looks like you’ve shot yourself in the foot by removing code from the init section.
function init() {
Object.assign(defaults);
}
An init parameter is required, ideally called playerOptions, and that needs to be added to the assign statement.
Luckily I have this to see what was removed.
https://jsfiddle.net/cna65Lwr/
I was trying to be careful.
I have controls set to on:
managePlayer.init({
playerVars: {
controls: 1
}
});
When they are on, I will know it is working.
function init() {
Object.assign(defaults.playerVars);
}
I don’t know what else needs to be added back.
https://jsfiddle.net/awnbr2j6/
I figured it out.
Changed from this:
https://jsfiddle.net/ngpubyq9/
function createPlayerOptions(settings) {
const defaultOptions = defaults;
const defaultPlayerVars = defaultOptions.playerVars;
const playerVars = Object.assign({}, defaultPlayerVars, settings);
defaults.playerVars = playerVars;
return defaults;
}
function init() {
Object.assign(defaults);
}
To this:
https://jsfiddle.net/awnbr2j6/4/
function createPlayerOptions(settings) {
const defaultOptions = defaults.playerVars;
const defaultPlayerVars = defaultOptions.playerVars;
const playerVars = Object.assign({}, defaultPlayerVars, settings);
playerVars.playerVars = playerVars;
return playerVars;
}
function init(playerVars) {
Object.assign(defaults.playerVars, playerVars);
}