Setting up single-player tests before adding spinner

There are 2 things I want to do.

One is add a spinner to the code.

/* Spinner */
.lds-dual-ring:after {
  content: " ";
  display: block;
  width: 64px;
  height: 64px;
  margin: auto;
  border-radius: 50%;
  border: 6px solid #fff;
  border-color: #fff transparent #fff transparent;
  animation: lds-dual-ring 1.2s linear infinite;
  opacity: 0.5;
}
@keyframes lds-dual-ring {
  0% {
    transform: rotate(0deg);
  }
  100% {
    transform: rotate(360deg);
  }
}
    function toggleSpinner(cover) {
        cover.classList.toggle("lds-dual-ring");
    }

Another is, doing something about this:

I read this from you:

I now have a different approach that is more stable and works no matter whether it is j or h or anything else.

I have this code written 2 different ways.

Both codes don’t have any errors in them.

One way: I figured out this way just now.

https://jsfiddle.net/1bow0y8x/1/

 function getIframe(player) {
    return player.h;
  }

  function onPlayerReady(event) {
    const iframe = getIframe(player);
    iframe.dispatchEvent(events.afterPlayerReady);
  }

    const iframe = getIframe(player);
    const eventHandler = eventHandlers.afterPlayerReady;
    iframe.addEventListener("afterPlayerReady", eventHandler);
  }

Another way: https://jsfiddle.net/2vs7d95g/

 function onPlayerReady(event) {
    const iframe = player.h;
    iframe.dispatchEvent(events.afterPlayerReady);
  }

    const iframe = player.h;
    const eventHandler = eventHandlers.afterPlayerReady;
    iframe.addEventListener("afterPlayerReady", eventHandler);
  }

What would that other approach look like?

We can work on this one 1st, then adding the spinner after.

I remember with a different set of code, player.b.b was being used, then a different approach was found.

This: // const playerVars = player.b.b.playerVars;

Was replaced with this: if (playerVars.loop && event.data === YT.PlayerState.ENDED)

Continuing the discussion from Why is playVideo() not in the code?:

3 Likes

Before I touch any more of your code I will need tests for the existing code that’s going to be touched, where the proper technique of adding a test for a new desired feature is done before adding that feature.

If you aren’t going to come up with the tests, then it will take some time for me to put them together before touching any of the code.

3 Likes

The tests that you did do using jsitor, every single one of them are gone.

It turns out, codes don’t stay saved inside jsitor.

This code here I believe I put together from this post.

https://jsfiddle.net/2vs7d95g/

 function onPlayerReady(event) {
    const iframe = player.h;
    iframe.dispatchEvent(events.afterPlayerReady);
  }

    const iframe = player.h;
    const eventHandler = eventHandlers.afterPlayerReady;
    iframe.addEventListener("afterPlayerReady", eventHandler);
  }

The code that I put together using this: https://jsfiddle.net/1bow0y8x/1/

 function getIframe(player) {
    return player.h;
  }

That was this post:

I think those 2 codes I made, which are nearly identical, I used the instructions from the single player code examples, which is what is being used in this post, a single video code.

1 Like

There’s nothing wrong with the code working, it’s working as it is supposed to as I understand it.

Because I was not able to see your jsitor examples, I had to follow the instructions to put together the code.

I looked for a code where this was done to a single video code, and those were the instructions I followed here.

This one: post #175

Which I used to make this: https://jsfiddle.net/o17mzajg/

Where the autoplay feature / or player.playVideo();

That I test in here: https://jsitor.com/A2BSNvuBw

But, if I am using that, I now need to provide a link from both the jsfiddle, and jsitor.

So that, the jsfiddle link is used as a backup for when the jsitor code becomes no-longer visible.

In the code there I made the left curtain panel transparent so that we can see the video appear after the button is clicked.

The only difference between that code in the instructions and the one in this post is that, an array is not being used here.

After I did that, I had seen this comment from you.

In the meantime my earlier concerns about the i.j from player.i.j.playerVars in post #78 being a problem occurred. Youtube changed it to i.h instead. I now have a different approach that is more stable and works no matter whether it is j or h or anything else.

In the code I put together player.h is used.

const iframe = player.h;
    iframe.dispatchEvent(events.afterPlayerReady);

    const iframe = player.h;
    const eventHandler = eventHandlers.afterPlayerReady;
    iframe.addEventListener("afterPlayerReady", eventHandler);
  }

I wanted to see if there was a different approach to that.

