Trying to get Shuffle Playlist to work

Not working here
How would I get it to work?
It should play in a random order every time it starts.

  function onPlayerReady(event) {
    const youtubePlayer = event.target;
    youtubePlayer.setVolume(50); // percent
    num = _.random(0, 5);
    setTimeout(() => {
      youtubePlayer.playVideoAt(num);
    }, 1000);

  }

Working version:

Fixed I think:

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

      events: {
        "onReady": onPlayerReady,
        "onStateChange": onPlayerReady
      }
    });
  };

@Paul_Wilkins

Something isn’t right here:

Does this make any sense at all?

Auto shuffle “is working” when it is set like this:

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

      events: {
        "onStateChange": onPlayerReady
      }
    });
  };

But auto shuffle “stops working” when it’s set like this:

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

      events: {
        "onReady": onPlayerReady
      }
    });
  };

No of course it won’t. The player is loaded but event.data is undefined, indicating that the playlist hasn’t yet become available. You cannot shuffle something that doesn’t yet exist.

I have this written wrong though, right?

Even though it works.

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

      events: {
        "onStateChange": onPlayerReady
      }
    });
  };

I’d move the setShuffle statement to a separate function called onStateChange instead.

1 Like

I think I got it.
And it’s working now.

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

events: {
        "onReady": onPlayerReady,
        "onStateChange": onPlayerStateChange 
      }
    });
  };

Since this is no-longer working:

It’s not working because it’s playing the same song over and over again after it is refreshed.

Would it be possible to set it up like this?
And have it either play in a random order, or no random order?

   const videoPlaylist = ['wyejXA9sZtE, 'mnfmQe8Mv1g', 'ZPz3wzPlruA', '-Xgi_way56U', 'CHahce95B1g', 
        'JFBUJ6kNl28', 'PEJpJ1UKQpg', 'pIuWymsUuk0', 'Nbp8XZnzfT8', 'pIuWymsUuk0',];

If this would be possible to do, I would like to see if this would be possible to do also.

Adding start, and end times to each video, this might be more complicated to figure out though.

loadPlayer({
    target: "wyejXA9sZtE",
    start: 0,
    end: 205,
});
loadPlayer({
    target: "mnfmQe8Mv1g",
    start: 0,
    end: 205,
});
loadPlayer({
    target: "Nbp8XZnzfT8",
    start: 0,
    end: 205,
});

Similar to how this was done:

        const settingsParams = ["width", "height", "host", "videoid"];
        const settings = settingsParams.reduce(paramInOpts, {});
        const playerVarsParams = ["autoplay", "cc_lang_pref", "cc_load_policy",
            "controls", "disablekb", "end", "fs", "hl", "iv_load_policy",
            "list", "listType", "loop", "playlist", "rel", "start"
        ];

Yes, that is how a playlist is designed to operate.

This is broken and doesn’t work:
player.setShuffle(true);

Is there a workaround to get it working?

https://stackoverflow.com/questions/12916017/youtube-api-setshuffle-dont-work

I read this suggestion:

The problem is that if you’ve loaded a playlist queue in the Youtube player, the next track will automatically start at the end of the current playing one.

So you should bind track ended event (which is event.data = 0 ) and then make the youtube player make two things:

  1. stop playing
  2. play a new track with a random index by calling playVideoAt method.

A simple solution to avoid repeating the same track more times is to store the played idx in a list. Then, you should have a function, like shuffle that generates a random integer between 0 and the queue length:

function getRandomId() {
    var random_id = 0
    while(played_idx.indexOf(random_id) != -1) {
      random_id = Math.floor(Math.random * playlist.length)
    }
    return random_id
}

Then, simply call playVideoAt(random_id) .

https://developers.google.com/youtube/iframe_api_reference#setShuffle

Setting playback behavior for playlists

player.setLoop(loopPlaylists:Boolean):Void

This function indicates whether the video player should continuously play a playlist or if it should stop playing after the last video in the playlist ends. The default behavior is that playlists do not loop.

