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.