After that I wanted to add a spinner to it.

Which I found instructions for here: post #96

But those would need to be changed a little because a single video code was not being used there.

1 Like

I was reading instructions here:

With this code here:

  function onYouTubeIframeAPIReady() {
    const cover = document.querySelector(".play");
    const wrapper = cover.parentElement;
    const frameContainer = wrapper.querySelector(".video");
    videoPlayer.addPlayer(frameContainer);
  }

I was able to get down to this: https://jsfiddle.net/s7w2cyqf/

  function onYouTubeIframeAPIReady() {
    const frameContainer = document.querySelector(".video");
    videoPlayer.addPlayer(frameContainer);
  }

But in those instructions,

I saw it can be changed to this:

  function onYouTubeIframeAPIReady() {
    videoPlayer.onIframeReady();
  }

Is that a change I would want to make in the code?

I couldn’t get it to work.

It’s probably fine the way it was, that was just something I had seen.

Changing that may force me to make a lot of other changes to the code which may not be necessary. So, maybe I will just leave it for now.

Aside from that, I’m not really sure if anything can be done about:

the player.h being in the code, and if it can be removed and replaced with something else.

const iframe = player.h;

Also, I don’t quite understand what the h represents.

What is its meaning?

After that, just adding the spinner which may be the easiest thing.

I think these are some of the instructions on adding the spinner

I’m not really sure.

I think that may go to the multi player code, not a single player code.

  addPlayer.init({
        afterAddPlayer: function (evt) {
            toggleSpinner(evt);
        },
        afterPlayerReady: function (evt) {
            toggleSpinner(evt);
            const cover = evt.detail.cover;
            manageCover.init(cover, showVideo);
        }
    });.

Adding the spinner to this: https://jsfiddle.net/o17mzajg/

I am not sure how that is done.

function play() {
    player.playVideo();
  }

  function addEvents(handlers) {
    eventHandlers.afterPlayerReady = handlers.afterPlayerReady;
    events.afterPlayerReady = new Event("afterPlayerReady");
  }

  function init(initEventHandlers) {
    addEvents(initEventHandlers);
    loadIframeScript();
    window.onYouTubeIframeAPIReady = onYouTubeIframeAPIReady;
  }

  return {
    addPlayer,
    init,
    play
  };
}());

videoPlayer.init({
  afterPlayerReady: function initCover() {
    manageCover.init(function playVideo() {
      videoPlayer.play();
    });
  }
});
1 Like

Why don’t you just take some time to learn JavaScript. Outside this context which you waste countless hours. Copy and pasting code which you don’t understand. How much time has been taken to teach you JavaScript. No progress. It’s just ten million line of someone hand feeding you everything. This should be a place of learning. Not spoon feeding people who could care less about programming beyond their selfishness sh needs to achieve a specific business goal. If this is the future of learning we are all doomed.

4 Likes

Is there an alternative approach than using player.h?

const iframe = player.h; https://jsfiddle.net/o17mzajg/

How is that found out?

What does h mean, does it have a specific meaning?

1 Like

I was trying different things and found this that works.

Instead of using this: const iframe = player.h;

I can do this: https://jsfiddle.net/q2v5hew4/

Is this good?

    const iframe = document.querySelector("iframe");
    iframe.dispatchEvent(events.afterPlayerReady);
  }
    const iframe = document.querySelector("iframe");
    const eventHandler = eventHandlers.afterPlayerReady;
    iframe.addEventListener("afterPlayerReady", eventHandler);
  }

Improving on that I can then do this: https://jsfiddle.net/z1kywacL/

 function getIframe() {
    return document.querySelector("iframe");
  }

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

  function onPlayerReady(event) {
    player = event.target;
    player.setVolume(100);
    shufflePlaylist(player);
    const iframe = getIframe();
    iframe.dispatchEvent(events.afterPlayerReady);
  }

  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);

    const iframe = getIframe();
    const eventHandler = eventHandlers.afterPlayerReady;
    iframe.addEventListener("afterPlayerReady", eventHandler);
  }

If that was good, next I can try to add the spinner in.

The spinner code would be added to this I think.

This seems difficult for me to understand how it is done.

videoPlayer.init({
  afterPlayerReady: function initCover() {
    manageCover.init(function playVideo() {
      videoPlayer.play();
    });
  }
});

Spinner Instructions: I found these that were done.

I do not understand how to do any of this:

And it may need to be changed a bit because I am only doing this to a single video, so some of, or all would need to be changed.

