Playing YouTube videos from an array

How might the random video code have been written to work in here?
https://jsfiddle.net/xwd6n4f0/

This is the one with init at the bottom.

videoPlayer.init([
    "0dgNc5S8cLI",
    "mnfmQe8Mv1g",
    "CHahce95B1g",
    "2VwsvrPFr9w"
]);

That would be done in the usual way, by making addPlayer capable of handling one or an array of videoIds.

    function addPlayer(video, videoIds) {
        const videoId = !Array.isArray(videoIds) && videoIds;
        const playlist = Array.isArray(videoIds) && videoIds.join();

We add both videoId and playlist to the playerOptions. The playlist can’t just be false when there’s no playlist, so we properly make that undefined instead.

        const playerOptions = {
            ...
            videoId,
            ...
        };
        playerOptions.playerVars = {
            ...
            playlist: playlist || undefined,
            ...
        };

addPlayer is run from onYouTubeIframeAPIReady, so we pass the videos to that:

    function onYouTubeIframeAPIReady() {
        ...
        videoPlayer.addPlayer(frameContainer, config.videoIds);
    }

And that config is updated from the init function.

    function init(videoIds) {
        config.videoIds = videoIds;
    	loadIframeScript();
        window.onYouTubeIframeAPIReady = onYouTubeIframeAPIReady;
    }

When it comes to initing with a random video, there are several different ways to deal that that. One that I prefer is to use a settings object to give different settings, such as to randomize the list.

videoPlayer.init([
    "0dgNc5S8cLI",
    "mnfmQe8Mv1g",
    "CHahce95B1g",
    "2VwsvrPFr9w"
], {
  randomVideo: true
});

That way from the init function, we can check for that randomVideo setting and do something different there.

    function init(videoIds, settings = {}) {
        if (settings.randomVideo) {
            const index = Math.floor(Math.random() * videoIds.length);
            config.videoIds = videoIds[index];
        } else {
            config.videoIds = videoIds;
        }
    	loadIframeScript();
        window.onYouTubeIframeAPIReady = onYouTubeIframeAPIReady;
    }
1 Like

The code isn’t working here: https://jsitor.com/SEWXsfQOf7

When you use jsitor, I am not able to see the changes you make to each code.

jsfiddle is better because the link is not the same.

Post #182 code
https://jsitor.com/SEWXsfQOf7

should be different from

post #194 code.
https://jsitor.com/SEWXsfQOf7

I am not able to see the code you did in post #182

The code you worked on here is not in the jsitor link you provided.

https://jsitor.com/SEWXsfQOf7

Everything you worked on in that post is not in the code link you provided.

Yep, that’s one of the dangers of having no tests. It’s all working now.

I’ve updated the manageCover code on the jsitor.com sites to all use exactly the same manageCover code. The next step from there is to move the manageCover code off of the page entirely, so that the same set of manageCover code can be included as a library. That results in there being only one set of code to manage instead of hundreds of different variations.

I can’t use jsitor.

I can’t see the jsitor codes you do.

jsfiddle I am able to see the codes individually, which is better for understanding the code that is being worked on.

When I work on code I use jsfiddle.

I got up this far: https://jsfiddle.net/rg8qnf0d/

The code link you provided does not represent the code in your post.

No that’s right, the manageCover code has all been improved now.

It should be, I am not able to ask you questions if it is not in the link.

With jsfiddle I can ask you questions, now I can’t.

If I am reading your post, and then I click on the link, and that’s not the code that you were talking about in your post, how am I able to learn from that?

How am I supposed to reference things from a post, if the code doesn’t match what is in your post?

I’m having a very difficult and hard time following the code that is being worked on because I am not able to see the code being changed from one and then updated to another.

I can see via jsfiddle the code being changed from one to the new one.

Old code
https://jsfiddle.net/r87wz9ps/

New code
https://jsfiddle.net/r87wz9ps/1/

via jsitor, I can’t see the code being changed from one to the new one.

I can only see the updated, I can’t see what it was changed from.

Old code
https://jsitor.com/SEWXsfQOf7

New code
https://jsitor.com/SEWXsfQOf7

On your next update can you use jsfiddle please?

So I am able to follow the work being made to the code.

Here is my last jsfiddle code:

Can progress be made from here?
https://jsfiddle.net/or5uqk1a/

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

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

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

    function hideAll(elements) {
        elements.forEach(hide);
    }

    function showCovers(playButton) {
        const cover = playButton.parentElement;
        cover.classList.add("active");
        show(cover);
    }

    function coverClickHandler(evt) {
        hideAll(config.containers);
        const cover = evt.currentTarget;
        showCovers(cover);
    }

    function addClickToButtons(playButtons) {
        playButtons.forEach(function addEventHandler(playButton) {
            playButton.addEventListener("click", coverClickHandler);
        });
    }

    function addCoverHandler(coverSelector, handler) {
        const cover = document.querySelector(coverSelector);
        cover.addEventListener("click", handler);
    }

    function init(selectors) {
        config.containers = document.querySelectorAll(selectors.container);
        const playButtons = document.querySelectorAll(selectors.playButton);
        addClickToButtons(playButtons);
    }

    return {
        addCoverHandler,
        init,
        show
    };
}());

const videoPlayer = (function makeVideoPlayer() {
    const players = [];

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


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

    function addPlayer(video, settings, videoIds) {
        const videoId = !Array.isArray(videoIds) && videoIds;
        const playlist = Array.isArray(videoIds) && videoIds;
        const defaults = {
            playerOptions: {
                events: {
                    "onReady": onPlayerReady
                },
                host: "https://www.youtube-nocookie.com",
                videoId: video.dataset.id
            }
        };
        const playerOptions = Object.assign({}, defaults.playerOptions, settings);
        players.push(new YT.Player(video, playerOptions));
    }

    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 defaultVars = defaultOptions.playerVars;
        const playerVars = settings.playerVars;
        const playerOptions = Object.assign({}, defaultOptions, settings);
        playerOptions.playerVars = Object.assign({}, defaultVars, 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
    };
}());


function onYouTubeIframeAPIReady() {
    managePlayer.init({
        playerVars: {
            autoplay: 0
        }
    });
    managePlayer.addRandom(".playa", {
        height: 207,
        start: 4,
        width: 277
    }, [
        "0dgNc5S8cLI",
        "mnfmQe8Mv1g",
        "-Xgi_way56U",
        "CHahce95B1g"
    ]);
    managePlayer.add(".playb", {
        height: 207,
        width: 277
    });
    manageCover.init({
        container: ".container",
        playButton: ".thePlay"
    });
}

The code that you quoted already has a good solution for that, and that is to extract out the defaultVars variable…

        const defaultVars = defaultOptions.playerVars;
        playerOptions.playerVars = Object.assign({}, defaultVars, playerVars);

In your case it is only the defaultOptions that needs to be extracted.

1 Like

I put that in here and it doesn’t work in the code:
https://jsfiddle.net/c4ofm19g/

The videos don’t show then.

You were not supposed to put the code in. That was instead an example of the type of thing to do.

What you are supposed to do was spelled out below it.

1 Like

In your case, defaults.playerOptions is a long piece that can be easily shortened. How that is shortened is to assign it to a variable called defaultOptions, and to use that shorter variable in the problem line instead.

That way, legibility of what it is and what it does is fully maintained, while also keeping to the 80 chars limit.

This:

        const playerOptions = Object.assign({}, defaultOptions, settings);
        players.push(new YT.Player(video, playerOptions));

defaultOptions is not highlighted.

Yes, and you need a separate assignment before that playerOptions line to assign the defaultOptions variable.

Where does the defaultOptions var go?