Questions about the YouTube player_api code


#61

No, as there’s a lot of code that uses that loadPlayer function.

The videoPlayera function though, that needs to be deleted.


#62

https://jsfiddle.net/hzyrfkwb/367/

Top:

function loadPlayer(containerSelector) {
    "use strict";
    const show = (el) => el.classList.remove("hide");


    function coverClickHandler(evt) {
        const wrapper = evt.currentTarget.nextElementSibling;
        show(wrapper);
    }
    
    const cover = document.querySelector(containerSelector);
    cover.addEventListener("click", coverClickHandler);  
}

Bottom:


function loadPlayer(containerSelector, playerVars) {
    "use strict";
    const show = (el) => el.classList.remove("hide");

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

    function coverClickHandler(evt) {
        const wrapper = evt.currentTarget.nextElementSibling;
        show(wrapper);
        initPlayer(wrapper);
    }
          
    const cover = document.querySelector(containerSelector);
    cover.addEventListener("click", coverClickHandler);
}

#63

The videoPlayera function still needs to be deleted, and the first loadPlayer function too.


#64

We need to back track to this point:
https://jsfiddle.net/hzyrfkwb/370/

This has to control player One:

I’m not using 1, to control both of them:


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

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

    function onPlayerStateChange(event) {
        const player = event.target;
        const playerVars = player.b.b.playerVars;
        if (playerVars.loop && event.data === YT.PlayerState.ENDED) {
            player.seekTo(playerVars.start);
        }
    }

    function addVideo(video) {
        const videoId = video.getAttribute("data-id");
        new YT.Player(video, {
            width: 606,
            height: 344,
            videoId: videoId,
            playerVars: {
                autoplay: 1,
                controls: 1,
                showinfo: 1,
                rel: 0,
                iv_load_policy: 3,
                cc_load_policy: 0,
                fs: 0,
                disablekb: 1,
                loop: true,
                start: 1,
                end: 204
            },
            events: {
                "onReady": onPlayerReady,
                "onStateChange": onPlayerStateChange
            }
        });
    }

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

(function iife() {
    "use strict";
    const show = (el) => el.classList.remove("hide");

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

    function coverClickHandler(evt) {
        const wrapper = evt.currentTarget.nextElementSibling;
        show(wrapper);
        initPlayer(wrapper);
    }
    
    const cover = document.querySelector(".jacketc");
    cover.addEventListener("click", coverClickHandler);
}());

#65

Why is that duplication needed?


#66

I wanted to keep them separate for now.

I started to see that one was starting to control both of them.

Here they are controlled separately:
https://jsfiddle.net/hzyrfkwb/371/


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

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

    function onPlayerStateChange(event) {
        const player = event.target;
        const playerVars = player.b.b.playerVars;
        if (playerVars.loop && event.data === YT.PlayerState.ENDED) {
            player.seekTo(playerVars.start);
        }
    }

    function addVideo(video) {
        const videoId = video.getAttribute("data-id");
        new YT.Player(video, {
            width: 606,
            height: 344,
            videoId: videoId,
            playerVars: {
                autoplay: 1,
                controls: 1,
                showinfo: 1,
                rel: 0,
                iv_load_policy: 3,
                cc_load_policy: 0,
                fs: 0,
                disablekb: 1,
                loop: true,
                start: 201,
                end: 204
            },
            events: {
                "onReady": onPlayerReady,
                "onStateChange": onPlayerStateChange
            }
        });
    }

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

(function iife() {
    "use strict";
    const show = (el) => el.classList.remove("hide");

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

    function coverClickHandler(evt) {
        const wrapper = evt.currentTarget.nextElementSibling;
        show(wrapper);
        initPlayer(wrapper);
    }
    
    const cover = document.querySelector(".jacketc");
    cover.addEventListener("click", coverClickHandler);
}());
const videoPlayer = (function makeVideoPlayer() {
    "use strict";
    const players = [];

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

    function onPlayerStateChange(event) {
        const player = event.target;
        if (event.data === YT.PlayerState.PLAYING) {
            const otherVideos = (video) => video !== player;
            const pauseVideo = (video) => video.pauseVideo();
            players.filter(otherVideos).forEach(pauseVideo);
        }
        const playerVars = player.b.b.playerVars;
        if (playerVars.loop && event.data === YT.PlayerState.ENDED) {
            player.seekTo(playerVars.start);
        }
    }

    function addVideo(video, desiredPlayerVars) {
        const videoId = video.getAttribute("data-id");
        const defaultPlayerVars = {
            autoplay: 1,
            controls: 1,
            showinfo: 1,
            rel: 0,
            iv_load_policy: 3,
            cc_load_policy: 0,
            fs: 0,
            disablekb: 1
        };
        const playerVars = Object.assign(defaultPlayerVars, desiredPlayerVars);
        players.push(new YT.Player(video, {
            width: 200,
            height: 200,
            videoId: videoId,
            playerVars,
            events: {
                "onReady": onPlayerReady,
                "onStateChange": onPlayerStateChange
            }
        }));
    }

     function init(opts) {
        var playerVars = opts.playerVars || {};
        if (!window.YT) {
            load.js("https://www.youtube.com/player_api").then(function() {
                YT.ready(function() {
                    addVideo(opts.video, playerVars);
                });
            });
        } else {
            addVideo(opts.video, playerVars);
        }
    }
    return {
        init
    };
}());