Because this spinner code was written many different ways I am seeing.

I do not know, or can’t comprehend how it would be added to a single video code .

function toggleSpinner(evt) {
        spinner.toggleDualRing(evt.target);
    }

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

  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);

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

I do know that the spinner code was used in these 3 topic threads:

Topic 1

Topic 2

Topic 3

Post #102

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.

And that doubt is exactly why tests are required. Not only do they confirm that the code works as we intend it to work, it also ensures that we are notified immediately when any future changes break that expected behaviour.

I don’t have a problem with tests.

As I understand it meaning, when I click on it right away, it does not open, which is the intended behavior.

1 quick thing before we begin with tests.

Which version of the code should we do the tests on?

All 3 of these work as they are intended to, and both work the same way.

In the jsfiddle links it can be seen that clicking on the play button right away, the player does not open. So that tells you it is working as it is intended to.

Here is me clicking on the play button right away and nothing happening.

To reproduce, click run, then the play button really fast.

So, the next thing would be adding the spinner?

Put the spinner in, then proceed to do tests to make sure it is working as it should?

Does it make sense to do tests on a code that is already working, where there are no issues?

Would it be better to add the spinner in, then do tests on that to make sure it is working how it should?

Code 1 https://jsfiddle.net/z1kywacL/

In referring to a different code I remember you saying this:

One way is to add a body variable to the init function. That does though result in us having a body variable in two places, one in resetPage, and one in init. That doesn’t become a problem until we have three such duplicates in the one module. If that occurs we can then move one of them up to a higher level, such as to the top of the module, and use that single body variable from all other places instead.

There are not 3 or more duplicates here so maybe using this code may not be beneficial.

function getIframe() {
    return document.querySelector("iframe");
  }

  function onPlayerReady(event) {
    const iframe = getIframe();
    iframe.dispatchEvent(events.afterPlayerReady);
  }

    const iframe = getIframe();
    const eventHandler = eventHandlers.afterPlayerReady;
    iframe.addEventListener("afterPlayerReady", eventHandler);
  }

Code 2 https://jsfiddle.net/f7yjx8nL/

I believe player.h;

Is the same as: doing: document.querySelector("iframe");

So, this would be a different way of writing it.

function onPlayerReady(event) {
    const iframe = document.querySelector("iframe");
    iframe.dispatchEvent(events.afterPlayerReady);
  }

    const iframe = document.querySelector("iframe");
    const eventHandler = eventHandlers.afterPlayerReady;
    iframe.addEventListener("afterPlayerReady", eventHandler);
  }

Code 3 https://jsfiddle.net/f7yjx8nL/2/

The instructions I followed used player.h

function onPlayerReady(event) {
    const iframe = player.h;
    iframe.dispatchEvent(events.afterPlayerReady);
  }

    const iframe = player.h;
    const eventHandler = eventHandlers.afterPlayerReady;
    iframe.addEventListener("afterPlayerReady", eventHandler);
  }

These were the instructions I followed to build the code: post #175

The only thing missing from the code is the spinner, which was not added to those particular instructions.

The question is usually the opposite: “Is it worth touching code that has no tests?” for which the answer is a resounding no.

Untested code really needs to have tests, especially before changing that code any further.

How do you want me to add tests to it?

I believe these were the tests that were already done on that set of code.

Adding tests to the video player code

Will the tests I be doing be different from those?

Can that be used as a guide, or as a frame of reference?

Also, how many tests are being done?

Also, what exactly is being tested?

What is already known is that,

In the code we disable clicking the play button, until the player is loaded and ready.

That’s what the code does, and how it works.

What is left is adding in the spinner, which I don’t have the proper instructions on how to implement that.

I believe it was only added to a multi player code, not a single player code. post #102

Yes, those tests were for the manageCover code.

We have recently been updating the tests for manageCover code in the other thread called Adding tests to video player code

Completing those tests are the best way forward.

It’s not the best way forward because I am taking a break from that code.

This code: https://jsfiddle.net/gqjaoykp/

I made following these instructions: post #175

The javascript in this code is completely different from the other code.

In the code here we disable clicking the play button, until the player is loaded and ready.

That is not in the other code I am taking a break from.

Also, all I am doing to this code is adding a spinner to it.