This setting will persist even if you load or cue a different playlist, which means that if you load a playlist, call the setLoop function with a value of true, and then load a second playlist, the second playlist will also loop.

The required loopPlaylists parameter identifies the looping behavior.

If the parameter value is true, then the video player will continuously play playlists. After playing the last video in a playlist, the video player will go back to the beginning of the playlist and play it again.

If the parameter value is false, then playbacks will end after the video player plays the last video in a playlist.

player.setShuffle(shufflePlaylist:Boolean):Void

This function indicates whether a playlist’s videos should be shuffled so that they play back in an order different from the one that the playlist creator designated. If you shuffle a playlist after it has already started playing, the list will be reordered while the video that is playing continues to play. The next video that plays will then be selected based on the reordered list.

This setting will not persist if you load or cue a different playlist, which means that if you load a playlist, call the setShuffle function, and then load a second playlist, the second playlist will not be shuffled.

The required shufflePlaylist parameter indicates whether YouTube should shuffle the playlist.

If the parameter value is true, then YouTube will shuffle the playlist order. If you instruct the function to shuffle a playlist that has already been shuffled, YouTube will shuffle the order again.

If the parameter value is false, then YouTube will change the playlist order back to its original order.

The required shufflePlaylist parameter indicates whether YouTube should shuffle the playlist.

  • If the parameter value is true , then YouTube will shuffle the playlist order. If you instruct the function to shuffle a playlist that has already been shuffled, YouTube will shuffle the order again.
  • If the parameter value is false , then YouTube will change the playlist order back to its original order.

Is that different from this?
setShuffle function
player.setShuffle(true);

shufflePlaylist is nowhere specified in here:

To expect that to work before the playlist has loaded, is foolish in the extreme.

In this example I’ve checked if the playlist has already been shuffled, which seems to work well.

let hasShuffled = false;
  function onPlayerStateChange(event) {
    ...
    if (!hasShuffled) {
      player.setShuffle(true);
      player.playVideoAt(0);
      hasShuffled = true;
    }
    ...
  }
2 Likes

