Why is playVideo() not in the code?

When a playlist is being used, audio starts playing before anything is clicked.

https://jsitor.com/YVOb8ulZV

function initPlayers() {
    initPlayer.init({
        target: ".jacket-left",
        playlist: "0dgNc5S8cLI,mnfmQe8Mv1g,-Xgi_way56U,CHahce95B1g",
    });

How is that fixed?

How would you like me to stop helping?

What did I do that was wrong, I added a playlist instead of a single video?

How do I add a playlist to one of them?
https://jsitor.com/5eBjd9wgGe

Audio starts right away before anything is clicked.

How is that fixed so that doesn’t happen?

playlist: "0dgNc5S8cLI,mnfmQe8Mv1g,-Xgi_way56U,CHahce95B1g"

All I added was the playlist line into the code.

function initPlayers() {
  initPlayer.init(".jacket-left");
  initPlayer.init(".jacket-middle", {
    playlist: "0dgNc5S8cLI,mnfmQe8Mv1g,-Xgi_way56U,CHahce95B1g"
  });
  initPlayer.init(".jacket-right");
}

Original code:
https://jsitor.com/YVOb8ulZV

I just wanted to know how a playlist would be able to be used in the code.

My apologies. I said it’s ready to go, and you asked how is how is this fixed? My mistake was thinking your question was about my code update, but instead it was asking about the playlist issue.

I shall return after some rest.

1 Like

With the spinners, it’s not a good idea to have the code calling toggleSpinner embedded directly in the other code that deals with players. There is a Separation of Concerns ideal that should be applied.

Instead of having the toggleSpinner embedded in the code, we want the spinner to start when the player is a added, and to stop spinning when the player is ready.

I achieved that but ended up with awful-looking code, such as:

if (events.onPlayerAdd) {
  events.onPlayerAdd();
}

But there’s a better way. We can use events instead, which is something that JavaScript is really good at.

When we init the players I want to tell it then, that we want to toggle the spinners. An init method is just right for that sort of thing, because the toggleSpinner behaviour is going to remain consistent no matter how many players we add.

function addPlayers() {
    function toggleSpinner(evt) {
        spinner.toggleDualRing(evt.target);
    }
    player.init({
        onAddPlayer: toggleSpinner,
        onPlayerReady: toggleSpinner
    });
    player.add(".jacket-left");
    player.add(".jacket-middle", {
        start: 4
    });
    player.add(".jacket-right");
}

In the player code we create a place where the config can be easily accessed:

const player = (function makePlayer() {
    "use strict";

    const config = {};
...
    function init(initConfig) {
        Object.assign(config, initConfig);
    }
    return {
        add,
        init
    };
}());

When we add a player to a cover, that’s when we want to set up events for that cover.

    const config = {};
    const onAddPlayer = new Event("onAddPlayer");
    const onPlayerReady = new Event("onPlayerReady");
...
    function addEvents(cover) {
        cover.addEventListener("onAddPlayer", config.onAddPlayer);
        cover.addEventListener("onPlayerReady", config.onPlayerReady);
    }

    function add(coverSelector, settings = {}) {
        const cover = document.querySelector(coverSelector);
        addEvents(cover);

That way, we can easily dispatch the desired event whenever the time is right.
With the onAddPlayer event that time is at the end of the add function:

    function add(coverSelector, settings = {}) {
        ...
        cover.dispatchEvent(onAddPlayer);
    }

And with the onPlayerReady event, that time is at the end of the playerReadyCallback function:

    function playerReadyWrapper(cover, onPlayerReady) {
        return function playerReadyCallback() {
            manageCover.init(cover);
            cover.dispatchEvent(onPlayerReady);
        };
    }

The placement of the start or the end of the function is not relevant at this stage. Later on if it does become important that’s when we use more detailed events, such as beforePlayerReady and afterPlayerReady. For now though onPlayerReady does the job perfectly well for us.

Using events is a really good way to fine-tine what happens in a function, without needing to change the function itself. We can just change the configuration of the event handler outside of the function, and the different behaviour that we want is achieved.

    player.init({
        onAddPlayer: toggleSpinner,
        onPlayerReady: toggleSpinner
    });

The code is updated at https://jsitor.com/YVOb8ulZV

I’ll investigate the playlist issue next.

2 Likes

With the playlist issue, it looks as if something unexpected has happened in the videoPlayer section to the addPlayer and initPlayer code.

I was talking earlier about the need for tests. When there are tests in place, they give you early warning about when things are going wrong, giving you the opportunity to fix them up before they become a problem.

Other than manually checking to see if a video plays, do you have any ways of checking that the code is properly working? And if the code isn’t, have you any way to be informed about what the problem is?

1 Like

This is how the code worked before:
https://jsfiddle.net/heL2x7vd/

   let hasShuffled = false;

   function onPlayerStateChange(event) {
     player = event.target;
     const shufflePlaylist = true;

     if (!hasShuffled) {
       player.setShuffle(shufflePlaylist);
       player.playVideoAt(0);
       hasShuffled = true;
     }
   }

That shuffle part of the code was moved to the onPlayerReady event, because that only happens once, and you don’t need to check for shuffling on every state change of the player.

What issue do you have with tests? Do you think they aren’t needed for your code? Or is it something else?

I tested it here:

Audio starts right away before anything is clicked.

How is that fixed?

You might have to click “Run”
https://jsitor.com/yv_kmUNUcr

  function shufflePlaylist(player) {
    player.setShuffle(true);
    player.playVideoAt(0);
  }

  function onPlayerReady(event) {
    const player = event.target;
    player.setVolume(100); // percent
    shufflePlaylist(player);
  }

  function onPlayerStateChange(event) {
    player = event.target;
  }

Adding a pauseVideo in the shuffle command helps to alleviate that.

    player.setShuffle(true);
      player.playVideoAt(0);
      player.pauseVideo();
  }

The pause is needed there because we are using playVideoAt to reset to the first video in the newly shuffled list.

1 Like

It’s fixed in the 3 player code now.
https://jsitor.com/1xqkXKIrsv

On the single player code, onPlayerStateChange can be removed from the code.

Which is an improvement because it is code that is no longer needed or being used.

https://jsitor.com/yv_kmUNUcr

const videoPlayer = (function makeVideoPlayer() {
  "use strict";

  let player = null;

  const tag = document.createElement("script");
  tag.src = "https://www.youtube.com/iframe_api";
  const firstScriptTag = document.getElementsByTagName("script")[0];
  firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

  function shufflePlaylist(player) {
    player.setShuffle(true);
    player.playVideoAt(0);
    player.pauseVideo();
  }

  function onPlayerReady(event) {
    const player = event.target;
    player.setVolume(100); // percent
    shufflePlaylist(player);
  }

  function addPlayer(video) {

    const playlist = "0dgNc5S8cLI,mnfmQe8Mv1g,-Xgi_way56U,CHahce95B1g";
    const config = {
      height: 360,
      host: "https://www.youtube-nocookie.com",
      width: 640
    };
    config.playerVars = {
      autoplay: 0,
      cc_load_policy: 0,
      controls: 1,
      disablekb: 1,
      fs: 0,
      iv_load_policy: 3,
      loop: 1,
      playlist,
      rel: 0
    };
    config.events = {
      "onReady": onPlayerReady
    };
    player = new YT.Player(video, config);

  }

But what if the aim is to have only one set of code that can work in all situations? Then you are not improving things but are creating another divergence instead.

If it is only being used with a single player, what situation would call for onPlayerStateChange to be needed?

I think that we have learned that you and me have different objectives.
You seem to want different code that must change for every different type of situation
Whereas I want one set of code that doesn’t need to change for different situations.

Wouldn’t something only be added to code if the situation calls for it, and if something is not being used, it can be left out.

It’s best for code to be generic enough so that it can handle a wide variety of situations. That is why we pass parameters to functions, so that the functions don’t need to be rewritten when we need something different done.

That is also why code libraries are configurable from the outside, so that we don’t have to go in and change things internally.

2 Likes

Does new RandomNumber only work with onPlayerStateChange?

Meaning, it’s not meant to or supposed to work with onPlayerReady.

function newRandomNumber(min, max) {
    return Math.floor(Math.random() * max) + min;
  }

works here
https://jsitor.com/hi-kYiM7DA

  function onPlayerStateChange(event) {
    player = event.target;
    player.setShuffle(true);
  }
  function newRandomNumber(min, max) {
    return Math.floor(Math.random() * max) + min;
  }

Doesn’t work here:
https://jsitor.com/E8JILS8mzZ

  function shufflePlaylist(player) {
    player.setShuffle(true);
    player.playVideoAt(0);
    player.pauseVideo();
  }

  function onPlayerReady(event) {
    const player = event.target;
    player.setVolume(100);
    shufflePlaylist(player);
  }

  function newRandomNumber(min, max) {
    return Math.floor(Math.random() * max) + min;
  }