const manageCover = (function makeManageCover() {
  const events = {};

  function show(el) {
    el.classList.remove("hide");
  }

  function hide(el) {
    el.classList.add("hide");
  }

  function openCurtain(cover) {
    hide(cover);
    const curtain = document.querySelector(".curtain");
    curtain.classList.add("slide");
    return curtain;
  }

  function showVideo(curtain) {
    const thewrap = curtain.parentElement.querySelector(".wrap");
    show(thewrap);
  }

  function coverClickHandler(evt) {
    const cover = evt.currentTarget;
    const curtain = openCurtain(cover);
    showVideo(curtain);
    cover.dispatchEvent(events.afterClickCover);
  }

  function init(callback) {
    const cover = document.querySelector(".play");
    cover.addEventListener("click", coverClickHandler);
    events.afterClickCover = new Event("afterClickCover");
    cover.addEventListener("afterClickCover", callback);
  }

  return {
    init
  };
}());

const videoPlayer = (function makeVideoPlayer() {
  const events = {};
  const eventHandlers = {};
  let player = null;


  function loadIframeScript() {
    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 onYouTubeIframeAPIReady() {
    const cover = document.querySelector(".play");
    const wrapper = cover.parentElement;
    const frameContainer = wrapper.querySelector(".video");
    videoPlayer.addPlayer(frameContainer);
  }

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

  function onPlayerReady(event) {
    player = event.target;
    player.setVolume(100);
    shufflePlaylist(player);
    const iframe = player.h;
    iframe.dispatchEvent(events.afterPlayerReady);
  }

  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);

    const iframe = player.h;
    const eventHandler = eventHandlers.afterPlayerReady;
    iframe.addEventListener("afterPlayerReady", eventHandler);
  }

  function play() {
    player.playVideo();
  }

  function addEvents(handlers) {
    eventHandlers.afterPlayerReady = handlers.afterPlayerReady;
    events.afterPlayerReady = new Event("afterPlayerReady");
  }

  function init(initEventHandlers) {
    addEvents(initEventHandlers);
    loadIframeScript();
    window.onYouTubeIframeAPIReady = onYouTubeIframeAPIReady;
  }

  return {
    addPlayer,
    init,
    play
  };
}());

videoPlayer.init({
  afterPlayerReady: function initCover() {
    manageCover.init(function playVideo() {
      videoPlayer.play();
    });
  }
});

We are soon going to have three completely different sets of tests and code for the one project. That way lies madness.

1 Like

This post may need to be moved out into a new topic, maybe called:

Setting up tests to prepare to add spinner to single player code.

How many tests would be needed to be made to prepare to add the spinner in for this single video code?

This code is using only 1 video, not multiple, where the javascript is set up differently, where there is no animation stuff inside the javascript.

I was able to do this: https://jsfiddle.net/edqkb3pg/

To be able to see the tests on the screen I did this:

.container {
  display: none;
}

Do I need to change any of the resources in here?

i.e., Do I need to remove any, add different ones?

jasmine.css
jasmine.min.js
jasmine-html.min.js
boot0.min.js
boot1.min.js

I don’t exactly know what is being tested because, what gets tested to then be able to add a spinner to it?

We know what the code does, and it does what it is supposed to do.

We disable clicking the play button, until the player is loaded and ready.

Instructions for the single player code that were followed: post #175

Where the play button is disabled, that’s where the spinner should be seen.

/* Spinner */
.lds-dual-ring:after {
  content: " ";
  display: block;
  width: 64px;
  height: 64px;
  margin: auto;
  border-radius: 50%;
  border: 6px solid #fff;
  border-color: #fff transparent #fff transparent;
  animation: lds-dual-ring 1.2s linear infinite;
  opacity: 0.5;
}
@keyframes lds-dual-ring {
  0% {
    transform: rotate(0deg);
  }
  100% {
    transform: rotate(360deg);
  }
}
 function toggleSpinner(cover) {
    cover.classList.toggle("lds-dual-ring");
  }

I first toggle the spinner when we init the cover:

    const cover = document.querySelector(opts.target);
    toggleSpinner(cover);
    const videoWrapper = cover.nextElementSibling;
    initPlayer(videoWrapper, onPlayerReady);

And toggle the spinner again, thus turning it off, when the player is ready.

    function onPlayerReady() {
        const coverSelector = opts.target;
        manageCover.init(coverSelector);
        const cover = document.querySelector(coverSelector);
        toggleSpinner(cover);
        cover.addEventListener("click", coverClickHandler);
    }

As soon as a video has loaded which only takes a second, the spinner goes away and you can click on the cover to start playing.

Which were part of the instructions here: post #96

But those instructions went with the multi player code, not a single player code.