Like this then: ?

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

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

  let hasShuffled = false;
  
  function onPlayerStateChange(event) {
    const player = event.target;

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

And then these would be removed as I understand it.

videoId: video.dataset.id,
data-id="TLGGCePU6hOj6WQyMjEyMjAxOA"

Removed:

Would I be able to get it to work using indevidual id’s like how it is done here?

var player;
var playlist = ['wyejXA9sZtE', 'mnfmQe8Mv1g', 'ZPz3wzPlruA', '-Xgi_way56U', 'CHahce95B1g', 
        'JFBUJ6kNl28', 'PEJpJ1UKQpg', 'pIuWymsUuk0', 'Nbp8XZnzfT8', 'pIuWymsUuk0'];
var previousIndex = 0;

Here’s the player without a cover on it so it be tested on it:

If I wanted to use individual id’s instead, how would that be set up?

The Youtube API doesn’t provide any way to achieve that.

I recommend that you create your own playlist on your youtube account, and use that instead.

1 Like

Can we work on improving this code.


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

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

    function onPlayerStateChange(event) {
        const player = event.target;
        player.setShuffle(true);
    }
    let oldNumber = 0;
    let NewNumber = 10;

    function newRandomNumber(min, max) {
        oldNumber = NewNumber;
        NewNumber = Math.floor(Math.random() * max) + min;
        if (NewNumber == oldNumber) {
            newRandomNumber(min, max);
        } else {
            return NewNumber;
        }
    }

    function addVideo(video) {
        player = new YT.Player(video, {
            width: 606,
            height: 344,
            playerVars: {
                autoplay: 0,
                controls: 1,
                index: newRandomNumber(0, 10),
                loop: true,
                listType: 'playlist',
                list: 'TLGGCePU6hOj6WQyMjEyMjAxOA'
            },
            events: {
                "onReady": onPlayerReady,
                "onStateChange": onPlayerStateChange
            }
        });
    }

Improving This
Single Player

    let oldNumber = 0;
    let NewNumber = 10;

    function newRandomNumber(min, max) {
        oldNumber = NewNumber;
        NewNumber = Math.floor(Math.random() * max) + min;
        if (NewNumber == oldNumber) {
            newRandomNumber(min, max);
        } else {
            return NewNumber;
        }
    }

To This:
Single Player

    let newNumber;

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

Improved Further Here:
Single Player
https://jsfiddle.net/qnbyg5x9/142/

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

Improved Even Further:
I think this may be as far as it can be improved.

Single Player
https://jsfiddle.net/qnbyg5x9/143/

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

I’m having issues here:

Single + Grid Player
Not Working:
https://jsfiddle.net/cgrw42zy/12/

This is how it works in the single player, no grid.
https://jsfiddle.net/qnbyg5x9/143/

Also, the top player works if you remove this piece from the code:
The only reason why it disappears is because it’s not working.
index: newRandomNumber(0, 10),

Undeclared ‘newRandomNumber’.
index: newRandomNumber(0, 10),

I don’t know how that will be resolved.

newRandomNumber is in 2 different functions where they are not able to connect to each other.

They would need to be inside the same function I think.

newRandomNumber is here:

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

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

newRandomNumber is here:

function loadPlayer(opts) {
    "use strict";

loadPlayer({
    target: ".jacketc",
    width: 600,
    height: 338,
    index: newRandomNumber(0, 10),
    loop: true,
    listType: "playlist",
    list: "TLGGCePU6hOj6WQyMjEyMjAxOA"
});

Full Code:

    function onPlayerStateChange(event) {
        const player = event.target;
        player.setShuffle(true);
        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 newRandomNumber(min, max) {
        return Math.floor(Math.random() * max) + min;
    }

    function addVideo(video, settings) {
        players.push(new YT.Player(video, Object.assign({
            videoId: video.dataset.id,
            host: "https://www.youtube-nocookie.com",
            events: {
                "onReady": onPlayerReady,
                "onStateChange": onPlayerStateChange
            }
        }, settings)));
        console.log(settings);
    }

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

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

    function initPlayer(wrapper) {
        const video = wrapper.querySelector(".video");
        opts.width = opts.width || 198;
        opts.height = opts.height || 198;
        opts.autoplay = 1;
        opts.controls = 1;
        opts.rel = 0;
        opts.iv_load_policy = 3;
        opts.fs = 0;
        opts.disablekb = 1;

        function paramInOpts(settings, param) {
            if (opts[param] !== undefined) {
                settings[param] = opts[param];
            }
            return settings;
        }
        const settingsParams = ["width", "height", "host", "videoid"];
        const settings = settingsParams.reduce(paramInOpts, {});
        const playerVarsParams = ["autoplay", "index", "cc_load_policy",
        "controls", "disablekb", "end", "fs", "iv_load_policy", "list",
        "listType", "loop", "playlist", "rel", "start"];
        settings.playerVars = playerVarsParams.reduce(paramInOpts, {});
        videoPlayer.init(video, settings);
    }

    function coverClickHandler(evt) {
        const wrapper = evt.currentTarget.nextElementSibling;
        show(wrapper);
        initPlayer(wrapper);
    }
    const cover = document.querySelector(opts.target);
    cover.addEventListener("click", coverClickHandler);
}
loadPlayer({
    target: ".jacketc",
    width: 600,
    height: 338,
    index: newRandomNumber(0, 10),
    loop: true,
    listType: "playlist",
    list: "TLGGCePU6hOj6WQyMjEyMjAxOA"
});

Not today, as it’s Christmas Eve.

2 Likes

oh, ok. another time when you are able to.

The last one on here is where I’m having issues:

#18

Undeclared ‘newRandomNumber’.
index: newRandomNumber(0, 10),

Single + Grid Player