function loadPlayer(containerSelector, playerVars) {
    "use strict";
    const show = (el) => el.classList.remove("hide");

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

    function coverClickHandler(evt) {
        const wrapper = evt.currentTarget.nextElementSibling;
        show(wrapper);
        initPlayer(wrapper);
    }
          
    const cover = document.querySelector(containerSelector);
    cover.addEventListener("click", coverClickHandler);
}
loadPlayer(".playa", {
    start: 900,
    end: 1200
});
loadPlayer(".playb", {
    start: 30,
    end: 50
});
loadPlayer(".playc", {
    start: 30,
    end: 50
});
loadPlayer(".playd", {
    start: 30,
    end: 50
});
loadPlayer(".playe", {
    start: 30,
    end: 50
});
loadPlayer(".playf", {
    start: 30,
    end: 50
});
loadPlayer(".playg", {
    start: 30,
    end: 50
});
loadPlayer(".playh", {
    start: 30,
    end: 50
});
loadPlayer(".playi", {
    start: 30,
    end: 50
});

#67

I just updated the single grid player to this:
https://jsfiddle.net/g6oaht8f/4/

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

function loadPlayer(containerSelector, playerVars) {
    "use strict";
    const show = (el) => el.classList.remove("hide");
    function initPlayer(wrapper) {
        videoPlayer.init({
            video: wrapper.querySelector(".video"),
            playerVars
        });
    }

    function coverClickHandler(evt) {
        const wrapper = evt.currentTarget.nextElementSibling;
        show(wrapper);
        initPlayer(wrapper);
    }
          
    const cover = document.querySelector(containerSelector);
    cover.addEventListener("click", coverClickHandler);
}

#68

As you’re wanting to keep them separate, don’t forget to change videoPlayer in the single code to videoPlayera


#69

I updated the single video player code to this:
https://jsfiddle.net/hzyrfkwb/372/

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

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

(function iife() {
  "use strict";
  const show = (el) => el.classList.remove("hide");

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

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

  const cover = document.querySelector(".jacketc");
  cover.addEventListener("click", coverClickHandler);
}());

#70

In the init function, that second addVideo line should be deleted.


#71

In improving them, it’s best to do them separately.


#72

Why is it best to do them separately, when one of them can instead completely replace the other?


#73

I removed too much.


#74

Fixed:
https://jsfiddle.net/hzyrfkwb/375/


#75

I would delete this second one too
addVideo(opts.video, playerVars);

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

#76

Leaving it there would certainly help when you later on want to adjust the playerVars.

Making such adjustments should always be done from the outside as configuration changes, instead of digging into the guts of an inner function itself.


#77

https://jsfiddle.net/g6oaht8f/5/

And this would become const:
var playerVars = opts.playerVars || {};

This:
const playerVars = opts.playerVars || {};
https://jsfiddle.net/g6oaht8f/8/


#78

Now I know why there were two of them:
That’s how it works with 2 players.

With the single player the if and else get removed.

        if (!window.YT) {
            load.js("https://www.youtube.com/player_api").then(function() {
                YT.ready(function() {
                    addVideo(opts.video);
                });
            });
        } else {
            addVideo(opts.video);
        }
    }

#79

They don’t have to be worked on separately. They just need to be controlled separately.

Last Updated:

Two players together:
https://jsfiddle.net/hzyrfkwb/385/

Single grid player:
https://jsfiddle.net/g6oaht8f/11/

Single player:
https://jsfiddle.net/hzyrfkwb/378/


#81

What else was I supposed to do, or not supposed to do?
https://jsfiddle.net/hzyrfkwb/393/

I deleted
Which is not needed anymore after everything is combined.

if (!window.YT) {

   } else {
        
    }

The function now looks like this:

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

I’m starting to like this one now.


Full Code:

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";
    const hide = (el) => el.classList.add("hide");

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

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

    function onPlayerStateChange(event) {
        const player = event.target;
        if (event.data === YT.PlayerState.PLAYING) {
            const otherVideos = (video) => video !== player;
            const pauseVideo = (video) => video.pauseVideo();
            players.filter(otherVideos).forEach(pauseVideo);
        }
        const playerVars = player.b.b.playerVars;
        if (playerVars.loop && event.data === YT.PlayerState.ENDED) {
            player.seekTo(playerVars.start);
        }
    }

    function addVideo(video, desiredPlayerVars) {
        const videoId = video.getAttribute("data-id");
        const defaultPlayerVars = {
            autoplay: 1,
            controls: 1,
            showinfo: 1,
            rel: 0,
            iv_load_policy: 3,
            cc_load_policy: 0,
            fs: 0,
            disablekb: 1
        };
        const playerVars = Object.assign(defaultPlayerVars, desiredPlayerVars);
        players.push(new YT.Player(video, {
            width: 198,
            height: 198,
            videoId: videoId,
            playerVars,
            events: {
                "onReady": onPlayerReady,
                "onStateChange": onPlayerStateChange
            }
        }));
    }

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

function loadPlayer(containerSelector, playerVars) {
    "use strict";
    const show = (el) => el.classList.remove("hide");

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

    function coverClickHandler(evt) {
        const wrapper = evt.currentTarget.nextElementSibling;
        show(wrapper);
        initPlayer(wrapper);
    }
    const cover = document.querySelector(containerSelector);
    cover.addEventListener("click", coverClickHandler);
}
loadPlayer(".jacketc", {
    start: 900,
    end: 1200
});
loadPlayer(".playa", {
    start: 900,
    end: 1200
});
loadPlayer(".playb", {
    start: 30,
    end: 50
});
loadPlayer(".playc", {
    start: 30,
    end: 50
});
loadPlayer(".playd", {
    start: 30,
    end: 50
});
loadPlayer(".playe", {
    start: 30,
    end: 50
});
loadPlayer(".playf", {
    start: 30,
    end: 50
});
loadPlayer(".playg", {
    start: 30,
    end: 50
});
loadPlayer(".playh", {
    start: 30,
    end: 50
});
loadPlayer(".playi", {
    start: 30,
    end: 50
});