Also, those may not be the correct instructions:

In post #102

You say this: Where new instructions are given.

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.

Still, that was done to the multi player code.

In the single player code it would be written differently.

I think that the spinner idea was not thought of until later on, so that would be why it was not added to the single player code at the time.

Would there be a way to come up with, or modify existing instructions for how to add the spinner to the single player code to see if there are any issues?

I found some code to test the spinner here: post #122

describe("Spinner", function () {
    const div = document.createElement("div");
    it("toggles on when the classname doesn't exist", function () {
        div.classList.remove("lds-dual-ring");
        spinner.toggleDualRing(div);
        expect(div.classList.contains("lds-dual-ring")).to.equal(true);
    });
    it("toggles off when the classname already exists", function () {
        div.classList.add("lds-dual-ring");
        spinner.toggleDualRing(div);
        expect(div.classList.contains("lds-dual-ring")).to.equal(false);
    });
});

Looking at this piece of instruction: post #26

   addPlayer.init({
        afterAddPlayer: function (evt) {
            toggleSpinner(evt);
        },
        afterPlayerReady: function (evt) {
            toggleSpinner(evt);
            const cover = evt.detail.cover;
            manageCover.init(cover, showVideo);
        }
    });

It looks that that would be added to this somehow:

Just because it looks similar, but I have no idea.

videoPlayer.init({
  afterPlayerReady: function initCover() {
    manageCover.init(function playVideo() {
      videoPlayer.play();
    });
  }
});

I didn’t realize it would be this complicated to figure out how to add a spinner to the code. For me it seems difficult to understand how it would be done.

Because the spinner happens on the cover, at minimum the manageCover code needs to be fully tested, as well as anything else that the spinner may affect.

But you’ve announced that you are taking a break from tests on the manageCover code.

The multiplayer code, not the single player code that looks nothing like the multiplayer code.

The spinner is being added to the single video code. https://jsfiddle.net/gqjaoykp/

How do I add tests to this?

How would that be set up?

I started the process of adding tests here: https://jsfiddle.net/edqkb3pg/

What tests will be done to it?

How do I get the process started?

const manageCover = (function makeManageCover() {
  const events = {};

  function show(el) {
    el.classList.remove("hide");
  }

  function hide(el) {
    el.classList.add("hide");
  }

  function openCurtain(cover) {
    hide(cover);
    const curtain = document.querySelector(".curtain");
    curtain.classList.add("slide");
    return curtain;
  }

  function showVideo(curtain) {
    const thewrap = curtain.parentElement.querySelector(".wrap");
    show(thewrap);
  }

  function coverClickHandler(evt) {
    const cover = evt.currentTarget;
    const curtain = openCurtain(cover);
    showVideo(curtain);
    cover.dispatchEvent(events.afterClickCover);
  }

  function init(callback) {
    const cover = document.querySelector(".play");
    cover.addEventListener("click", coverClickHandler);
    events.afterClickCover = new Event("afterClickCover");
    cover.addEventListener("afterClickCover", callback);
  }

  return {
    init
  };
}());

const videoPlayer = (function makeVideoPlayer() {
  const events = {};
  const eventHandlers = {};
  let player = null;


  function loadIframeScript() {
    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 onYouTubeIframeAPIReady() {
    const cover = document.querySelector(".play");
    const wrapper = cover.parentElement;
    const frameContainer = wrapper.querySelector(".video");
    videoPlayer.addPlayer(frameContainer);
  }

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

  function onPlayerReady(event) {
    player = event.target;
    player.setVolume(100);
    shufflePlaylist(player);
    const iframe = player.h;
    iframe.dispatchEvent(events.afterPlayerReady);
  }

  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);

    const iframe = player.h;
    const eventHandler = eventHandlers.afterPlayerReady;
    iframe.addEventListener("afterPlayerReady", eventHandler);
  }

  function play() {
    player.playVideo();
  }

  function addEvents(handlers) {
    eventHandlers.afterPlayerReady = handlers.afterPlayerReady;
    events.afterPlayerReady = new Event("afterPlayerReady");
  }

  function init(initEventHandlers) {
    addEvents(initEventHandlers);
    loadIframeScript();
    window.onYouTubeIframeAPIReady = onYouTubeIframeAPIReady;
  }

  return {
    addPlayer,
    init,
    play
  };
}());

videoPlayer.init({
  afterPlayerReady: function initCover() {
    manageCover.init(function playVideo() {
      videoPlayer.play();
    });
  }
});