Zhenyi Tan And a Dinosaur

How Does YouTube Autoplay Its Videos on iOS?

I wonder if the WebKit team will patch this.

By far the most requested feature for Vinegar is to autoplay the next related video or the next video in the playlist. But Safari on iOS requires a user gesture to play video in a <video> element. More specifically:

The call to video.play() must have directly resulted from a handler for a touchend, click, doubleclick, or keydown event. So, button.addEventListener('click', () => { video.play(); }) would satisfy the user gesture requirement. video.addEventListener('canplaythrough', () => { video.play(); }) would not.

So how come YouTube can seemingly bypass this requirement and autoplay one video after another? I don’t actually know, but I think this is how:

  1. On page load, mute the video and start playing (Safari allows muted autoplay).
  2. When the user unmutes the video, capture the click event.
  3. In the event handler, do this:
    1. When the video ends, load another one and play it.
    2. Update the rest of the web page and the URL dynamically.
  4. When the user clicks on another video, do 3i and 3ii.

It doesn’t matter if your code is in a callback of a callback of a callback. As long as you can trace it back to a click event handler, you’re good. Here’s a proof of concept to show that it even works if you create <video> elements on the fly:

var index = 0;

function nextVideo(oldVideo) {
  let video = document.createElement('video');
  video.playsinline = true;
  video.controls = true;

  if (oldVideo) {
    oldVideo.replaceWith(video);
  } else {
    document.body.appendChild(video);
  }

  video.src = `${++index}.mp4`;
  video.play(); // It works!

  video.addEventListener('ended', (e) => {
    nextVideo(video);
  });
}

// The only user gesture you need
document.body.addEventListener('click', (e) => {
  if (index === 0) nextVideo();
});