What is the purpose of the load function?

In here?

From this:

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

to this?

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

What’s the difference between the 2?

The code works with either one.

The difference is that back in 2012 Google renamed it to iframe_api
The player_api works for now, but there’s no guarantee that it will continue to work into the future.

1 Like

Also, onYouTubeIframeAPIReady is preferred to be used instead of onYouTubePlayerAPIReady

Both will work for now, but the Iframe one is the more reliable one to use.

1 Like

Can’t function names be called anything?

Change this:
https://jsfiddle.net/p6qLh5nv/

  function addVideo(video) {
    new YT.Player(video, {


  function init(opts) {
    addVideo(opts.video);
  }
  return {
    init
  };
}());

to

This?
https://jsfiddle.net/tveuLsk4/1/

  function onYouTubeIframeAPIReady(video) {
    new YT.Player(video, {


  function init(opts) {
    onYouTubeIframeAPIReady(opts.video);
  }
  return {
    init
  };
}());

Can you clarify what you mean by this?

I shared an example above here.

Is that what you meant?

Yes. If you go to the API reference page at https://developers.google.com/youtube/iframe_api_reference and search for player_api. you will see that it’s been updated to be iframe_api

Also, if you search for playerapi on the API reference page you will see that refer to a requirements section near the top of the page where it says that the API will call onYouTubeIframeAPIReady when the page has finished downloading.

The way that you’ve done it at https://jsfiddle.net/tveuLsk4/1/ is not correct, as if someone is fast, it’s possible to click the cover before the file has finished downloading.

The onYouTubeIframeAPIReady function must be a global function, so that the google API can run that function once the iframe code has been downloaded.

I’ll work through how that impacts the code shortly.

2 Likes

How would I change it, what would I change it to?

Doing things more properly according to Google means making several changes.

The good news is that the following code needs to run immediately when the page loads:

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

That is correctly being done at the start of the videoPlayer IIFE (immediately invoked function expression).

The onYouTubeIframeAPIReady function though is not for us to run in the code. That needs to be globally accessible (outside of any other functions) so that the API can automatically run that function when the API is ready.

I’m going to rename what you have there to addPlayer and make that available from the videoPlayer code. I am also setting autoplay to 0, so that it doesn’t start playing as soon as the iframe is created. I’ll add code to play the video afterwards.

  // function onYouTubeIframeAPIReady(video) {
  function addPlayer(video) {
    const playlist = "0dgNc5S8cLI,mnfmQe8Mv1g,-Xgi_way56U,CHahce95B1g";
    new YT.Player(video, {
...
      playerVars: {
        // autoplay: 1,
        autoplay: 0,
...
  // function init(opts) {
  //   onYouTubeIframeAPIReady(opts.video);
  // }
  return {
    addPlayer
  };
}());

and below that, we’ll have a globally accessible function called onYouTubeIframeAPIReady

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

The wrapper is not yet available. We can’t pass config information to the onYouTubeIframeAPIReady function, so we’ll get that config information from else where.

Where is a good place for config information? At the top of the code of course.

const cover = document.querySelector(".jacket");
...
  // const cover = document.querySelector(".jacket");
  cover.addEventListener("click", coverClickHandler);

We can now refer to that cover from within the onYouTubeIframeAPIReady function too:

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

When the player is ready, the onPlayerReady function is run:

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

We want to later on play the video when someone clicks on the cover. It is from that onPlayerReady function that we save aside a reference to the player.

const videoPlayer = (function makeVideoPlayer() {
  "use strict";
  let player = null;
...
  function onPlayerReady(event) {
    // const player = event.target;
    player = event.target;
    player.setVolume(100); // percent
  }

That way, when the cover is clicked, we can have the videoPlayer code play the video.

  function play() {
    player.playVideo();
  }
  return {
    addPlayer,
    play
  };
}());

Lastly, we remove the initPlayer code because the different videoPlayer.play code is being used instead.

  // function initPlayer(wrapper) {
  //   videoPlayer.init({
  //     video: wrapper.querySelector(".video")
  //   });
  // }

  function coverClickHandler(evt) {
    const wrapper = evt.currentTarget.nextElementSibling;
    show(wrapper);
    // initPlayer(wrapper);
    videoPlayer.play();
  }

The way it all works is that the iframe_api is loaded as soon as possible, which when loaded creates the iframe as soon as possible. The video is ready and waiting, but not playing.
Later on when we click the cover, the video starts playing.

The updated code is at https://jsfiddle.net/71y52qa8/

2 Likes

What about the codes that use js.load

Those are fine?

https://jsfiddle.net/f26o57kt/2/

const load = (function() {
  "use strict";

  function _load(tag) {
    return function(url) {
      return new Promise(function(resolve) {
        const element = document.createElement(tag);
        const parent = "body";
        const attr = "src";
        element.onload = function() {
          resolve(url);
        };
        element[attr] = url;
        document[parent].appendChild(element);
      });
    };
  }
  return {
    js: _load("script")
  };
}());
(function manageCover() {
  "use strict";

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

  function coverClickHandler(evt) {
    const cover = evt.currentTarget;
    hide(cover);
  }
  const cover = document.querySelector(".jacket");
  cover.addEventListener("click", coverClickHandler);
}());
const videoPlayer = (function makeVideoPlayer() {
  "use strict";

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

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

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

  function addVideo(video) {

    const playlist = "0dgNc5S8cLI,mnfmQe8Mv1g,-Xgi_way56U,CHahce95B1g";

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

  function init(opts) {
    load.js("https://www.youtube.com/player_api").then(function() {
      YT.ready(function() {
        addVideo(opts.video);
      });
    });
  }
  return {
    init
  };
}());

The load code is completely unwanted. The iframe_api takes care of that all by itself.

This is needed though.

const load = (function() {
  "use strict";

  function _load(tag) {
    return function(url) {
      return new Promise(function(resolve) {
        const element = document.createElement(tag);
        const parent = "body";
        const attr = "src";
        element.onload = function() {
          resolve(url);
        };
        element[attr] = url;
        document[parent].appendChild(element);
      });
    };
  }
  return {
    js: _load("script")
  };
}());

Why do you think that it is needed? The youtube API takes care of all of that.

It prevents the youtube api from being caught in the browser until it has loaded.

That is also what the onYouTubeIframeAPIReady function achieves.

The load code is a useless complication. It’s better to do things the way that YouTube instructs in their API documentation.

Oh, and no it doesn’t prevent the youtube api from being caught in the browser. When testing on local pages where things happen fast, that problem can still occur.

The load code does not protect from that.

Use onYouTubeIframeAPIReady and that problem no longer exists.

This would be for when no cover is used.
https://jsfiddle.net/78ndxtm3/2/


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

  let player

  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 onPlayerReady(event) {
    const player = event.target;
    player.setVolume(100); // percent
  }
  let hasShuffled = false;

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

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

  function addPlayer(video) {
    const playlist = "0dgNc5S8cLI,mnfmQe8Mv1g,-Xgi_way56U,CHahce95B1g";
    new YT.Player(video, {

      width: 640,
      height: 360,
      host: "https://www.youtube-nocookie.com",
      playerVars: {
        autoplay: 1,
        controls: 1,
        loop: 1,
        rel: 0,
        iv_load_policy: 3,
        cc_load_policy: 0,
        fs: 0,
        disablekb: 1,
        playlist
      },
      events: {
        "onReady": onPlayerReady,
        "onStateChange": onPlayerStateChange
      }
    });
  }

  function play() {
    player.playVideo();
  }
  return {
    addPlayer,
    play
  };
}());

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

Let’s look back at the code changes I posted at post #34

All is good until we get down to the addPlayer part. We need to be able to access the addPlayer function, and have the onYouTubeIframeAPIReady use that addPlayer function.

First, provide access to the addPlayer function, removing the init code too while we’re at it because it’s not used anymore:

  // function init(opts) {
  //   addPlayer(opts.video);
  // }
  return {
    // init
    addPlayer
  };
}());

Then we replace the videoPlayer.init code with the onYouTubeIframeAPIReady

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

That’s it. https://jsfiddle.net/1codzwb4/

1 Like

52 posts were split to a new topic: Why does autoplay start playing the video?