videojs player.textTracks() returns wrong type of object on safari, cannot capture TextTrack cuechange event

Viewed 355

I am trying to work with some TextTrack information connected to a video. I've got a video embedded from Mux.com, which has metadata containing Program Data Time (PDT). Most browsers behave, but videojs appears to return a different type of object in safari so I am unable to attach an event listener to capture the cuechange event and extract its PDT date string.

On most browsers I test (Firefox, Chrome, Edge, etc.), this code will properly show the latest PDT in DIV#sneakyimp_pdt, but in Safari, the object returned by the videojs player.textTracks() function is a different type. Rather than being some class e, as it is in most browsers, Safari yields a metadataTrack object that is a TextTrack object. Even so, I cannot seem to attach any event listeners to the TextTrack cuechange event.

Can someone tell me what I'm doing wrong here? I've added quite a bit of special case code to try and attach a listener to these text tracks and it still doesn't work.

<div id="sneakyimp">
  <figure>
    <video class='mux-player video-js' width=1920 height=1080 poster='https://example.com/foo.thumb.jpg' controls preload='metadata'>
      <source src='https://stream.mux.com/VIDEO-ID-HERE.m3u8' type='application/x-mpegURL' />
    </video>
  </figure>
</div>
<div id="sneakyimp_pdt">PDT WILL LOAD HERE</div>
<div id="sneakyimp_ct">currentTime WILL LOAD HERE</div>
<script>
// the videojs player object
let player = null;
function myPlayerInit() {
    const metadataTrack = Array.prototype.find.call(player.textTracks(), track => track.label === 'segment-metadata');
    if (!metadataTrack) {
      console.log('metadataTrack NOT FOUND');
    } else {
      // in Safari, construct.name is TextTrack, on other browsers, it's just e
      console.log('metadataTrack located, constructor name is ' + (metadataTrack.constructor.name));
      console.log(metadataTrack);
    }
    if (!metadataTrack.on) {
      // THIS RUNS ON SAFARI
      console.log('metadataTrack has no on method, will try addEventListener');
      // THIS NEVER FIRES
      metadataTrack.addEventListener('cuechange', function () {
        console.log('event listener cuechange firing');
        let cues = metadataTrack.activeCues;
        console.log("cues found, type=" + (typeof cues)); 
        let pdt = metadataTrack.activeCues[0].value.dateTimeString;
        if (!pdt) {
          console.log('no pdt womp womp. pdt type=' + (typeof pdt));
        }
        console.log('pdt: ' + pdt);
        document.getElementById('sneakyimp_pdt').innerHTML = pdt;
      });
      console.log('metadataTrack.addEventListener added');
      console.log('also trying oncuechange');
      // THIS NEVER FIRES
      metadataTrack.oncuechange = function() {
        console.log('oncuechange running');
      }
    } else {
      // THIS RUNS ON FIREFOX, CHROME, EDGE, ETC
      console.log('adding metadataTrack.on listener');
      metadataTrack.on('cuechange', () => {
        let pdt = metadataTrack.activeCues[0].value.dateTimeString;
        document.getElementById('sneakyimp_pdt').innerHTML = pdt;
      });
    }
    // THIS WORKS ON ALL BROWSERS I'VE TESTED
    player.on('timeupdate', (evt) => {
      document.getElementById('sneakyimp_ct').innerHTML = player.currentTime();
    });
}
// sometimes loadedmetadata seems to fire loadeddata before
// DOMready so we have this
let loadedmetadata = false;
let myVideo = document.querySelector("#sneakyimp video");
if (myVideo) {
  window.addEventListener('loadedmetadata', function(ev) {
      console.log('directly added, pre-dom loadedmetadata fired');
      loadedmetadata = true;
  }, true);
}
// we wait for DOM to do most of this stuff
window.addEventListener('DOMContentLoaded', (event) => {
    let video = document.querySelector("#sneakyimp video");
    if (!video) {
        throw "no video found";
    }
    player = videojs(video.id, {
      html5: {
        nativeTextTracks: false,
        vhs: {
          overrideNative: true
        }
      }
    });

    window.player = player;
    if (loadedmetadata) {
      console.log('loadedmetadata fired before domready, firing myPlayerInit');
      myPlayerInit();
    } else {
      console.log('attaching loadeddata event to player');
      player.on('loadeddata', () => {
        console.log("== player loadeddata, firing myPlayerInit ==");
        myPlayerInit();
      });
    }
});
</script>

As I mentioned above, this code works on most browsers. In Safari, it reports a few things:

  • metadataTrack located, constructor name is TextTrack
  • metadataTrack has no on method, will try addEventListener
  • metadataTrack.addEventListener added
  • also trying oncuechange

However, the event listeners I add never fire.

0 Answers
Related