JSFiddle - React, Tailwind, and code Playground

by shamaleyte

HTML

<script src="https://static.bocoup.com/js/popcorn.min.js"></script>
<video height="180" width="300" id="a" src="https://mpowr.s3.amazonaws.com/data/b50798b5-5e13-49d4-8fb7-9c6b41adb89f/fee36b44-750e-402f-ba26-b58a410c009e.webm?AWSAccessKeyId=AKIAIFGTL4MKKNPGSZFQ&Expires=1500648371&Signature=Ys4VvWVvDqyQluDLTPEX9gh44HY%3D" controls> 
<source src="https://videos.mozilla.org/serv/webmademovies/popcorntest.mp4"></source>
<source src="https://videos.mozilla.org/serv/webmademovies/popcorntest.ogv"></source>
<source src="https://videos.mozilla.org/serv/webmademovies/popcorntest.webm"></source>
</video>
<video height="180" width="300" id="b" src="https://mpowr.s3.amazonaws.com/data/b50798b5-5e13-49d4-8fb7-9c6b41adb89f/e4ecc548-2e35-4dff-834f-7d8beacf9123.webm?AWSAccessKeyId=AKIAIFGTL4MKKNPGSZFQ&Expires=1500648371&Signature=T5UG9nqCKHutnjBlZBZolnmVlCM%3D"> 
</video>

<input type="range" value="0" id="scrub" />

CSS

html{font-family:arial;}

JavaScript

var videos = {
    a: Popcorn("#a"),
    b: Popcorn("#b"),
  },
  scrub = $("#scrub"),
  loadCount = 0,
  events = "play pause timeupdate seeking".split(/\s+/g);

// iterate both media sources
Popcorn.forEach(videos, function(media, type) {

  // when each is ready... 
  media.on("canplayall", function() {

    // trigger a custom "sync" event
    this.emit("sync");

    // set the max value of the "scrubber"
    scrub.attr("max", this.duration());

    // Listen for the custom sync event...    
  }).on("sync", function() {

    // Once both items are loaded, sync events
    if (++loadCount == 2) {

      // Iterate all events and trigger them on the video B
      // whenever they occur on the video A
      events.forEach(function(event) {

        videos.a.on(event, function() {

          // Avoid overkill events, trigger timeupdate manually
          if (event === "timeupdate") {

            if (!this.media.paused) {
              return;
            }
            videos.b.emit("timeupdate");

            // update scrubber
            scrub.val(this.currentTime());

            return;
          }

          if (event === "seeking") {
            videos.b.currentTime(this.currentTime());
          }

          if (event === "play" || event === "pause") {
            videos.b[event]();
          }
        });
      });
    }
  });
});

scrub.bind("change", function() {
  var val = this.value;
  videos.a.currentTime(val);
  videos.b.currentTime(val);
});

// With requestAnimationFrame, we can ensure that as 
// frequently as the browser would allow, 
// the video is resync'ed.
function sync() {
  if (videos.b.media.readyState === 4) {
    videos.b.currentTime(
      videos.a.currentTime()
    );
  }
  requestAnimationFrame(sync);
}

sync();